diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-30 09:22:00 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-30 09:22:00 -0700 |
| commit | 034dd340b08be1f2f0477ad16131d609f9dbd53c (patch) | |
| tree | 2536f4b2d7893ccd916b5abdf3c454ad6edc03c2 /drivers/video/fbdev/i810 | |
| download | linux-stable-034dd340b08be1f2f0477ad16131d609f9dbd53c.tar.gz linux-stable-034dd340b08be1f2f0477ad16131d609f9dbd53c.zip | |
Merge tag 'trace-v7.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-tracegrafted
Pull tracing fixes from Steven Rostedt:
- Fix error output of boot instance creation failure
Currently if a boot instance creation fails, instead of printing out
the name of the instance that failed, it prints "(null)". That is
because it prints "cur_str" that had already been processed by
strsep(). Print the saved name instead.
While at it, print the error code of the failure.
- Fix use-after-free for same named historgrams
Histograms can be named so that they can be used in multiple events.
But if the named histogram has a variable attached, the second event
that uses the named histogram which duplicates it and needs to free
the original after duplication leaves the old variable in place and
still visible. If another histogram uses than variable, it will use
the stale one which will try to reference the freed duplicate
histogram and crash the kernel.
Free the duplicate variables along with the duplicated histogram
data.
- Check return value of kthread_run() in event self test
The events self tests uses a kthread for testing but does not check
if it succeeded in creating a kthread. If the kthread creation were
to fail, the code will still try to call kthread_stop() on the error
returned.
- Fix race between reading trace_pipe and updating subbuffer size
If a user is reading the trace_pipe file at the same time they update
the ring buffer sub-buffer size, can cause the trace_pipe read to
read stale data. Add trace_access_lock() around updating the ring
buffer sub-buffer size.
- Fix eventfs_inode on failure path in creation of the events directory
In the creation of the "events" directory, if after allocating the
eventfs_inode a failure is detected, it calls cleanup_ei() which
calls free_ei(). The free_ei() will test if eventfs_inode being freed
has no children. It is a bug if it does. But on the failure case of
the creation of the "events" directory, the children lists have not
yet been initialized and the free will trigger a warning because
list_empty() on an uninitialized list returns false.
Move the initialization into init_ei() where it makes more sense and
makes sure that a created eventfs_inode has its lists initialized
upon creation.
- Check return value of kthread_run() in ftrace direct sample code
The sample code that shows how to use the ftrace direct calls does
not test the return of kthread_run() to see if it succeeds. Return a
failure if the kthread_run() doesn't succeed.
- Clear user events state on fork in case of alloc failure
On fork, the child gets a pointer to the parent's user events state.
It makes a copy of it then updates the child's pointer to it. But if
the allocation fails, the duplication function leaves the child with
a pointer to its parent's descriptor. When the child cleans up its
data, it will free the parent's descriptor while the parent is still
using it.
In the duplication function, set the child's user_event_mm to NULL
before testing if the allocation succeeded, and when it exits it will
not free the parent's descriptor.
- Fix retry exhaustion in simple ring buffer reader swap
simple_ring_buffer_swap_reader_page() starts with retry set to 8 and
post-decrements it only after a failed link replacement. On the final
attempt, a successful replacement leaves retry at zero, while a
failed replacement leaves it at -1.
But the check for success expects the retry value to be non-zero and
exits with an error on zero. This is the opposite result. Fix it.
- Fail nicely when the remote swap_reader_page() returns an error
Currently, if the swap_reader_page() of a remote buffer fails, it
triggers a WARN_ON_ONCE() and continues normally. Instead, have it
exit with an error and a pr_warn() print instead of a full WARNING.
* tag 'trace-v7.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
ring-buffer: Stop remote reader update when page swap fails
tracing: Fix retry exhaustion in simple ring buffer reader swap
tracing/user_events: Clear copied tracing state before fork duplication
samples/ftrace: Fix kthread_stop() on ERR_PTR in ftrace-direct-multi-modify
samples/ftrace: Fix kthread_stop() on ERR_PTR in ftrace-direct-modify
eventfs: Initialize ei->children and ei->list in init_ei()
tracing: Fix use-after-free in trace_pipe read on sub-buffer order change
tracing: Fix crash passing ERR_PTR to kthread_stop()
tracing: Fix use-after-free with same-name named triggers
tracing: Fix logged instance name on creation failure
Diffstat (limited to 'drivers/video/fbdev/i810')
| -rw-r--r-- | drivers/video/fbdev/i810/Makefile | 18 | ||||
| -rw-r--r-- | drivers/video/fbdev/i810/i810-i2c.c | 175 | ||||
| -rw-r--r-- | drivers/video/fbdev/i810/i810.h | 298 | ||||
| -rw-r--r-- | drivers/video/fbdev/i810/i810_accel.c | 456 | ||||
| -rw-r--r-- | drivers/video/fbdev/i810/i810_dvt.c | 313 | ||||
| -rw-r--r-- | drivers/video/fbdev/i810/i810_gtf.c | 276 | ||||
| -rw-r--r-- | drivers/video/fbdev/i810/i810_main.c | 2234 | ||||
| -rw-r--r-- | drivers/video/fbdev/i810/i810_main.h | 69 | ||||
| -rw-r--r-- | drivers/video/fbdev/i810/i810_regs.h | 275 |
9 files changed, 4114 insertions, 0 deletions
diff --git a/drivers/video/fbdev/i810/Makefile b/drivers/video/fbdev/i810/Makefile new file mode 100644 index 000000000..3e466510f --- /dev/null +++ b/drivers/video/fbdev/i810/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the Intel 810/815 framebuffer driver +# + +obj-$(CONFIG_FB_I810) += i810fb.o + +i810fb-objs := i810_main.o i810_accel.o + +ifdef CONFIG_FB_I810_GTF +i810fb-objs += i810_gtf.o +else +i810fb-objs += i810_dvt.o +endif + +ifdef CONFIG_FB_I810_I2C +i810fb-objs += i810-i2c.o +endif diff --git a/drivers/video/fbdev/i810/i810-i2c.c b/drivers/video/fbdev/i810/i810-i2c.c new file mode 100644 index 000000000..7db17d0d8 --- /dev/null +++ b/drivers/video/fbdev/i810/i810-i2c.c @@ -0,0 +1,175 @@ + /*-*- linux-c -*- + * linux/drivers/video/i810-i2c.c -- Intel 810/815 I2C support + * + * Copyright (C) 2004 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/gfp.h> +#include <linux/pci.h> +#include <linux/fb.h> +#include "i810.h" +#include "i810_regs.h" +#include "i810_main.h" +#include "../edid.h" + +/* bit locations in the registers */ +#define SCL_DIR_MASK 0x0001 +#define SCL_DIR 0x0002 +#define SCL_VAL_MASK 0x0004 +#define SCL_VAL_OUT 0x0008 +#define SCL_VAL_IN 0x0010 +#define SDA_DIR_MASK 0x0100 +#define SDA_DIR 0x0200 +#define SDA_VAL_MASK 0x0400 +#define SDA_VAL_OUT 0x0800 +#define SDA_VAL_IN 0x1000 + +#define DEBUG /* define this for verbose EDID parsing output */ + +#ifdef DEBUG +#define DPRINTK(fmt, args...) printk(fmt,## args) +#else +#define DPRINTK(fmt, args...) +#endif + +static void i810i2c_setscl(void *data, int state) +{ + struct i810fb_i2c_chan *chan = data; + struct i810fb_par *par = chan->par; + u8 __iomem *mmio = par->mmio_start_virtual; + + if (state) + i810_writel(mmio, chan->ddc_base, SCL_DIR_MASK | SCL_VAL_MASK); + else + i810_writel(mmio, chan->ddc_base, SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK); + i810_readl(mmio, chan->ddc_base); /* flush posted write */ +} + +static void i810i2c_setsda(void *data, int state) +{ + struct i810fb_i2c_chan *chan = data; + struct i810fb_par *par = chan->par; + u8 __iomem *mmio = par->mmio_start_virtual; + + if (state) + i810_writel(mmio, chan->ddc_base, SDA_DIR_MASK | SDA_VAL_MASK); + else + i810_writel(mmio, chan->ddc_base, SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK); + i810_readl(mmio, chan->ddc_base); /* flush posted write */ +} + +static int i810i2c_getscl(void *data) +{ + struct i810fb_i2c_chan *chan = data; + struct i810fb_par *par = chan->par; + u8 __iomem *mmio = par->mmio_start_virtual; + + i810_writel(mmio, chan->ddc_base, SCL_DIR_MASK); + i810_writel(mmio, chan->ddc_base, 0); + return ((i810_readl(mmio, chan->ddc_base) & SCL_VAL_IN) != 0); +} + +static int i810i2c_getsda(void *data) +{ + struct i810fb_i2c_chan *chan = data; + struct i810fb_par *par = chan->par; + u8 __iomem *mmio = par->mmio_start_virtual; + + i810_writel(mmio, chan->ddc_base, SDA_DIR_MASK); + i810_writel(mmio, chan->ddc_base, 0); + return ((i810_readl(mmio, chan->ddc_base) & SDA_VAL_IN) != 0); +} + +static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name) +{ + int rc; + + strcpy(chan->adapter.name, name); + chan->adapter.owner = THIS_MODULE; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->par->dev->dev; + chan->algo.setsda = i810i2c_setsda; + chan->algo.setscl = i810i2c_setscl; + chan->algo.getsda = i810i2c_getsda; + chan->algo.getscl = i810i2c_getscl; + chan->algo.udelay = 10; + chan->algo.timeout = (HZ/2); + chan->algo.data = chan; + + i2c_set_adapdata(&chan->adapter, chan); + + /* Raise SCL and SDA */ + chan->algo.setsda(chan, 1); + chan->algo.setscl(chan, 1); + udelay(20); + + rc = i2c_bit_add_bus(&chan->adapter); + + if (rc == 0) + dev_dbg(&chan->par->dev->dev, "I2C bus %s registered.\n",name); + else { + dev_warn(&chan->par->dev->dev, "Failed to register I2C bus " + "%s.\n", name); + chan->par = NULL; + } + + return rc; +} + +void i810_create_i2c_busses(struct i810fb_par *par) +{ + par->chan[0].par = par; + par->chan[1].par = par; + par->chan[2].par = par; + + par->chan[0].ddc_base = GPIOA; + i810_setup_i2c_bus(&par->chan[0], "I810-DDC"); + par->chan[1].ddc_base = GPIOB; + i810_setup_i2c_bus(&par->chan[1], "I810-I2C"); + par->chan[2].ddc_base = GPIOC; + i810_setup_i2c_bus(&par->chan[2], "I810-GPIOC"); +} + +void i810_delete_i2c_busses(struct i810fb_par *par) +{ + if (par->chan[0].par) + i2c_del_adapter(&par->chan[0].adapter); + par->chan[0].par = NULL; + + if (par->chan[1].par) + i2c_del_adapter(&par->chan[1].adapter); + par->chan[1].par = NULL; + + if (par->chan[2].par) + i2c_del_adapter(&par->chan[2].adapter); + par->chan[2].par = NULL; +} + +int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn) +{ + struct i810fb_par *par = info->par; + u8 *edid = NULL; + + DPRINTK("i810-i2c: Probe DDC%i Bus\n", conn+1); + if (conn < par->ddc_num) { + edid = fb_ddc_read(&par->chan[conn].adapter); + } else { + const u8 *e = fb_firmware_edid(info->device); + + if (e != NULL) { + DPRINTK("i810-i2c: Getting EDID from BIOS\n"); + edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL); + } + } + + *out_edid = edid; + + return (edid) ? 0 : 1; +} diff --git a/drivers/video/fbdev/i810/i810.h b/drivers/video/fbdev/i810/i810.h new file mode 100644 index 000000000..7b1c002bf --- /dev/null +++ b/drivers/video/fbdev/i810/i810.h @@ -0,0 +1,298 @@ +/*-*- linux-c -*- + * linux/drivers/video/i810.h -- Intel 810 General Definitions/Declarations + * + * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#ifndef __I810_H__ +#define __I810_H__ + +#include <linux/list.h> +#include <linux/agp_backend.h> +#include <linux/fb.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include <video/vga.h> + +/* Fence */ +#define TILEWALK_X (0 << 12) +#define TILEWALK_Y (1 << 12) + +/* Raster ops */ +#define COLOR_COPY_ROP 0xF0 +#define PAT_COPY_ROP 0xCC +#define CLEAR_ROP 0x00 +#define WHITE_ROP 0xFF +#define INVERT_ROP 0x55 +#define XOR_ROP 0x5A + +/* 2D Engine definitions */ +#define SOLIDPATTERN 0x80000000 +#define NONSOLID 0x00000000 +#define BPP8 (0 << 24) +#define BPP16 (1 << 24) +#define BPP24 (2 << 24) + +#define PIXCONF8 (2 << 16) +#define PIXCONF15 (4 << 16) +#define PIXCONF16 (5 << 16) +#define PIXCONF24 (6 << 16) +#define PIXCONF32 (7 << 16) + +#define DYN_COLOR_EN (1 << 26) +#define DYN_COLOR_DIS (0 << 26) +#define INCREMENT 0x00000000 +#define DECREMENT (0x01 << 30) +#define ARB_ON 0x00000001 +#define ARB_OFF 0x00000000 +#define SYNC_FLIP 0x00000000 +#define ASYNC_FLIP 0x00000040 +#define OPTYPE_MASK 0xE0000000 +#define PARSER_MASK 0x001F8000 +#define D2_MASK 0x001FC000 /* 2D mask */ + +/* Instruction type */ +/* There are more but pertains to 3D */ +#define PARSER 0x00000000 +#define BLIT (0x02 << 29) +#define RENDER (0x03 << 29) + +/* Parser */ +#define NOP 0x00 /* No operation, padding */ +#define BP_INT (0x01 << 23) /* Breakpoint interrupt */ +#define USR_INT (0x02 << 23) /* User interrupt */ +#define WAIT_FOR_EVNT (0x03 << 23) /* Wait for event */ +#define FLUSH (0x04 << 23) +#define CONTEXT_SEL (0x05 << 23) +#define REPORT_HEAD (0x07 << 23) +#define ARB_ON_OFF (0x08 << 23) +#define OVERLAY_FLIP (0x11 << 23) +#define LOAD_SCAN_INC (0x12 << 23) +#define LOAD_SCAN_EX (0x13 << 23) +#define FRONT_BUFFER (0x14 << 23) +#define DEST_BUFFER (0x15 << 23) +#define Z_BUFFER (0x16 << 23) + +#define STORE_DWORD_IMM (0x20 << 23) +#define STORE_DWORD_IDX (0x21 << 23) +#define BATCH_BUFFER (0x30 << 23) + +/* Blit */ +#define SETUP_BLIT 0x00 +#define SETUP_MONO_PATTERN_SL_BLT (0x10 << 22) +#define PIXEL_BLT (0x20 << 22) +#define SCANLINE_BLT (0x21 << 22) +#define TEXT_BLT (0x22 << 22) +#define TEXT_IMM_BLT (0x30 << 22) +#define COLOR_BLT (0x40 << 22) +#define MONO_PAT_BLIT (0x42 << 22) +#define SOURCE_COPY_BLIT (0x43 << 22) +#define MONO_SOURCE_COPY_BLIT (0x44 << 22) +#define SOURCE_COPY_IMMEDIATE (0x60 << 22) +#define MONO_SOURCE_COPY_IMMEDIATE (0x61 << 22) + +#define VERSION_MAJOR 0 +#define VERSION_MINOR 9 +#define VERSION_TEENIE 0 +#define BRANCH_VERSION "" + + +/* mvo: intel i815 */ +#ifndef PCI_DEVICE_ID_INTEL_82815_100 + #define PCI_DEVICE_ID_INTEL_82815_100 0x1102 +#endif +#ifndef PCI_DEVICE_ID_INTEL_82815_NOAGP + #define PCI_DEVICE_ID_INTEL_82815_NOAGP 0x1112 +#endif +#ifndef PCI_DEVICE_ID_INTEL_82815_FULL_CTRL + #define PCI_DEVICE_ID_INTEL_82815_FULL_CTRL 0x1130 +#endif + +/* General Defines */ +#define I810_PAGESIZE 4096 +#define MAX_DMA_SIZE (1024 * 4096) +#define SAREA_SIZE 4096 +#define PCI_I810_MISCC 0x72 +#define MMIO_SIZE (512*1024) +#define GTT_SIZE (16*1024) +#define RINGBUFFER_SIZE (64*1024) +#define CURSOR_SIZE 4096 +#define OFF 0 +#define ON 1 +#define MAX_KEY 256 +#define WAIT_COUNT 10000000 +#define IRING_PAD 8 +#define FONTDATAMAX 8192 +/* Masks (AND ops) and OR's */ +#define FB_START_MASK (0x3f << (32 - 6)) +#define MMIO_ADDR_MASK (0x1FFF << (32 - 13)) +#define FREQ_MASK (1 << 4) +#define SCR_OFF 0x20 +#define DRAM_ON 0x08 +#define DRAM_OFF 0xE7 +#define PG_ENABLE_MASK 0x01 +#define RING_SIZE_MASK (RINGBUFFER_SIZE - 1) + +/* defines for restoring registers partially */ +#define ADDR_MAP_MASK (0x07 << 5) +#define DISP_CTRL ~0 +#define PIXCONF_0 (0x64 << 8) +#define PIXCONF_2 (0xF3 << 24) +#define PIXCONF_1 (0xF0 << 16) +#define MN_MASK 0x3FF03FF +#define P_OR (0x7 << 4) +#define DAC_BIT (1 << 16) +#define INTERLACE_BIT (1 << 7) +#define IER_MASK (3 << 13) +#define IMR_MASK (3 << 13) + +/* Power Management */ +#define DPMS_MASK 0xF0000 +#define POWERON 0x00000 +#define STANDBY 0x20000 +#define SUSPEND 0x80000 +#define POWERDOWN 0xA0000 +#define EMR_MASK ~0x3F +#define FW_BLC_MASK ~(0x3F|(7 << 8)|(0x3F << 12)|(7 << 20)) + +/* Ringbuffer */ +#define RBUFFER_START_MASK 0xFFFFF000 +#define RBUFFER_SIZE_MASK 0x001FF000 +#define RBUFFER_HEAD_MASK 0x001FFFFC +#define RBUFFER_TAIL_MASK 0x001FFFF8 + +/* Video Timings */ +#define REF_FREQ 24000000 +#define TARGET_N_MAX 30 + +#define MAX_PIXELCLOCK 230000000 +#define MIN_PIXELCLOCK 15000000 +#define VFMAX 60 +#define VFMIN 60 +#define HFMAX 30000 +#define HFMIN 29000 + +/* Cursor */ +#define CURSOR_ENABLE_MASK 0x1000 +#define CURSOR_MODE_64_TRANS 4 +#define CURSOR_MODE_64_XOR 5 +#define CURSOR_MODE_64_3C 6 +#define COORD_INACTIVE 0 +#define COORD_ACTIVE (1 << 4) +#define EXTENDED_PALETTE 1 + +/* AGP Memory Types*/ +#define AGP_NORMAL_MEMORY 0 +#define AGP_DCACHE_MEMORY 1 +#define AGP_PHYSICAL_MEMORY 2 + +/* Allocated resource Flags */ +#define FRAMEBUFFER_REQ 1 +#define MMIO_REQ 2 +#define PCI_DEVICE_ENABLED 4 +#define HAS_FONTCACHE 8 + +/* driver flags */ +#define HAS_ACCELERATION 2 +#define ALWAYS_SYNC 4 +#define LOCKUP 8 + +struct gtt_data { + struct agp_memory *i810_fb_memory; + struct agp_memory *i810_cursor_memory; +}; + +struct mode_registers { + u32 pixclock, M, N, P; + u8 cr00, cr01, cr02, cr03; + u8 cr04, cr05, cr06, cr07; + u8 cr09, cr10, cr11, cr12; + u8 cr13, cr15, cr16, cr30; + u8 cr31, cr32, cr33, cr35, cr39; + u32 bpp8_100, bpp16_100; + u32 bpp24_100, bpp8_133; + u32 bpp16_133, bpp24_133; + u8 msr; +}; + +struct heap_data { + unsigned long physical; + __u8 __iomem *virtual; + u32 offset; + u32 size; +}; + +struct state_registers { + u32 dclk_1d, dclk_2d, dclk_0ds; + u32 pixconf, fw_blc, pgtbl_ctl; + u32 fence0, hws_pga, dplystas; + u16 bltcntl, hwstam, ier, iir, imr; + u8 cr00, cr01, cr02, cr03, cr04; + u8 cr05, cr06, cr07, cr08, cr09; + u8 cr10, cr11, cr12, cr13, cr14; + u8 cr15, cr16, cr17, cr80, gr10; + u8 cr30, cr31, cr32, cr33, cr35; + u8 cr39, cr41, cr70, sr01, msr; +}; + +struct i810fb_par; + +struct i810fb_i2c_chan { + struct i810fb_par *par; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; + unsigned long ddc_base; +}; + +struct i810fb_par { + struct mode_registers regs; + struct state_registers hw_state; + struct gtt_data i810_gtt; + struct fb_ops i810fb_ops; + struct pci_dev *dev; + struct heap_data aperture; + struct heap_data fb; + struct heap_data iring; + struct heap_data cursor_heap; + struct vgastate state; + struct i810fb_i2c_chan chan[3]; + struct mutex open_lock; + unsigned int use_count; + u32 pseudo_palette[16]; + unsigned long mmio_start_phys; + u8 __iomem *mmio_start_virtual; + u8 *edid; + u32 pitch; + u32 pixconf; + u32 watermark; + u32 mem_freq; + u32 res_flags; + u32 dev_flags; + u32 cur_tail; + u32 depth; + u32 blit_bpp; + u32 ovract; + u32 cur_state; + u32 ddc_num; + int wc_cookie; + u16 bltcntl; + u8 interlace; +}; + +/* + * Register I/O + */ +#define i810_readb(where, mmio) readb(mmio + where) +#define i810_readw(where, mmio) readw(mmio + where) +#define i810_readl(where, mmio) readl(mmio + where) +#define i810_writeb(where, mmio, val) writeb(val, mmio + where) +#define i810_writew(where, mmio, val) writew(val, mmio + where) +#define i810_writel(where, mmio, val) writel(val, mmio + where) + +#endif /* __I810_H__ */ diff --git a/drivers/video/fbdev/i810/i810_accel.c b/drivers/video/fbdev/i810/i810_accel.c new file mode 100644 index 000000000..7672d2ea9 --- /dev/null +++ b/drivers/video/fbdev/i810/i810_accel.c @@ -0,0 +1,456 @@ +/*-*- linux-c -*- + * linux/drivers/video/i810_accel.c -- Hardware Acceleration + * + * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/fb.h> + +#include "i810_regs.h" +#include "i810.h" +#include "i810_main.h" + +static u32 i810fb_rop[] = { + COLOR_COPY_ROP, /* ROP_COPY */ + XOR_ROP /* ROP_XOR */ +}; + +/* Macros */ +#define PUT_RING(n) { \ + i810_writel(par->cur_tail, par->iring.virtual, n); \ + par->cur_tail += 4; \ + par->cur_tail &= RING_SIZE_MASK; \ +} + +extern void flush_cache(void); + +/************************************************************/ + +/* BLT Engine Routines */ +static inline void i810_report_error(u8 __iomem *mmio) +{ + printk("IIR : 0x%04x\n" + "EIR : 0x%04x\n" + "PGTBL_ER: 0x%04x\n" + "IPEIR : 0x%04x\n" + "IPEHR : 0x%04x\n", + i810_readw(IIR, mmio), + i810_readb(EIR, mmio), + i810_readl(PGTBL_ER, mmio), + i810_readl(IPEIR, mmio), + i810_readl(IPEHR, mmio)); +} + +/** + * wait_for_space - check ring buffer free space + * @space: amount of ringbuffer space needed in bytes + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * The function waits until a free space from the ringbuffer + * is available + */ +static inline int wait_for_space(struct fb_info *info, u32 space) +{ + struct i810fb_par *par = info->par; + u32 head, count = WAIT_COUNT, tail; + u8 __iomem *mmio = par->mmio_start_virtual; + + tail = par->cur_tail; + while (count--) { + head = i810_readl(IRING + 4, mmio) & RBUFFER_HEAD_MASK; + if ((tail == head) || + (tail > head && + (par->iring.size - tail + head) >= space) || + (tail < head && (head - tail) >= space)) { + return 0; + } + } + printk("ringbuffer lockup!!!\n"); + i810_report_error(mmio); + par->dev_flags |= LOCKUP; + info->pixmap.scan_align = 1; + return 1; +} + +/** + * wait_for_engine_idle - waits for all hardware engines to finish + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * This waits for lring(0), iring(1), and batch(3), etc to finish and + * waits until ringbuffer is empty. + */ +static inline int wait_for_engine_idle(struct fb_info *info) +{ + struct i810fb_par *par = info->par; + u8 __iomem *mmio = par->mmio_start_virtual; + int count = WAIT_COUNT; + + if (wait_for_space(info, par->iring.size)) /* flush */ + return 1; + + while((i810_readw(INSTDONE, mmio) & 0x7B) != 0x7B && --count); + if (count) return 0; + + printk("accel engine lockup!!!\n"); + printk("INSTDONE: 0x%04x\n", i810_readl(INSTDONE, mmio)); + i810_report_error(mmio); + par->dev_flags |= LOCKUP; + info->pixmap.scan_align = 1; + return 1; +} + +/* begin_iring - prepares the ringbuffer + * @space: length of sequence in dwords + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Checks/waits for sufficient space in ringbuffer of size + * space. Returns the tail of the buffer + */ +static inline u32 begin_iring(struct fb_info *info, u32 space) +{ + struct i810fb_par *par = info->par; + + if (par->dev_flags & ALWAYS_SYNC) + wait_for_engine_idle(info); + return wait_for_space(info, space); +} + +/** + * end_iring - advances the buffer + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * This advances the tail of the ringbuffer, effectively + * beginning the execution of the graphics instruction sequence. + */ +static inline void end_iring(struct i810fb_par *par) +{ + u8 __iomem *mmio = par->mmio_start_virtual; + + i810_writel(IRING, mmio, par->cur_tail); +} + +/** + * source_copy_blit - BLIT transfer operation + * @dwidth: width of rectangular graphics data + * @dheight: height of rectangular graphics data + * @dpitch: bytes per line of destination buffer + * @xdir: direction of copy (left to right or right to left) + * @src: address of first pixel to read from + * @dest: address of first pixel to write to + * @from: source address + * @where: destination address + * @rop: raster operation + * @blit_bpp: pixel format which can be different from the + * framebuffer's pixelformat + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * This is a BLIT operation typically used when doing + * a 'Copy and Paste' + */ +static inline void source_copy_blit(int dwidth, int dheight, int dpitch, + int xdir, int src, int dest, int rop, + int blit_bpp, struct fb_info *info) +{ + struct i810fb_par *par = info->par; + + if (begin_iring(info, 24 + IRING_PAD)) return; + + PUT_RING(BLIT | SOURCE_COPY_BLIT | 4); + PUT_RING(xdir | rop << 16 | dpitch | DYN_COLOR_EN | blit_bpp); + PUT_RING(dheight << 16 | dwidth); + PUT_RING(dest); + PUT_RING(dpitch); + PUT_RING(src); + + end_iring(par); +} + +/** + * color_blit - solid color BLIT operation + * @width: width of destination + * @height: height of destination + * @pitch: pixels per line of the buffer + * @dest: address of first pixel to write to + * @where: destination + * @rop: raster operation + * @what: color to transfer + * @blit_bpp: pixel format which can be different from the + * framebuffer's pixelformat + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * A BLIT operation which can be used for color fill/rectangular fill + */ +static inline void color_blit(int width, int height, int pitch, int dest, + int rop, int what, int blit_bpp, + struct fb_info *info) +{ + struct i810fb_par *par = info->par; + + if (begin_iring(info, 24 + IRING_PAD)) return; + + PUT_RING(BLIT | COLOR_BLT | 3); + PUT_RING(rop << 16 | pitch | SOLIDPATTERN | DYN_COLOR_EN | blit_bpp); + PUT_RING(height << 16 | width); + PUT_RING(dest); + PUT_RING(what); + PUT_RING(NOP); + + end_iring(par); +} + +/** + * mono_src_copy_imm_blit - color expand from system memory to framebuffer + * @dwidth: width of destination + * @dheight: height of destination + * @dpitch: pixels per line of the buffer + * @dsize: size of bitmap in double words + * @dest: address of first byte of pixel; + * @rop: raster operation + * @blit_bpp: pixelformat to use which can be different from the + * framebuffer's pixelformat + * @src: address of image data + * @bg: backgound color + * @fg: forground color + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * A color expand operation where the source data is placed in the + * ringbuffer itself. Useful for drawing text. + * + * REQUIREMENT: + * The end of a scanline must be padded to the next word. + */ +static inline void mono_src_copy_imm_blit(int dwidth, int dheight, int dpitch, + int dsize, int blit_bpp, int rop, + int dest, const u32 *src, int bg, + int fg, struct fb_info *info) +{ + struct i810fb_par *par = info->par; + + if (begin_iring(info, 24 + (dsize << 2) + IRING_PAD)) return; + + PUT_RING(BLIT | MONO_SOURCE_COPY_IMMEDIATE | (4 + dsize)); + PUT_RING(DYN_COLOR_EN | blit_bpp | rop << 16 | dpitch); + PUT_RING(dheight << 16 | dwidth); + PUT_RING(dest); + PUT_RING(bg); + PUT_RING(fg); + while (dsize--) + PUT_RING(*src++); + + end_iring(par); +} + +static inline void load_front(int offset, struct fb_info *info) +{ + struct i810fb_par *par = info->par; + + if (begin_iring(info, 8 + IRING_PAD)) return; + + PUT_RING(PARSER | FLUSH); + PUT_RING(NOP); + + end_iring(par); + + if (begin_iring(info, 8 + IRING_PAD)) return; + + PUT_RING(PARSER | FRONT_BUFFER | ((par->pitch >> 3) << 8)); + PUT_RING((par->fb.offset << 12) + offset); + + end_iring(par); +} + +/** + * i810fb_iring_enable - enables/disables the ringbuffer + * @mode: enable or disable + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Enables or disables the ringbuffer, effectively enabling or + * disabling the instruction/acceleration engine. + */ +static inline void i810fb_iring_enable(struct i810fb_par *par, u32 mode) +{ + u32 tmp; + u8 __iomem *mmio = par->mmio_start_virtual; + + tmp = i810_readl(IRING + 12, mmio); + if (mode == OFF) + tmp &= ~1; + else + tmp |= 1; + flush_cache(); + i810_writel(IRING + 12, mmio, tmp); +} + +void i810fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct i810fb_par *par = info->par; + u32 dx, dy, width, height, dest, rop = 0, color = 0; + + if (!info->var.accel_flags || par->dev_flags & LOCKUP || + par->depth == 4) { + cfb_fillrect(info, rect); + return; + } + + if (par->depth == 1) + color = rect->color; + else + color = ((u32 *) (info->pseudo_palette))[rect->color]; + + rop = i810fb_rop[rect->rop]; + + dx = rect->dx * par->depth; + width = rect->width * par->depth; + dy = rect->dy; + height = rect->height; + + dest = info->fix.smem_start + (dy * info->fix.line_length) + dx; + color_blit(width, height, info->fix.line_length, dest, rop, color, + par->blit_bpp, info); +} + +void i810fb_copyarea(struct fb_info *info, const struct fb_copyarea *region) +{ + struct i810fb_par *par = info->par; + u32 sx, sy, dx, dy, pitch, width, height, src, dest, xdir; + + if (!info->var.accel_flags || par->dev_flags & LOCKUP || + par->depth == 4) { + cfb_copyarea(info, region); + return; + } + + dx = region->dx * par->depth; + sx = region->sx * par->depth; + width = region->width * par->depth; + sy = region->sy; + dy = region->dy; + height = region->height; + + if (dx <= sx) { + xdir = INCREMENT; + } + else { + xdir = DECREMENT; + sx += width - 1; + dx += width - 1; + } + if (dy <= sy) { + pitch = info->fix.line_length; + } + else { + pitch = (-(info->fix.line_length)) & 0xFFFF; + sy += height - 1; + dy += height - 1; + } + src = info->fix.smem_start + (sy * info->fix.line_length) + sx; + dest = info->fix.smem_start + (dy * info->fix.line_length) + dx; + + source_copy_blit(width, height, pitch, xdir, src, dest, + PAT_COPY_ROP, par->blit_bpp, info); +} + +void i810fb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct i810fb_par *par = info->par; + u32 fg = 0, bg = 0, size, dst; + + if (!info->var.accel_flags || par->dev_flags & LOCKUP || + par->depth == 4 || image->depth != 1) { + cfb_imageblit(info, image); + return; + } + + switch (info->var.bits_per_pixel) { + case 8: + fg = image->fg_color; + bg = image->bg_color; + break; + case 16: + case 24: + fg = ((u32 *)(info->pseudo_palette))[image->fg_color]; + bg = ((u32 *)(info->pseudo_palette))[image->bg_color]; + break; + } + + dst = info->fix.smem_start + (image->dy * info->fix.line_length) + + (image->dx * par->depth); + + size = (image->width+7)/8 + 1; + size &= ~1; + size *= image->height; + size += 7; + size &= ~7; + mono_src_copy_imm_blit(image->width * par->depth, + image->height, info->fix.line_length, + size/4, par->blit_bpp, + PAT_COPY_ROP, dst, (u32 *) image->data, + bg, fg, info); +} + +int i810fb_sync(struct fb_info *info) +{ + struct i810fb_par *par = info->par; + + if (!info->var.accel_flags || par->dev_flags & LOCKUP) + return 0; + + return wait_for_engine_idle(info); +} + +void i810fb_load_front(u32 offset, struct fb_info *info) +{ + struct i810fb_par *par = info->par; + u8 __iomem *mmio = par->mmio_start_virtual; + + if (!info->var.accel_flags || par->dev_flags & LOCKUP) + i810_writel(DPLYBASE, mmio, par->fb.physical + offset); + else + load_front(offset, info); +} + +/** + * i810fb_init_ringbuffer - initialize the ringbuffer + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Initializes the ringbuffer by telling the device the + * size and location of the ringbuffer. It also sets + * the head and tail pointers = 0 + */ +void i810fb_init_ringbuffer(struct fb_info *info) +{ + struct i810fb_par *par = info->par; + u32 tmp1, tmp2; + u8 __iomem *mmio = par->mmio_start_virtual; + + wait_for_engine_idle(info); + i810fb_iring_enable(par, OFF); + i810_writel(IRING, mmio, 0); + i810_writel(IRING + 4, mmio, 0); + par->cur_tail = 0; + + tmp2 = i810_readl(IRING + 8, mmio) & ~RBUFFER_START_MASK; + tmp1 = par->iring.physical; + i810_writel(IRING + 8, mmio, tmp2 | tmp1); + + tmp1 = i810_readl(IRING + 12, mmio); + tmp1 &= ~RBUFFER_SIZE_MASK; + tmp2 = (par->iring.size - I810_PAGESIZE) & RBUFFER_SIZE_MASK; + i810_writel(IRING + 12, mmio, tmp1 | tmp2); + i810fb_iring_enable(par, ON); +} diff --git a/drivers/video/fbdev/i810/i810_dvt.c b/drivers/video/fbdev/i810/i810_dvt.c new file mode 100644 index 000000000..2082b5c92 --- /dev/null +++ b/drivers/video/fbdev/i810/i810_dvt.c @@ -0,0 +1,313 @@ +/*-*- linux-c -*- + * linux/drivers/video/i810_dvt.c -- Intel 810 Discrete Video Timings (Intel) + * + * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/kernel.h> + +#include "i810_regs.h" +#include "i810.h" +#include "i810_main.h" + +struct mode_registers std_modes[] = { + /* 640x480 @ 60Hz */ + { 25000, 0x0013, 0x0003, 0x40, 0x5F, 0x4F, 0x50, 0x82, 0x51, 0x9D, + 0x0B, 0x10, 0x40, 0xE9, 0x0B, 0xDF, 0x50, 0xE7, 0x04, 0x02, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x22002000, 0x22004000, 0x22006000, + 0x22002000, 0x22004000, 0x22006000, 0xC0 }, + + /* 640x480 @ 70Hz */ + { 28000, 0x0053, 0x0010, 0x40, 0x61, 0x4F, 0x4F, 0x85, 0x52, 0x9A, + 0xF2, 0x10, 0x40, 0xE0, 0x03, 0xDF, 0x50, 0xDF, 0xF3, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x22002000, 0x22004000, 0x22005000, + 0x22002000, 0x22004000, 0x22005000, 0xC0 }, + + /* 640x480 @ 72Hz */ + { 31000, 0x0013, 0x0002, 0x40, 0x63, 0x4F, 0x4F, 0x87, 0x52, 0x97, + 0x06, 0x0F, 0x40, 0xE8, 0x0B, 0xDF, 0x50, 0xDF, 0x07, 0x02, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x22003000, 0x22005000, 0x22007000, + 0x22003000, 0x22005000, 0x22007000, 0xC0 }, + + /* 640x480 @ 75Hz */ + { 31000, 0x0013, 0x0002, 0x40, 0x64, 0x4F, 0x4F, 0x88, 0x51, 0x99, + 0xF2, 0x10, 0x40, 0xE0, 0x03, 0xDF, 0x50, 0xDF, 0xF3, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x22003000, 0x22005000, 0x22007000, + 0x22003000, 0x22005000, 0x22007000, 0xC0 }, + + /* 640x480 @ 85Hz */ + { 36000, 0x0010, 0x0001, 0x40, 0x63, 0x4F, 0x4F, 0x87, 0x56, 0x9D, + 0xFB, 0x10, 0x40, 0xE0, 0x03, 0xDF, 0x50, 0xDF, 0xFC, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x22003000, 0x22005000, 0x22107000, + 0x22003000, 0x22005000, 0x22107000, 0xC0 }, + + /* 800x600 @ 56Hz */ + { 36000, 0x0010, 0x0001, 0x40, 0x7B, 0x63, 0x63, 0x9F, 0x66, 0x8F, + 0x6F, 0x10, 0x40, 0x58, 0x0A, 0x57, 0xC8, 0x57, 0x70, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x01, 0x22003000, 0x22005000, 0x22107000, + 0x22003000, 0x22005000, 0x22107000, 0x00 }, + + /* 800x600 @ 60Hz */ + { 40000, 0x0008, 0x0001, 0x30, 0x7F, 0x63, 0x63, 0x83, 0x68, 0x18, + 0x72, 0x10, 0x40, 0x58, 0x0C, 0x57, 0xC8, 0x57, 0x73, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x00, 0x22003000, 0x22006000, 0x22108000, + 0x22003000, 0x22006000, 0x22108000, 0x00 }, + + /* 800x600 @ 70Hz */ + { 45000, 0x0054, 0x0015, 0x30, 0x7D, 0x63, 0x63, 0x81, 0x68, 0x12, + 0x6f, 0x10, 0x40, 0x58, 0x0b, 0x57, 0x64, 0x57, 0x70, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22007000, 0x2210A000, + 0x22004000, 0x22007000, 0x2210A000, 0x00 }, + + /* 800x600 @ 72Hz */ + { 50000, 0x0017, 0x0004, 0x30, 0x7D, 0x63, 0x63, 0x81, 0x6A, 0x19, + 0x98, 0x10, 0x40, 0x7C, 0x02, 0x57, 0xC8, 0x57, 0x99, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22007000, 0x2210A000, + 0x22004000, 0x22007000, 0x2210A000, 0x00 }, + + /* 800x600 @ 75Hz */ + { 49000, 0x001F, 0x0006, 0x30, 0x7F, 0x63, 0x63, 0x83, 0x65, 0x0F, + 0x6F, 0x10, 0x40, 0x58, 0x0B, 0x57, 0xC8, 0x57, 0x70, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22007000, 0x2210B000, + 0x22004000, 0x22007000, 0x2210B000, 0x00 }, + + /* 800x600 @ 85Hz */ + { 56000, 0x0049, 0x000E, 0x30, 0x7E, 0x63, 0x63, 0x82, 0x67, 0x0F, + 0x75, 0x10, 0x40, 0x58, 0x0B, 0x57, 0xC8, 0x57, 0x76, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22108000, 0x2210b000, + 0x22004000, 0x22108000, 0x2210b000, 0x00 }, + + /* 1024x768 @ 60Hz */ + { 65000, 0x003F, 0x000A, 0x30, 0xA3, 0x7F, 0x7F, 0x87, 0x83, 0x94, + 0x24, 0x10, 0x40, 0x02, 0x08, 0xFF, 0x80, 0xFF, 0x25, 0x03, + 0x02, 0x03, 0x02, 0x00, 0x00, 0x22005000, 0x22109000, 0x2220D000, + 0x22005000, 0x22109000, 0x2220D000, 0xC0 }, + + /* 1024x768 @ 70Hz */ + { 75000, 0x0017, 0x0002, 0x30, 0xA1, 0x7F, 0x7F, 0x85, 0x82, 0x93, + 0x24, 0x10, 0x40, 0x02, 0x08, 0xFF, 0x80, 0xFF, 0x25, 0x03, + 0x02, 0x03, 0x02, 0x00, 0x00, 0x22005000, 0x2210A000, 0x2220F000, + 0x22005000, 0x2210A000, 0x2220F000, 0xC0 }, + + /* 1024x768 @ 75Hz */ + { 78000, 0x0050, 0x0017, 0x20, 0x9F, 0x7F, 0x7F, 0x83, 0x81, 0x8D, + 0x1E, 0x10, 0x40, 0x00, 0x03, 0xFF, 0x80, 0xFF, 0x1F, 0x03, + 0x02, 0x03, 0x02, 0x00, 0x00, 0x22006000, 0x2210B000, 0x22210000, + 0x22006000, 0x2210B000, 0x22210000, 0x00 }, + + /* 1024x768 @ 85Hz */ + { 94000, 0x003D, 0x000E, 0x20, 0xA7, 0x7F, 0x7F, 0x8B, 0x85, 0x91, + 0x26, 0x10, 0x40, 0x00, 0x03, 0xFF, 0x80, 0xFF, 0x27, 0x03, + 0x02, 0x03, 0x02, 0x00, 0x00, 0x22007000, 0x2220E000, 0x22212000, + 0x22007000, 0x2220E000, 0x22212000, 0x00 }, + + /* 1152x864 @ 60Hz */ + { 80000, 0x0008, 0x0001, 0x20, 0xB3, 0x8F, 0x8F, 0x97, 0x93, 0x9f, + 0x87, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5f, 0x88, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x00, 0x2220C000, 0x22210000, 0x22415000, + 0x2220C000, 0x22210000, 0x22415000, 0x00 }, + + /* 1152x864 @ 70Hz */ + { 96000, 0x000a, 0x0001, 0x20, 0xbb, 0x8F, 0x8F, 0x9f, 0x98, 0x87, + 0x82, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x83, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x00, 0x22107000, 0x22210000, 0x22415000, + 0x22107000, 0x22210000, 0x22415000, 0x00 }, + + /* 1152x864 @ 72Hz */ + { 99000, 0x001f, 0x0006, 0x20, 0xbb, 0x8F, 0x8F, 0x9f, 0x98, 0x87, + 0x83, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x84, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x00, 0x22107000, 0x22210000, 0x22415000, + 0x22107000, 0x22210000, 0x22415000, 0x00 }, + + /* 1152x864 @ 75Hz */ + { 108000, 0x0010, 0x0002, 0x20, 0xC3, 0x8F, 0x8F, 0x87, 0x97, 0x07, + 0x82, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x83, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x01, 0x22107000, 0x22210000, 0x22415000, + 0x22107000, 0x22210000, 0x22415000, 0x00 }, + + /* 1152x864 @ 85Hz */ + { 121000, 0x006D, 0x0014, 0x20, 0xc0, 0x8F, 0x8F, 0x84, 0x97, 0x07, + 0x93, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x94, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x01, 0x2220C000, 0x22210000, 0x22415000, + 0x2220C000, 0x22210000, 0x22415000, 0x0 }, + + /* 1280x960 @ 60Hz */ + { 108000, 0x0010, 0x0002, 0x20, 0xDC, 0x9F, 0x9F, 0x80, 0xAB, 0x99, + 0xE6, 0x10, 0x40, 0xC0, 0x03, 0xBF, 0xA0, 0xBF, 0xE7, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x01, 0x2210A000, 0x22210000, 0x22415000, + 0x2210A000, 0x22210000, 0x22415000, 0x00 }, + + /* 1280x960 @ 75Hz */ + { 129000, 0x0029, 0x0006, 0x20, 0xD3, 0x9F, 0x9F, 0x97, 0xaa, 0x1b, + 0xE8, 0x10, 0x40, 0xC0, 0x03, 0xBF, 0xA0, 0xBF, 0xE9, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x01, 0x2210A000, 0x22210000, 0x2241B000, + 0x2210A000, 0x22210000, 0x2241B000, 0x00 }, + + /* 1280x960 @ 85Hz */ + { 148000, 0x0042, 0x0009, 0x20, 0xD3, 0x9F, 0x9F, 0x97, 0xA7, 0x1B, + 0xF1, 0x10, 0x40, 0xC0, 0x03, 0xBF, 0xA0, 0xBF, 0xF2, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x01, 0x2210A000, 0x22220000, 0x2241D000, + 0x2210A000, 0x22220000, 0x2241D000, 0x00 }, + + /* 1600x1200 @ 60Hz */ + { 162000, 0x0019, 0x0006, 0x10, 0x09, 0xC7, 0xC7, 0x8D, 0xcf, 0x07, + 0xE0, 0x10, 0x40, 0xB0, 0x03, 0xAF, 0xC8, 0xAF, 0xE1, 0x04, + 0x04, 0x04, 0x04, 0x01, 0x00, 0x2210b000, 0x22416000, 0x44419000, + 0x2210b000, 0x22416000, 0x44419000, 0x00 }, + + /* 1600x1200 @ 65 Hz */ + { 175000, 0x005d, 0x0018, 0x10, 0x09, 0xC7, 0xC7, 0x8D, 0xcf, 0x07, + 0xE0, 0x10, 0x40, 0xB0, 0x03, 0xAF, 0xC8, 0xAF, 0xE1, 0x04, + 0x04, 0x04, 0x04, 0x01, 0x00, 0x2210c000, 0x22416000, 0x44419000, + 0x2210c000, 0x22416000, 0x44419000, 0x00 }, + + /* 1600x1200 @ 70 Hz */ + { 189000, 0x003D, 0x000e, 0x10, 0x09, 0xC7, 0xC7, 0x8d, 0xcf, 0x07, + 0xE0, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xE1, 0x04, + 0x04, 0x04, 0x04, 0x01, 0x00, 0x2220e000, 0x22416000, 0x44419000, + 0x2220e000, 0x22416000, 0x44419000, 0x00 }, + + /* 1600x1200 @ 72 Hz */ + { 195000, 0x003f, 0x000e, 0x10, 0x0b, 0xC7, 0xC7, 0x8f, 0xd5, 0x0b, + 0xE1, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xe2, 0x04, 0x04, + 0x04, 0x04, 0x01, 0x00, 0x2220e000, 0x22416000, 0x44419000, + 0x2220e000, 0x22416000, 0x44419000, 0x00 }, + + /* 1600x1200 @ 75 Hz */ + { 202000, 0x0024, 0x0007, 0x10, 0x09, 0xC7, 0xC7, 0x8d, 0xcf, 0x07, + 0xE0, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xE1, 0x04, 0x04, + 0x04, 0x04, 0x01, 0x00, 0x2220e000, 0x22416000, 0x44419000, + 0x2220e000, 0x22416000, 0x44419000, 0x00 }, + + /* 1600x1200 @ 85 Hz */ + { 229000, 0x0029, 0x0007, 0x10, 0x09, 0xC7, 0xC7, 0x8d, 0xcf, 0x07, + 0xE0, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xE1, 0x04, 0x04, + 0x04, 0x04, 0x01, 0x00, 0x22210000, 0x22416000, 0x0, + 0x22210000, 0x22416000, 0x0, 0x00 }, +}; + +void round_off_xres(u32 *xres) +{ + if (*xres <= 640) + *xres = 640; + else if (*xres <= 800) + *xres = 800; + else if (*xres <= 1024) + *xres = 1024; + else if (*xres <= 1152) + *xres = 1152; + else if (*xres <= 1280) + *xres = 1280; + else + *xres = 1600; +} + +inline void round_off_yres(u32 *xres, u32 *yres) +{ + *yres = (*xres * 3) >> 2; +} + +static int i810fb_find_best_mode(u32 xres, u32 yres, u32 pixclock) +{ + u32 diff = 0, diff_best = 0xFFFFFFFF, i = 0, i_best = 0; + u8 hfl = (u8) ((xres >> 3) - 1); + + for (i = 0; i < ARRAY_SIZE(std_modes); i++) { + if (std_modes[i].cr01 == hfl) { + if (std_modes[i].pixclock <= pixclock) + diff = pixclock - std_modes[i].pixclock; + if (diff < diff_best) { + i_best = i; + diff_best = diff; + } + } + } + return i_best; +} + +void i810fb_encode_registers(const struct fb_var_screeninfo *var, + struct i810fb_par *par, u32 xres, u32 yres) +{ + u32 i_best = i810fb_find_best_mode(xres, yres, par->regs.pixclock); + + par->regs = std_modes[i_best]; + + /* overlay */ + par->ovract = ((xres + var->right_margin + var->hsync_len + + var->left_margin - 32) | ((xres - 32) << 16)); +} + +void i810fb_fill_var_timings(struct fb_var_screeninfo *var) +{ + u32 total, xres, yres; + u32 mode, pixclock; + + xres = var->xres; + yres = var->yres; + + pixclock = 1000000000 / var->pixclock; + mode = i810fb_find_best_mode(xres, yres, pixclock); + + total = (std_modes[mode].cr00 | (std_modes[mode].cr35 & 1) << 8) + 3; + total <<= 3; + + var->pixclock = 1000000000 / std_modes[mode].pixclock; + var->right_margin = (std_modes[mode].cr04 << 3) - xres; + var->hsync_len = ((std_modes[mode].cr05 & 0x1F) - + (std_modes[mode].cr04 & 0x1F)) << 3; + var->left_margin = (total - (xres + var->right_margin + + var->hsync_len)); + var->sync = FB_SYNC_ON_GREEN; + if (~(std_modes[mode].msr & (1 << 6))) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (~(std_modes[mode].msr & (1 << 7))) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + + total = (std_modes[mode].cr06 | (std_modes[mode].cr30 & 0xF) << 8) + 2; + var->lower_margin = (std_modes[mode].cr10 | + (std_modes[mode].cr32 & 0x0F) << 8) - yres; + var->vsync_len = (std_modes[mode].cr11 & 0x0F) - + (var->lower_margin & 0x0F); + var->upper_margin = total - (yres + var->lower_margin + var->vsync_len); +} + +u32 i810_get_watermark(const struct fb_var_screeninfo *var, + struct i810fb_par *par) +{ + struct mode_registers *params = &par->regs; + u32 wmark = 0; + + if (par->mem_freq == 100) { + switch (var->bits_per_pixel) { + case 8: + wmark = params->bpp8_100; + break; + case 16: + wmark = params->bpp16_100; + break; + case 24: + case 32: + wmark = params->bpp24_100; + } + } else { + switch (var->bits_per_pixel) { + case 8: + wmark = params->bpp8_133; + break; + case 16: + wmark = params->bpp16_133; + break; + case 24: + case 32: + wmark = params->bpp24_133; + } + } + return wmark; +} + diff --git a/drivers/video/fbdev/i810/i810_gtf.c b/drivers/video/fbdev/i810/i810_gtf.c new file mode 100644 index 000000000..9743d51e7 --- /dev/null +++ b/drivers/video/fbdev/i810/i810_gtf.c @@ -0,0 +1,276 @@ +/*-*- linux-c -*- + * linux/drivers/video/i810_main.h -- Intel 810 Non-discrete Video Timings + * (VESA GTF) + * + * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ +#include <linux/kernel.h> + +#include "i810_regs.h" +#include "i810.h" +#include "i810_main.h" + +/* + * FIFO and Watermark tables - based almost wholly on i810_wmark.c in + * XFree86 v4.03 by Precision Insight. Slightly modified for integer + * operation, instead of float + */ + +struct wm_info { + u32 freq; + u32 wm; +}; + +static struct wm_info i810_wm_8_100[] = { + { 15, 0x0070c000 }, { 19, 0x0070c000 }, { 25, 0x22003000 }, + { 28, 0x22003000 }, { 31, 0x22003000 }, { 36, 0x22007000 }, + { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22008000 }, + { 50, 0x22008000 }, { 56, 0x22008000 }, { 65, 0x22008000 }, + { 75, 0x22008000 }, { 78, 0x22008000 }, { 80, 0x22008000 }, + { 94, 0x22008000 }, { 96, 0x22107000 }, { 99, 0x22107000 }, + { 108, 0x22107000 }, { 121, 0x22107000 }, { 128, 0x22107000 }, + { 132, 0x22109000 }, { 135, 0x22109000 }, { 157, 0x2210b000 }, + { 162, 0x2210b000 }, { 175, 0x2210b000 }, { 189, 0x2220e000 }, + { 195, 0x2220e000 }, { 202, 0x2220e000 }, { 204, 0x2220e000 }, + { 218, 0x2220f000 }, { 229, 0x22210000 }, { 234, 0x22210000 }, +}; + +static struct wm_info i810_wm_16_100[] = { + { 15, 0x0070c000 }, { 19, 0x0020c000 }, { 25, 0x22006000 }, + { 28, 0x22006000 }, { 31, 0x22007000 }, { 36, 0x22007000 }, + { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22009000 }, + { 50, 0x22009000 }, { 56, 0x22108000 }, { 65, 0x2210e000 }, + { 75, 0x2210e000 }, { 78, 0x2210e000 }, { 80, 0x22210000 }, + { 94, 0x22210000 }, { 96, 0x22210000 }, { 99, 0x22210000 }, + { 108, 0x22210000 }, { 121, 0x22210000 }, { 128, 0x22210000 }, + { 132, 0x22314000 }, { 135, 0x22314000 }, { 157, 0x22415000 }, + { 162, 0x22416000 }, { 175, 0x22416000 }, { 189, 0x22416000 }, + { 195, 0x22416000 }, { 202, 0x22416000 }, { 204, 0x22416000 }, + { 218, 0x22416000 }, { 229, 0x22416000 }, +}; + +static struct wm_info i810_wm_24_100[] = { + { 15, 0x0020c000 }, { 19, 0x0040c000 }, { 25, 0x22009000 }, + { 28, 0x22009000 }, { 31, 0x2200a000 }, { 36, 0x2210c000 }, + { 40, 0x2210c000 }, { 45, 0x2210c000 }, { 49, 0x22111000 }, + { 50, 0x22111000 }, { 56, 0x22111000 }, { 65, 0x22214000 }, + { 75, 0x22214000 }, { 78, 0x22215000 }, { 80, 0x22216000 }, + { 94, 0x22218000 }, { 96, 0x22418000 }, { 99, 0x22418000 }, + { 108, 0x22418000 }, { 121, 0x22418000 }, { 128, 0x22419000 }, + { 132, 0x22519000 }, { 135, 0x4441d000 }, { 157, 0x44419000 }, + { 162, 0x44419000 }, { 175, 0x44419000 }, { 189, 0x44419000 }, + { 195, 0x44419000 }, { 202, 0x44419000 }, { 204, 0x44419000 }, +}; + +static struct wm_info i810_wm_8_133[] = { + { 15, 0x0070c000 }, { 19, 0x0070c000 }, { 25, 0x22003000 }, + { 28, 0x22003000 }, { 31, 0x22003000 }, { 36, 0x22007000 }, + { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22008000 }, + { 50, 0x22008000 }, { 56, 0x22008000 }, { 65, 0x22008000 }, + { 75, 0x22008000 }, { 78, 0x22008000 }, { 80, 0x22008000 }, + { 94, 0x22008000 }, { 96, 0x22107000 }, { 99, 0x22107000 }, + { 108, 0x22107000 }, { 121, 0x22107000 }, { 128, 0x22107000 }, + { 132, 0x22109000 }, { 135, 0x22109000 }, { 157, 0x2210b000 }, + { 162, 0x2210b000 }, { 175, 0x2210b000 }, { 189, 0x2220e000 }, + { 195, 0x2220e000 }, { 202, 0x2220e000 }, { 204, 0x2220e000 }, + { 218, 0x2220f000 }, { 229, 0x22210000 }, { 234, 0x22210000 }, +}; + +static struct wm_info i810_wm_16_133[] = { + { 15, 0x0020c000 }, { 19, 0x0020c000 }, { 25, 0x22006000 }, + { 28, 0x22006000 }, { 31, 0x22007000 }, { 36, 0x22007000 }, + { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22009000 }, + { 50, 0x22009000 }, { 56, 0x22108000 }, { 65, 0x2210e000 }, + { 75, 0x2210e000 }, { 78, 0x2210e000 }, { 80, 0x22210000 }, + { 94, 0x22210000 }, { 96, 0x22210000 }, { 99, 0x22210000 }, + { 108, 0x22210000 }, { 121, 0x22210000 }, { 128, 0x22210000 }, + { 132, 0x22314000 }, { 135, 0x22314000 }, { 157, 0x22415000 }, + { 162, 0x22416000 }, { 175, 0x22416000 }, { 189, 0x22416000 }, + { 195, 0x22416000 }, { 202, 0x22416000 }, { 204, 0x22416000 }, + { 218, 0x22416000 }, { 229, 0x22416000 }, +}; + +static struct wm_info i810_wm_24_133[] = { + { 15, 0x0020c000 }, { 19, 0x00408000 }, { 25, 0x22009000 }, + { 28, 0x22009000 }, { 31, 0x2200a000 }, { 36, 0x2210c000 }, + { 40, 0x2210c000 }, { 45, 0x2210c000 }, { 49, 0x22111000 }, + { 50, 0x22111000 }, { 56, 0x22111000 }, { 65, 0x22214000 }, + { 75, 0x22214000 }, { 78, 0x22215000 }, { 80, 0x22216000 }, + { 94, 0x22218000 }, { 96, 0x22418000 }, { 99, 0x22418000 }, + { 108, 0x22418000 }, { 121, 0x22418000 }, { 128, 0x22419000 }, + { 132, 0x22519000 }, { 135, 0x4441d000 }, { 157, 0x44419000 }, + { 162, 0x44419000 }, { 175, 0x44419000 }, { 189, 0x44419000 }, + { 195, 0x44419000 }, { 202, 0x44419000 }, { 204, 0x44419000 }, +}; + +void round_off_xres(u32 *xres) { } +void round_off_yres(u32 *xres, u32 *yres) { } + +/** + * i810fb_encode_registers - encode @var to hardware register values + * @var: pointer to var structure + * @par: pointer to hardware par structure + * + * DESCRIPTION: + * Timing values in @var will be converted to appropriate + * register values of @par. + */ +void i810fb_encode_registers(const struct fb_var_screeninfo *var, + struct i810fb_par *par, u32 xres, u32 yres) +{ + int n, blank_s, blank_e; + u8 __iomem *mmio = par->mmio_start_virtual; + u8 msr = 0; + + /* Horizontal */ + /* htotal */ + n = ((xres + var->right_margin + var->hsync_len + + var->left_margin) >> 3) - 5; + par->regs.cr00 = (u8) n; + par->regs.cr35 = (u8) ((n >> 8) & 1); + + /* xres */ + par->regs.cr01 = (u8) ((xres >> 3) - 1); + + /* hblank */ + blank_e = (xres + var->right_margin + var->hsync_len + + var->left_margin) >> 3; + blank_e--; + blank_s = blank_e - 127; + if (blank_s < (xres >> 3)) + blank_s = xres >> 3; + par->regs.cr02 = (u8) blank_s; + par->regs.cr03 = (u8) (blank_e & 0x1F); + par->regs.cr05 = (u8) ((blank_e & (1 << 5)) << 2); + par->regs.cr39 = (u8) ((blank_e >> 6) & 1); + + /* hsync */ + par->regs.cr04 = (u8) ((xres + var->right_margin) >> 3); + par->regs.cr05 |= (u8) (((xres + var->right_margin + + var->hsync_len) >> 3) & 0x1F); + + /* Vertical */ + /* vtotal */ + n = yres + var->lower_margin + var->vsync_len + var->upper_margin - 2; + par->regs.cr06 = (u8) (n & 0xFF); + par->regs.cr30 = (u8) ((n >> 8) & 0x0F); + + /* vsync */ + n = yres + var->lower_margin; + par->regs.cr10 = (u8) (n & 0xFF); + par->regs.cr32 = (u8) ((n >> 8) & 0x0F); + par->regs.cr11 = i810_readb(CR11, mmio) & ~0x0F; + par->regs.cr11 |= (u8) ((yres + var->lower_margin + + var->vsync_len) & 0x0F); + + /* yres */ + n = yres - 1; + par->regs.cr12 = (u8) (n & 0xFF); + par->regs.cr31 = (u8) ((n >> 8) & 0x0F); + + /* vblank */ + blank_e = yres + var->lower_margin + var->vsync_len + + var->upper_margin; + blank_e--; + blank_s = blank_e - 127; + if (blank_s < yres) + blank_s = yres; + par->regs.cr15 = (u8) (blank_s & 0xFF); + par->regs.cr33 = (u8) ((blank_s >> 8) & 0x0F); + par->regs.cr16 = (u8) (blank_e & 0xFF); + par->regs.cr09 = 0; + + /* sync polarity */ + if (!(var->sync & FB_SYNC_HOR_HIGH_ACT)) + msr |= 1 << 6; + if (!(var->sync & FB_SYNC_VERT_HIGH_ACT)) + msr |= 1 << 7; + par->regs.msr = msr; + + /* interlace */ + if (var->vmode & FB_VMODE_INTERLACED) + par->interlace = (1 << 7) | ((u8) (var->yres >> 4)); + else + par->interlace = 0; + + if (var->vmode & FB_VMODE_DOUBLE) + par->regs.cr09 |= 1 << 7; + + /* overlay */ + par->ovract = ((var->xres + var->right_margin + var->hsync_len + + var->left_margin - 32) | ((var->xres - 32) << 16)); +} + +void i810fb_fill_var_timings(struct fb_var_screeninfo *var) { } + +/** + * i810_get_watermark - gets watermark + * @var: pointer to fb_var_screeninfo + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Gets the required watermark based on + * pixelclock and RAMBUS frequency. + * + * RETURNS: + * watermark + */ +u32 i810_get_watermark(const struct fb_var_screeninfo *var, + struct i810fb_par *par) +{ + struct wm_info *wmark = NULL; + u32 i, size = 0, pixclock, wm_best = 0, min, diff; + + if (par->mem_freq == 100) { + switch (var->bits_per_pixel) { + case 8: + wmark = i810_wm_8_100; + size = ARRAY_SIZE(i810_wm_8_100); + break; + case 16: + wmark = i810_wm_16_100; + size = ARRAY_SIZE(i810_wm_16_100); + break; + case 24: + case 32: + wmark = i810_wm_24_100; + size = ARRAY_SIZE(i810_wm_24_100); + } + } else { + switch(var->bits_per_pixel) { + case 8: + wmark = i810_wm_8_133; + size = ARRAY_SIZE(i810_wm_8_133); + break; + case 16: + wmark = i810_wm_16_133; + size = ARRAY_SIZE(i810_wm_16_133); + break; + case 24: + case 32: + wmark = i810_wm_24_133; + size = ARRAY_SIZE(i810_wm_24_133); + } + } + + pixclock = 1000000/var->pixclock; + min = ~0; + for (i = 0; i < size; i++) { + if (pixclock <= wmark[i].freq) + diff = wmark[i].freq - pixclock; + else + diff = pixclock - wmark[i].freq; + if (diff < min) { + wm_best = wmark[i].wm; + min = diff; + } + } + return wm_best; +} + diff --git a/drivers/video/fbdev/i810/i810_main.c b/drivers/video/fbdev/i810/i810_main.c new file mode 100644 index 000000000..10b914a24 --- /dev/null +++ b/drivers/video/fbdev/i810/i810_main.c @@ -0,0 +1,2234 @@ + /*-*- linux-c -*- + * linux/drivers/video/i810_main.c -- Intel 810 frame buffer device + * + * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * Contributors: + * Michael Vogt <mvogt@acm.org> - added support for Intel 815 chipsets + * and enabling the power-on state of + * external VGA connectors for + * secondary displays + * + * Fredrik Andersson <krueger@shell.linux.se> - alpha testing of + * the VESA GTF + * + * Brad Corrion <bcorrion@web-co.com> - alpha testing of customized + * timings support + * + * The code framework is a modification of vfb.c by Geert Uytterhoeven. + * DotClock and PLL calculations are partly based on i810_driver.c + * in xfree86 v4.0.3 by Precision Insight. + * Watermark calculation and tables are based on i810_wmark.c + * in xfre86 v4.0.3 by Precision Insight. Slight modifications + * only to allow for integer operations instead of floating point. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/aperture.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/resource.h> +#include <linux/unistd.h> +#include <linux/console.h> +#include <linux/io.h> + +#include <asm/io.h> +#include <asm/div64.h> +#include <asm/page.h> + +#include "i810_regs.h" +#include "i810.h" +#include "i810_main.h" + +/* + * voffset - framebuffer offset in MiB from aperture start address. In order for + * the driver to work with X, we must try to use memory holes left untouched by X. The + * following table lists where X's different surfaces start at. + * + * --------------------------------------------- + * : : 64 MiB : 32 MiB : + * ---------------------------------------------- + * : FrontBuffer : 0 : 0 : + * : DepthBuffer : 48 : 16 : + * : BackBuffer : 56 : 24 : + * ---------------------------------------------- + * + * So for chipsets with 64 MiB Aperture sizes, 32 MiB for v_offset is okay, allowing up to + * 15 + 1 MiB of Framebuffer memory. For 32 MiB Aperture sizes, a v_offset of 8 MiB should + * work, allowing 7 + 1 MiB of Framebuffer memory. + * Note, the size of the hole may change depending on how much memory you allocate to X, + * and how the memory is split up between these surfaces. + * + * Note: Anytime the DepthBuffer or FrontBuffer is overlapped, X would still run but with + * DRI disabled. But if the Frontbuffer is overlapped, X will fail to load. + * + * Experiment with v_offset to find out which works best for you. + */ +static u32 v_offset_default; /* For 32 MiB Aper size, 8 should be the default */ +static u32 voffset; + +static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor); +static int i810fb_init_pci(struct pci_dev *dev, + const struct pci_device_id *entry); +static void i810fb_remove_pci(struct pci_dev *dev); +static int i810fb_resume(struct pci_dev *dev); +static int i810fb_suspend(struct pci_dev *dev, pm_message_t state); + +/* Chipset Specific Functions */ +static int i810fb_set_par (struct fb_info *info); +static int i810fb_getcolreg (u8 regno, u8 *red, u8 *green, u8 *blue, + u8 *transp, struct fb_info *info); +static int i810fb_setcolreg (unsigned regno, unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *info); +static int i810fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); +static int i810fb_blank (int blank_mode, struct fb_info *info); + +/* Initialization */ +static void i810fb_release_resource (struct fb_info *info, struct i810fb_par *par); + +/* PCI */ +static const char * const i810_pci_list[] = { + "Intel(R) 810 Framebuffer Device" , + "Intel(R) 810-DC100 Framebuffer Device" , + "Intel(R) 810E Framebuffer Device" , + "Intel(R) 815 (Internal Graphics 100Mhz FSB) Framebuffer Device" , + "Intel(R) 815 (Internal Graphics only) Framebuffer Device" , + "Intel(R) 815 (Internal Graphics with AGP) Framebuffer Device" +}; + +static const struct pci_device_id i810fb_pci_tbl[] = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810E_IG, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, + /* mvo: added i815 PCI-ID */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_NOAGP, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, + { 0 }, +}; + +static struct pci_driver i810fb_driver = { + .name = "i810fb", + .id_table = i810fb_pci_tbl, + .probe = i810fb_init_pci, + .remove = i810fb_remove_pci, + .suspend = i810fb_suspend, + .resume = i810fb_resume, +}; + +static char *mode_option = NULL; +static int vram = 4; +static int bpp = 8; +static bool mtrr; +static bool accel; +static int hsync1; +static int hsync2; +static int vsync1; +static int vsync2; +static int xres; +static int yres; +static int vyres; +static bool sync; +static bool extvga; +static bool dcolor; +static bool ddc3; + +/*------------------------------------------------------------*/ + +/************************************************************** + * Hardware Low Level Routines * + **************************************************************/ + +/** + * i810_screen_off - turns off/on display + * @mmio: address of register space + * @mode: on or off + * + * DESCRIPTION: + * Blanks/unblanks the display + */ +static void i810_screen_off(u8 __iomem *mmio, u8 mode) +{ + u32 count = WAIT_COUNT; + u8 val; + + i810_writeb(SR_INDEX, mmio, SR01); + val = i810_readb(SR_DATA, mmio); + val = (mode == OFF) ? val | SCR_OFF : + val & ~SCR_OFF; + + while((i810_readw(DISP_SL, mmio) & 0xFFF) && count--); + i810_writeb(SR_INDEX, mmio, SR01); + i810_writeb(SR_DATA, mmio, val); +} + +/** + * i810_dram_off - turns off/on dram refresh + * @mmio: address of register space + * @mode: on or off + * + * DESCRIPTION: + * Turns off DRAM refresh. Must be off for only 2 vsyncs + * before data becomes corrupt + */ +static void i810_dram_off(u8 __iomem *mmio, u8 mode) +{ + u8 val; + + val = i810_readb(DRAMCH, mmio); + val &= DRAM_OFF; + val = (mode == OFF) ? val : val | DRAM_ON; + i810_writeb(DRAMCH, mmio, val); +} + +/** + * i810_protect_regs - allows rw/ro mode of certain VGA registers + * @mmio: address of register space + * @mode: protect/unprotect + * + * DESCRIPTION: + * The IBM VGA standard allows protection of certain VGA registers. + * This will protect or unprotect them. + */ +static void i810_protect_regs(u8 __iomem *mmio, int mode) +{ + u8 reg; + + i810_writeb(CR_INDEX_CGA, mmio, CR11); + reg = i810_readb(CR_DATA_CGA, mmio); + reg = (mode == OFF) ? reg & ~0x80 : + reg | 0x80; + + i810_writeb(CR_INDEX_CGA, mmio, CR11); + i810_writeb(CR_DATA_CGA, mmio, reg); +} + +/** + * i810_load_pll - loads values for the hardware PLL clock + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Loads the P, M, and N registers. + */ +static void i810_load_pll(struct i810fb_par *par) +{ + u32 tmp1, tmp2; + u8 __iomem *mmio = par->mmio_start_virtual; + + tmp1 = par->regs.M | par->regs.N << 16; + tmp2 = i810_readl(DCLK_2D, mmio); + tmp2 &= ~MN_MASK; + i810_writel(DCLK_2D, mmio, tmp1 | tmp2); + + tmp1 = par->regs.P; + tmp2 = i810_readl(DCLK_0DS, mmio); + tmp2 &= ~(P_OR << 16); + i810_writel(DCLK_0DS, mmio, (tmp1 << 16) | tmp2); + + i810_writeb(MSR_WRITE, mmio, par->regs.msr | 0xC8 | 1); + +} + +/** + * i810_load_vga - load standard VGA registers + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Load values to VGA registers + */ +static void i810_load_vga(struct i810fb_par *par) +{ + u8 __iomem *mmio = par->mmio_start_virtual; + + /* interlace */ + i810_writeb(CR_INDEX_CGA, mmio, CR70); + i810_writeb(CR_DATA_CGA, mmio, par->interlace); + + i810_writeb(CR_INDEX_CGA, mmio, CR00); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr00); + i810_writeb(CR_INDEX_CGA, mmio, CR01); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr01); + i810_writeb(CR_INDEX_CGA, mmio, CR02); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr02); + i810_writeb(CR_INDEX_CGA, mmio, CR03); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr03); + i810_writeb(CR_INDEX_CGA, mmio, CR04); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr04); + i810_writeb(CR_INDEX_CGA, mmio, CR05); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr05); + i810_writeb(CR_INDEX_CGA, mmio, CR06); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr06); + i810_writeb(CR_INDEX_CGA, mmio, CR09); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr09); + i810_writeb(CR_INDEX_CGA, mmio, CR10); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr10); + i810_writeb(CR_INDEX_CGA, mmio, CR11); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr11); + i810_writeb(CR_INDEX_CGA, mmio, CR12); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr12); + i810_writeb(CR_INDEX_CGA, mmio, CR15); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr15); + i810_writeb(CR_INDEX_CGA, mmio, CR16); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr16); +} + +/** + * i810_load_vgax - load extended VGA registers + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Load values to extended VGA registers + */ +static void i810_load_vgax(struct i810fb_par *par) +{ + u8 __iomem *mmio = par->mmio_start_virtual; + + i810_writeb(CR_INDEX_CGA, mmio, CR30); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr30); + i810_writeb(CR_INDEX_CGA, mmio, CR31); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr31); + i810_writeb(CR_INDEX_CGA, mmio, CR32); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr32); + i810_writeb(CR_INDEX_CGA, mmio, CR33); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr33); + i810_writeb(CR_INDEX_CGA, mmio, CR35); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr35); + i810_writeb(CR_INDEX_CGA, mmio, CR39); + i810_writeb(CR_DATA_CGA, mmio, par->regs.cr39); +} + +/** + * i810_load_2d - load grahics registers + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Load values to graphics registers + */ +static void i810_load_2d(struct i810fb_par *par) +{ + u32 tmp; + u8 tmp8; + u8 __iomem *mmio = par->mmio_start_virtual; + + i810_writel(FW_BLC, mmio, par->watermark); + tmp = i810_readl(PIXCONF, mmio); + tmp |= 1 | 1 << 20; + i810_writel(PIXCONF, mmio, tmp); + + i810_writel(OVRACT, mmio, par->ovract); + + i810_writeb(GR_INDEX, mmio, GR10); + tmp8 = i810_readb(GR_DATA, mmio); + tmp8 |= 2; + i810_writeb(GR_INDEX, mmio, GR10); + i810_writeb(GR_DATA, mmio, tmp8); +} + +/** + * i810_hires - enables high resolution mode + * @mmio: address of register space + */ +static void i810_hires(u8 __iomem *mmio) +{ + u8 val; + + i810_writeb(CR_INDEX_CGA, mmio, CR80); + val = i810_readb(CR_DATA_CGA, mmio); + i810_writeb(CR_INDEX_CGA, mmio, CR80); + i810_writeb(CR_DATA_CGA, mmio, val | 1); + /* Stop LCD displays from flickering */ + i810_writel(MEM_MODE, mmio, i810_readl(MEM_MODE, mmio) | 4); +} + +/** + * i810_load_pitch - loads the characters per line of the display + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Loads the characters per line + */ +static void i810_load_pitch(struct i810fb_par *par) +{ + u32 tmp, pitch; + u8 val; + u8 __iomem *mmio = par->mmio_start_virtual; + + pitch = par->pitch >> 3; + i810_writeb(SR_INDEX, mmio, SR01); + val = i810_readb(SR_DATA, mmio); + val &= 0xE0; + val |= 1 | 1 << 2; + i810_writeb(SR_INDEX, mmio, SR01); + i810_writeb(SR_DATA, mmio, val); + + tmp = pitch & 0xFF; + i810_writeb(CR_INDEX_CGA, mmio, CR13); + i810_writeb(CR_DATA_CGA, mmio, (u8) tmp); + + tmp = pitch >> 8; + i810_writeb(CR_INDEX_CGA, mmio, CR41); + val = i810_readb(CR_DATA_CGA, mmio) & ~0x0F; + i810_writeb(CR_INDEX_CGA, mmio, CR41); + i810_writeb(CR_DATA_CGA, mmio, (u8) tmp | val); +} + +/** + * i810_load_color - loads the color depth of the display + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Loads the color depth of the display and the graphics engine + */ +static void i810_load_color(struct i810fb_par *par) +{ + u8 __iomem *mmio = par->mmio_start_virtual; + u32 reg1; + u16 reg2; + + reg1 = i810_readl(PIXCONF, mmio) & ~(0xF0000 | 1 << 27); + reg2 = i810_readw(BLTCNTL, mmio) & ~0x30; + + reg1 |= 0x8000 | par->pixconf; + reg2 |= par->bltcntl; + i810_writel(PIXCONF, mmio, reg1); + i810_writew(BLTCNTL, mmio, reg2); +} + +/** + * i810_load_regs - loads all registers for the mode + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Loads registers + */ +static void i810_load_regs(struct i810fb_par *par) +{ + u8 __iomem *mmio = par->mmio_start_virtual; + + i810_screen_off(mmio, OFF); + i810_protect_regs(mmio, OFF); + i810_dram_off(mmio, OFF); + i810_load_pll(par); + i810_load_vga(par); + i810_load_vgax(par); + i810_dram_off(mmio, ON); + i810_load_2d(par); + i810_hires(mmio); + i810_screen_off(mmio, ON); + i810_protect_regs(mmio, ON); + i810_load_color(par); + i810_load_pitch(par); +} + +static void i810_write_dac(u8 regno, u8 red, u8 green, u8 blue, + u8 __iomem *mmio) +{ + i810_writeb(CLUT_INDEX_WRITE, mmio, regno); + i810_writeb(CLUT_DATA, mmio, red); + i810_writeb(CLUT_DATA, mmio, green); + i810_writeb(CLUT_DATA, mmio, blue); +} + +static void i810_read_dac(u8 regno, u8 *red, u8 *green, u8 *blue, + u8 __iomem *mmio) +{ + i810_writeb(CLUT_INDEX_READ, mmio, regno); + *red = i810_readb(CLUT_DATA, mmio); + *green = i810_readb(CLUT_DATA, mmio); + *blue = i810_readb(CLUT_DATA, mmio); +} + +/************************************************************ + * VGA State Restore * + ************************************************************/ +static void i810_restore_pll(struct i810fb_par *par) +{ + u32 tmp1, tmp2; + u8 __iomem *mmio = par->mmio_start_virtual; + + tmp1 = par->hw_state.dclk_2d; + tmp2 = i810_readl(DCLK_2D, mmio); + tmp1 &= ~MN_MASK; + tmp2 &= MN_MASK; + i810_writel(DCLK_2D, mmio, tmp1 | tmp2); + + tmp1 = par->hw_state.dclk_1d; + tmp2 = i810_readl(DCLK_1D, mmio); + tmp1 &= ~MN_MASK; + tmp2 &= MN_MASK; + i810_writel(DCLK_1D, mmio, tmp1 | tmp2); + + i810_writel(DCLK_0DS, mmio, par->hw_state.dclk_0ds); +} + +static void i810_restore_dac(struct i810fb_par *par) +{ + u32 tmp1, tmp2; + u8 __iomem *mmio = par->mmio_start_virtual; + + tmp1 = par->hw_state.pixconf; + tmp2 = i810_readl(PIXCONF, mmio); + tmp1 &= DAC_BIT; + tmp2 &= ~DAC_BIT; + i810_writel(PIXCONF, mmio, tmp1 | tmp2); +} + +static void i810_restore_vgax(struct i810fb_par *par) +{ + u8 i, j; + u8 __iomem *mmio = par->mmio_start_virtual; + + for (i = 0; i < 4; i++) { + i810_writeb(CR_INDEX_CGA, mmio, CR30+i); + i810_writeb(CR_DATA_CGA, mmio, *(&(par->hw_state.cr30) + i)); + } + i810_writeb(CR_INDEX_CGA, mmio, CR35); + i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr35); + i810_writeb(CR_INDEX_CGA, mmio, CR39); + i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr39); + i810_writeb(CR_INDEX_CGA, mmio, CR41); + i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr39); + + /*restore interlace*/ + i810_writeb(CR_INDEX_CGA, mmio, CR70); + i = par->hw_state.cr70; + i &= INTERLACE_BIT; + j = i810_readb(CR_DATA_CGA, mmio); + i810_writeb(CR_INDEX_CGA, mmio, CR70); + i810_writeb(CR_DATA_CGA, mmio, j | i); + + i810_writeb(CR_INDEX_CGA, mmio, CR80); + i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr80); + i810_writeb(MSR_WRITE, mmio, par->hw_state.msr); + i810_writeb(SR_INDEX, mmio, SR01); + i = (par->hw_state.sr01) & ~0xE0 ; + j = i810_readb(SR_DATA, mmio) & 0xE0; + i810_writeb(SR_INDEX, mmio, SR01); + i810_writeb(SR_DATA, mmio, i | j); +} + +static void i810_restore_vga(struct i810fb_par *par) +{ + u8 i; + u8 __iomem *mmio = par->mmio_start_virtual; + + for (i = 0; i < 10; i++) { + i810_writeb(CR_INDEX_CGA, mmio, CR00 + i); + i810_writeb(CR_DATA_CGA, mmio, *((&par->hw_state.cr00) + i)); + } + for (i = 0; i < 8; i++) { + i810_writeb(CR_INDEX_CGA, mmio, CR10 + i); + i810_writeb(CR_DATA_CGA, mmio, *((&par->hw_state.cr10) + i)); + } +} + +static void i810_restore_addr_map(struct i810fb_par *par) +{ + u8 tmp; + u8 __iomem *mmio = par->mmio_start_virtual; + + i810_writeb(GR_INDEX, mmio, GR10); + tmp = i810_readb(GR_DATA, mmio); + tmp &= ADDR_MAP_MASK; + tmp |= par->hw_state.gr10; + i810_writeb(GR_INDEX, mmio, GR10); + i810_writeb(GR_DATA, mmio, tmp); +} + +static void i810_restore_2d(struct i810fb_par *par) +{ + u32 tmp_long; + u16 tmp_word; + u8 __iomem *mmio = par->mmio_start_virtual; + + tmp_word = i810_readw(BLTCNTL, mmio); + tmp_word &= ~(3 << 4); + tmp_word |= par->hw_state.bltcntl; + i810_writew(BLTCNTL, mmio, tmp_word); + + i810_dram_off(mmio, OFF); + i810_writel(PIXCONF, mmio, par->hw_state.pixconf); + i810_dram_off(mmio, ON); + + tmp_word = i810_readw(HWSTAM, mmio); + tmp_word &= 3 << 13; + tmp_word |= par->hw_state.hwstam; + i810_writew(HWSTAM, mmio, tmp_word); + + tmp_long = i810_readl(FW_BLC, mmio); + tmp_long &= FW_BLC_MASK; + tmp_long |= par->hw_state.fw_blc; + i810_writel(FW_BLC, mmio, tmp_long); + + i810_writel(HWS_PGA, mmio, par->hw_state.hws_pga); + i810_writew(IER, mmio, par->hw_state.ier); + i810_writew(IMR, mmio, par->hw_state.imr); + i810_writel(DPLYSTAS, mmio, par->hw_state.dplystas); +} + +static void i810_restore_vga_state(struct i810fb_par *par) +{ + u8 __iomem *mmio = par->mmio_start_virtual; + + i810_screen_off(mmio, OFF); + i810_protect_regs(mmio, OFF); + i810_dram_off(mmio, OFF); + i810_restore_pll(par); + i810_restore_dac(par); + i810_restore_vga(par); + i810_restore_vgax(par); + i810_restore_addr_map(par); + i810_dram_off(mmio, ON); + i810_restore_2d(par); + i810_screen_off(mmio, ON); + i810_protect_regs(mmio, ON); +} + +/*********************************************************************** + * VGA State Save * + ***********************************************************************/ + +static void i810_save_vgax(struct i810fb_par *par) +{ + u8 i; + u8 __iomem *mmio = par->mmio_start_virtual; + + for (i = 0; i < 4; i++) { + i810_writeb(CR_INDEX_CGA, mmio, CR30 + i); + *(&(par->hw_state.cr30) + i) = i810_readb(CR_DATA_CGA, mmio); + } + i810_writeb(CR_INDEX_CGA, mmio, CR35); + par->hw_state.cr35 = i810_readb(CR_DATA_CGA, mmio); + i810_writeb(CR_INDEX_CGA, mmio, CR39); + par->hw_state.cr39 = i810_readb(CR_DATA_CGA, mmio); + i810_writeb(CR_INDEX_CGA, mmio, CR41); + par->hw_state.cr41 = i810_readb(CR_DATA_CGA, mmio); + i810_writeb(CR_INDEX_CGA, mmio, CR70); + par->hw_state.cr70 = i810_readb(CR_DATA_CGA, mmio); + par->hw_state.msr = i810_readb(MSR_READ, mmio); + i810_writeb(CR_INDEX_CGA, mmio, CR80); + par->hw_state.cr80 = i810_readb(CR_DATA_CGA, mmio); + i810_writeb(SR_INDEX, mmio, SR01); + par->hw_state.sr01 = i810_readb(SR_DATA, mmio); +} + +static void i810_save_vga(struct i810fb_par *par) +{ + u8 i; + u8 __iomem *mmio = par->mmio_start_virtual; + + for (i = 0; i < 10; i++) { + i810_writeb(CR_INDEX_CGA, mmio, CR00 + i); + *((&par->hw_state.cr00) + i) = i810_readb(CR_DATA_CGA, mmio); + } + for (i = 0; i < 8; i++) { + i810_writeb(CR_INDEX_CGA, mmio, CR10 + i); + *((&par->hw_state.cr10) + i) = i810_readb(CR_DATA_CGA, mmio); + } +} + +static void i810_save_2d(struct i810fb_par *par) +{ + u8 __iomem *mmio = par->mmio_start_virtual; + + par->hw_state.dclk_2d = i810_readl(DCLK_2D, mmio); + par->hw_state.dclk_1d = i810_readl(DCLK_1D, mmio); + par->hw_state.dclk_0ds = i810_readl(DCLK_0DS, mmio); + par->hw_state.pixconf = i810_readl(PIXCONF, mmio); + par->hw_state.fw_blc = i810_readl(FW_BLC, mmio); + par->hw_state.bltcntl = i810_readw(BLTCNTL, mmio); + par->hw_state.hwstam = i810_readw(HWSTAM, mmio); + par->hw_state.hws_pga = i810_readl(HWS_PGA, mmio); + par->hw_state.ier = i810_readw(IER, mmio); + par->hw_state.imr = i810_readw(IMR, mmio); + par->hw_state.dplystas = i810_readl(DPLYSTAS, mmio); +} + +static void i810_save_vga_state(struct i810fb_par *par) +{ + i810_save_vga(par); + i810_save_vgax(par); + i810_save_2d(par); +} + +/************************************************************ + * Helpers * + ************************************************************/ +/** + * get_line_length - calculates buffer pitch in bytes + * @par: pointer to i810fb_par structure + * @xres_virtual: virtual resolution of the frame + * @bpp: bits per pixel + * + * DESCRIPTION: + * Calculates buffer pitch in bytes. + */ +static u32 get_line_length(struct i810fb_par *par, int xres_virtual, int bpp) +{ + u32 length; + + length = xres_virtual*bpp; + length = (length+31)&-32; + length >>= 3; + return length; +} + +/** + * i810_calc_dclk - calculates the P, M, and N values of a pixelclock value + * @freq: target pixelclock in picoseconds + * @m: where to write M register + * @n: where to write N register + * @p: where to write P register + * + * DESCRIPTION: + * Based on the formula Freq_actual = (4*M*Freq_ref)/(N^P) + * Repeatedly computes the Freq until the actual Freq is equal to + * the target Freq or until the loop count is zero. In the latter + * case, the actual frequency nearest the target will be used. + */ +static void i810_calc_dclk(u32 freq, u32 *m, u32 *n, u32 *p) +{ + u32 m_reg, n_reg, p_divisor, n_target_max; + u32 m_target, n_target, p_target, n_best, m_best, mod; + u32 f_out, target_freq, diff = 0, mod_min, diff_min; + + diff_min = mod_min = 0xFFFFFFFF; + n_best = m_best = m_target = f_out = 0; + + target_freq = freq; + n_target_max = 30; + + /* + * find P such that target freq is 16x reference freq (Hz). + */ + p_divisor = 1; + p_target = 0; + while(!((1000000 * p_divisor)/(16 * 24 * target_freq)) && + p_divisor <= 32) { + p_divisor <<= 1; + p_target++; + } + + n_reg = m_reg = n_target = 3; + while (diff_min && mod_min && (n_target < n_target_max)) { + f_out = (p_divisor * n_reg * 1000000)/(4 * 24 * m_reg); + mod = (p_divisor * n_reg * 1000000) % (4 * 24 * m_reg); + m_target = m_reg; + n_target = n_reg; + if (f_out <= target_freq) { + n_reg++; + diff = target_freq - f_out; + } else { + m_reg++; + diff = f_out - target_freq; + } + + if (diff_min > diff) { + diff_min = diff; + n_best = n_target; + m_best = m_target; + } + + if (!diff && mod_min > mod) { + mod_min = mod; + n_best = n_target; + m_best = m_target; + } + } + if (m) *m = (m_best - 2) & 0x3FF; + if (n) *n = (n_best - 2) & 0x3FF; + if (p) *p = (p_target << 4); +} + +/************************************************************* + * Hardware Cursor Routines * + *************************************************************/ + +/** + * i810_enable_cursor - show or hide the hardware cursor + * @mmio: address of register space + * @mode: show (1) or hide (0) + * + * Description: + * Shows or hides the hardware cursor + */ +static void i810_enable_cursor(u8 __iomem *mmio, int mode) +{ + u32 temp; + + temp = i810_readl(PIXCONF, mmio); + temp = (mode == ON) ? temp | CURSOR_ENABLE_MASK : + temp & ~CURSOR_ENABLE_MASK; + + i810_writel(PIXCONF, mmio, temp); +} + +static void i810_reset_cursor_image(struct i810fb_par *par) +{ + u8 __iomem *addr = par->cursor_heap.virtual; + int i, j; + + for (i = 64; i--; ) { + for (j = 0; j < 8; j++) { + i810_writeb(j, addr, 0xff); + i810_writeb(j+8, addr, 0x00); + } + addr +=16; + } +} + +static void i810_load_cursor_image(int width, int height, u8 *data, + struct i810fb_par *par) +{ + u8 __iomem *addr = par->cursor_heap.virtual; + int i, j, w = width/8; + int mod = width % 8, t_mask, d_mask; + + t_mask = 0xff >> mod; + d_mask = ~(0xff >> mod); + for (i = height; i--; ) { + for (j = 0; j < w; j++) { + i810_writeb(j+0, addr, 0x00); + i810_writeb(j+8, addr, *data++); + } + if (mod) { + i810_writeb(j+0, addr, t_mask); + i810_writeb(j+8, addr, *data++ & d_mask); + } + addr += 16; + } +} + +static void i810_load_cursor_colors(int fg, int bg, struct fb_info *info) +{ + struct i810fb_par *par = info->par; + u8 __iomem *mmio = par->mmio_start_virtual; + u8 red, green, blue, trans, temp; + + i810fb_getcolreg(bg, &red, &green, &blue, &trans, info); + + temp = i810_readb(PIXCONF1, mmio); + i810_writeb(PIXCONF1, mmio, temp | EXTENDED_PALETTE); + + i810_write_dac(4, red, green, blue, mmio); + + i810_writeb(PIXCONF1, mmio, temp); + + i810fb_getcolreg(fg, &red, &green, &blue, &trans, info); + temp = i810_readb(PIXCONF1, mmio); + i810_writeb(PIXCONF1, mmio, temp | EXTENDED_PALETTE); + + i810_write_dac(5, red, green, blue, mmio); + + i810_writeb(PIXCONF1, mmio, temp); +} + +/** + * i810_init_cursor - initializes the cursor + * @par: pointer to i810fb_par structure + * + * DESCRIPTION: + * Initializes the cursor registers + */ +static void i810_init_cursor(struct i810fb_par *par) +{ + u8 __iomem *mmio = par->mmio_start_virtual; + + i810_enable_cursor(mmio, OFF); + i810_writel(CURBASE, mmio, par->cursor_heap.physical); + i810_writew(CURCNTR, mmio, COORD_ACTIVE | CURSOR_MODE_64_XOR); +} + +/********************************************************************* + * Framebuffer hook helpers * + *********************************************************************/ +/** + * i810_round_off - Round off values to capability of hardware + * @var: pointer to fb_var_screeninfo structure + * + * DESCRIPTION: + * @var contains user-defined information for the mode to be set. + * This will try modify those values to ones nearest the + * capability of the hardware + */ +static void i810_round_off(struct fb_var_screeninfo *var) +{ + u32 xres, yres, vxres, vyres; + + /* + * Presently supports only these configurations + */ + + xres = var->xres; + yres = var->yres; + vxres = var->xres_virtual; + vyres = var->yres_virtual; + + var->bits_per_pixel += 7; + var->bits_per_pixel &= ~7; + + if (var->bits_per_pixel < 8) + var->bits_per_pixel = 8; + if (var->bits_per_pixel > 32) + var->bits_per_pixel = 32; + + round_off_xres(&xres); + if (xres < 40) + xres = 40; + if (xres > 2048) + xres = 2048; + xres = (xres + 7) & ~7; + + if (vxres < xres) + vxres = xres; + + round_off_yres(&xres, &yres); + if (yres < 1) + yres = 1; + if (yres >= 2048) + yres = 2048; + + if (vyres < yres) + vyres = yres; + + if (var->bits_per_pixel == 32) + var->accel_flags = 0; + + /* round of horizontal timings to nearest 8 pixels */ + var->left_margin = (var->left_margin + 4) & ~7; + var->right_margin = (var->right_margin + 4) & ~7; + var->hsync_len = (var->hsync_len + 4) & ~7; + + if (var->vmode & FB_VMODE_INTERLACED) { + if (!((yres + var->upper_margin + var->vsync_len + + var->lower_margin) & 1)) + var->upper_margin++; + } + + var->xres = xres; + var->yres = yres; + var->xres_virtual = vxres; + var->yres_virtual = vyres; +} + +/** + * set_color_bitfields - sets rgba fields + * @var: pointer to fb_var_screeninfo + * + * DESCRIPTION: + * The length, offset and ordering for each color field + * (red, green, blue) will be set as specified + * by the hardware + */ +static void set_color_bitfields(struct fb_var_screeninfo *var) +{ + switch (var->bits_per_pixel) { + case 8: + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case 16: + var->green.length = (var->green.length == 5) ? 5 : 6; + var->red.length = 5; + var->blue.length = 5; + var->transp.length = 6 - var->green.length; + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 5 + var->green.length; + var->transp.offset = (5 + var->red.offset) & 15; + break; + case 24: /* RGB 888 */ + case 32: /* RGBA 8888 */ + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.length = var->bits_per_pixel - 24; + var->transp.offset = (var->transp.length) ? 24 : 0; + break; + } + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; +} + +/** + * i810_check_params - check if contents in var are valid + * @var: pointer to fb_var_screeninfo + * @info: pointer to fb_info + * + * DESCRIPTION: + * This will check if the framebuffer size is sufficient + * for the current mode and if the user's monitor has the + * required specifications to display the current mode. + */ +static int i810_check_params(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct i810fb_par *par = info->par; + int line_length, vidmem, mode_valid = 0, retval = 0; + u32 vyres = var->yres_virtual, vxres = var->xres_virtual; + + /* + * Memory limit + */ + line_length = get_line_length(par, vxres, var->bits_per_pixel); + vidmem = line_length*vyres; + + if (vidmem > par->fb.size) { + vyres = par->fb.size/line_length; + if (vyres < var->yres) { + vyres = info->var.yres; + vxres = par->fb.size/vyres; + vxres /= var->bits_per_pixel >> 3; + line_length = get_line_length(par, vxres, + var->bits_per_pixel); + vidmem = line_length * info->var.yres; + if (vxres < var->xres) { + dev_info(&par->dev->dev, "required video memory, " + "%d bytes, for %dx%d-%d (virtual) " + "is out of range\n", + vidmem, vxres, vyres, + var->bits_per_pixel); + return -ENOMEM; + } + } + } + + var->xres_virtual = vxres; + var->yres_virtual = vyres; + + /* + * Monitor limit + */ + switch (var->bits_per_pixel) { + case 8: + info->monspecs.dclkmax = 234000000; + break; + case 16: + info->monspecs.dclkmax = 229000000; + break; + case 24: + case 32: + info->monspecs.dclkmax = 204000000; + break; + } + + info->monspecs.dclkmin = 15000000; + + if (!fb_validate_mode(var, info)) + mode_valid = 1; + +#ifdef CONFIG_FB_I810_I2C + if (!mode_valid && info->monspecs.gtf && + !fb_get_mode(FB_MAXTIMINGS, 0, var, info)) + mode_valid = 1; + + if (!mode_valid && info->monspecs.modedb_len) { + const struct fb_videomode *mode; + + mode = fb_find_best_mode(var, &info->modelist); + if (mode) { + fb_videomode_to_var(var, mode); + mode_valid = 1; + } + } +#endif + if (!mode_valid && info->monspecs.modedb_len == 0) { + if (fb_get_mode(FB_MAXTIMINGS, 0, var, info)) { + int default_sync = (info->monspecs.hfmin-HFMIN) + |(info->monspecs.hfmax-HFMAX) + |(info->monspecs.vfmin-VFMIN) + |(info->monspecs.vfmax-VFMAX); + dev_err(&par->dev->dev, "invalid video mode%s\n", + default_sync ? "" : ". Specifying " + "vsyncN/hsyncN parameters may help"); + retval = -EINVAL; + } + } + + return retval; +} + +/** + * encode_fix - fill up fb_fix_screeninfo structure + * @fix: pointer to fb_fix_screeninfo + * @info: pointer to fb_info + * + * DESCRIPTION: + * This will set up parameters that are unmodifiable by the user. + */ +static int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info) +{ + struct i810fb_par *par = info->par; + + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + + strcpy(fix->id, "I810"); + mutex_lock(&info->mm_lock); + fix->smem_start = par->fb.physical; + fix->smem_len = par->fb.size; + mutex_unlock(&info->mm_lock); + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + fix->xpanstep = 8; + fix->ypanstep = 1; + + switch (info->var.bits_per_pixel) { + case 8: + fix->visual = FB_VISUAL_PSEUDOCOLOR; + break; + case 16: + case 24: + case 32: + if (info->var.nonstd) + fix->visual = FB_VISUAL_DIRECTCOLOR; + else + fix->visual = FB_VISUAL_TRUECOLOR; + break; + default: + return -EINVAL; + } + fix->ywrapstep = 0; + fix->line_length = par->pitch; + fix->mmio_start = par->mmio_start_phys; + fix->mmio_len = MMIO_SIZE; + fix->accel = FB_ACCEL_I810; + + return 0; +} + +/** + * decode_var - modify par according to contents of var + * @var: pointer to fb_var_screeninfo + * @par: pointer to i810fb_par + * + * DESCRIPTION: + * Based on the contents of @var, @par will be dynamically filled up. + * @par contains all information necessary to modify the hardware. +*/ +static void decode_var(const struct fb_var_screeninfo *var, + struct i810fb_par *par) +{ + u32 xres, yres, vxres, vyres; + + xres = var->xres; + yres = var->yres; + vxres = var->xres_virtual; + vyres = var->yres_virtual; + + switch (var->bits_per_pixel) { + case 8: + par->pixconf = PIXCONF8; + par->bltcntl = 0; + par->depth = 1; + par->blit_bpp = BPP8; + break; + case 16: + if (var->green.length == 5) + par->pixconf = PIXCONF15; + else + par->pixconf = PIXCONF16; + par->bltcntl = 16; + par->depth = 2; + par->blit_bpp = BPP16; + break; + case 24: + par->pixconf = PIXCONF24; + par->bltcntl = 32; + par->depth = 3; + par->blit_bpp = BPP24; + break; + case 32: + par->pixconf = PIXCONF32; + par->bltcntl = 0; + par->depth = 4; + par->blit_bpp = 3 << 24; + break; + } + if (var->nonstd && var->bits_per_pixel != 8) + par->pixconf |= 1 << 27; + + i810_calc_dclk(var->pixclock, &par->regs.M, + &par->regs.N, &par->regs.P); + i810fb_encode_registers(var, par, xres, yres); + + par->watermark = i810_get_watermark(var, par); + par->pitch = get_line_length(par, vxres, var->bits_per_pixel); +} + +/** + * i810fb_getcolreg - gets red, green and blue values of the hardware DAC + * @regno: DAC index + * @red: red + * @green: green + * @blue: blue + * @transp: transparency (alpha) + * @info: pointer to fb_info + * + * DESCRIPTION: + * Gets the red, green and blue values of the hardware DAC as pointed by @regno + * and writes them to @red, @green and @blue respectively + */ +static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue, + u8 *transp, struct fb_info *info) +{ + struct i810fb_par *par = info->par; + u8 __iomem *mmio = par->mmio_start_virtual; + u8 temp; + + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + if ((info->var.green.length == 5 && regno > 31) || + (info->var.green.length == 6 && regno > 63)) + return 1; + } + + temp = i810_readb(PIXCONF1, mmio); + i810_writeb(PIXCONF1, mmio, temp & ~EXTENDED_PALETTE); + + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && + info->var.green.length == 5) + i810_read_dac(regno * 8, red, green, blue, mmio); + + else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && + info->var.green.length == 6) { + u8 tmp; + + i810_read_dac(regno * 8, red, &tmp, blue, mmio); + i810_read_dac(regno * 4, &tmp, green, &tmp, mmio); + } + else + i810_read_dac(regno, red, green, blue, mmio); + + *transp = 0; + i810_writeb(PIXCONF1, mmio, temp); + + return 0; +} + +/****************************************************************** + * Framebuffer device-specific hooks * + ******************************************************************/ + +static int i810fb_open(struct fb_info *info, int user) +{ + struct i810fb_par *par = info->par; + + mutex_lock(&par->open_lock); + if (par->use_count == 0) { + memset(&par->state, 0, sizeof(struct vgastate)); + par->state.flags = VGA_SAVE_CMAP; + par->state.vgabase = par->mmio_start_virtual; + save_vga(&par->state); + + i810_save_vga_state(par); + } + + par->use_count++; + mutex_unlock(&par->open_lock); + + return 0; +} + +static int i810fb_release(struct fb_info *info, int user) +{ + struct i810fb_par *par = info->par; + + mutex_lock(&par->open_lock); + if (par->use_count == 0) { + mutex_unlock(&par->open_lock); + return -EINVAL; + } + + if (par->use_count == 1) { + i810_restore_vga_state(par); + restore_vga(&par->state); + } + + par->use_count--; + mutex_unlock(&par->open_lock); + + return 0; +} + + +static int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct i810fb_par *par = info->par; + u8 __iomem *mmio = par->mmio_start_virtual; + u8 temp; + int i; + + if (regno > 255) return 1; + + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + if ((info->var.green.length == 5 && regno > 31) || + (info->var.green.length == 6 && regno > 63)) + return 1; + } + + if (info->var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; + + temp = i810_readb(PIXCONF1, mmio); + i810_writeb(PIXCONF1, mmio, temp & ~EXTENDED_PALETTE); + + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && + info->var.green.length == 5) { + for (i = 0; i < 8; i++) + i810_write_dac((u8) (regno * 8) + i, (u8) red, + (u8) green, (u8) blue, mmio); + } else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR && + info->var.green.length == 6) { + u8 r, g, b; + + if (regno < 32) { + for (i = 0; i < 8; i++) + i810_write_dac((u8) (regno * 8) + i, + (u8) red, (u8) green, + (u8) blue, mmio); + } + i810_read_dac((u8) (regno*4), &r, &g, &b, mmio); + for (i = 0; i < 4; i++) + i810_write_dac((u8) (regno*4) + i, r, (u8) green, + b, mmio); + } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { + i810_write_dac((u8) regno, (u8) red, (u8) green, + (u8) blue, mmio); + } + + i810_writeb(PIXCONF1, mmio, temp); + + if (regno < 16) { + switch (info->var.bits_per_pixel) { + case 16: + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + if (info->var.green.length == 5) + ((u32 *)info->pseudo_palette)[regno] = + (regno << 10) | (regno << 5) | + regno; + else + ((u32 *)info->pseudo_palette)[regno] = + (regno << 11) | (regno << 5) | + regno; + } else { + if (info->var.green.length == 5) { + /* RGB 555 */ + ((u32 *)info->pseudo_palette)[regno] = + ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + } else { + /* RGB 565 */ + ((u32 *)info->pseudo_palette)[regno] = + (red & 0xf800) | + ((green & 0xf800) >> 5) | + ((blue & 0xf800) >> 11); + } + } + break; + case 24: /* RGB 888 */ + case 32: /* RGBA 8888 */ + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) + ((u32 *)info->pseudo_palette)[regno] = + (regno << 16) | (regno << 8) | + regno; + else + ((u32 *)info->pseudo_palette)[regno] = + ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); + break; + } + } + return 0; +} + +static int i810fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct i810fb_par *par = info->par; + u32 total; + + total = var->xoffset * par->depth + + var->yoffset * info->fix.line_length; + i810fb_load_front(total, info); + + return 0; +} + +static int i810fb_blank (int blank_mode, struct fb_info *info) +{ + struct i810fb_par *par = info->par; + u8 __iomem *mmio = par->mmio_start_virtual; + int mode = 0, pwr, scr_off = 0; + + pwr = i810_readl(PWR_CLKC, mmio); + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + mode = POWERON; + pwr |= 1; + scr_off = ON; + break; + case FB_BLANK_NORMAL: + mode = POWERON; + pwr |= 1; + scr_off = OFF; + break; + case FB_BLANK_VSYNC_SUSPEND: + mode = STANDBY; + pwr |= 1; + scr_off = OFF; + break; + case FB_BLANK_HSYNC_SUSPEND: + mode = SUSPEND; + pwr |= 1; + scr_off = OFF; + break; + case FB_BLANK_POWERDOWN: + mode = POWERDOWN; + pwr &= ~1; + scr_off = OFF; + break; + default: + return -EINVAL; + } + + i810_screen_off(mmio, scr_off); + i810_writel(HVSYNC, mmio, mode); + i810_writel(PWR_CLKC, mmio, pwr); + + return 0; +} + +static int i810fb_set_par(struct fb_info *info) +{ + struct i810fb_par *par = info->par; + + decode_var(&info->var, par); + i810_load_regs(par); + i810_init_cursor(par); + encode_fix(&info->fix, info); + + if (info->var.accel_flags && !(par->dev_flags & LOCKUP)) { + info->flags = FBINFO_HWACCEL_YPAN | + FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_IMAGEBLIT; + info->pixmap.scan_align = 2; + } else { + info->pixmap.scan_align = 1; + info->flags = FBINFO_HWACCEL_YPAN; + } + return 0; +} + +static int i810fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int err; + + if (IS_DVT) { + var->vmode &= ~FB_VMODE_MASK; + var->vmode |= FB_VMODE_NONINTERLACED; + } + if (var->vmode & FB_VMODE_DOUBLE) { + var->vmode &= ~FB_VMODE_MASK; + var->vmode |= FB_VMODE_NONINTERLACED; + } + + i810_round_off(var); + if ((err = i810_check_params(var, info))) + return err; + + i810fb_fill_var_timings(var); + set_color_bitfields(var); + return 0; +} + +static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct i810fb_par *par = info->par; + u8 __iomem *mmio = par->mmio_start_virtual; + + if (par->dev_flags & LOCKUP) + return -ENXIO; + + if (cursor->image.width > 64 || cursor->image.height > 64) + return -ENXIO; + + if ((i810_readl(CURBASE, mmio) & 0xf) != par->cursor_heap.physical) { + i810_init_cursor(par); + cursor->set |= FB_CUR_SETALL; + } + + i810_enable_cursor(mmio, OFF); + + if (cursor->set & FB_CUR_SETPOS) { + u32 tmp; + + tmp = (cursor->image.dx - info->var.xoffset) & 0xffff; + tmp |= (cursor->image.dy - info->var.yoffset) << 16; + i810_writel(CURPOS, mmio, tmp); + } + + if (cursor->set & FB_CUR_SETSIZE) + i810_reset_cursor_image(par); + + if (cursor->set & FB_CUR_SETCMAP) + i810_load_cursor_colors(cursor->image.fg_color, + cursor->image.bg_color, + info); + + if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { + int size = ((cursor->image.width + 7) >> 3) * + cursor->image.height; + int i; + u8 *data = kmalloc(64 * 8, GFP_ATOMIC); + + if (data == NULL) + return -ENOMEM; + + switch (cursor->rop) { + case ROP_XOR: + for (i = 0; i < size; i++) + data[i] = cursor->image.data[i] ^ cursor->mask[i]; + break; + case ROP_COPY: + default: + for (i = 0; i < size; i++) + data[i] = cursor->image.data[i] & cursor->mask[i]; + break; + } + + i810_load_cursor_image(cursor->image.width, + cursor->image.height, data, + par); + kfree(data); + } + + if (cursor->enable) + i810_enable_cursor(mmio, ON); + + return 0; +} + +static const struct fb_ops i810fb_ops = { + .owner = THIS_MODULE, + .fb_open = i810fb_open, + .fb_release = i810fb_release, + __FB_DEFAULT_IOMEM_OPS_RDWR, + .fb_check_var = i810fb_check_var, + .fb_set_par = i810fb_set_par, + .fb_setcolreg = i810fb_setcolreg, + .fb_blank = i810fb_blank, + .fb_pan_display = i810fb_pan_display, + .fb_fillrect = i810fb_fillrect, + .fb_copyarea = i810fb_copyarea, + .fb_imageblit = i810fb_imageblit, + .fb_cursor = i810fb_cursor, + .fb_sync = i810fb_sync, + __FB_DEFAULT_IOMEM_OPS_MMAP, +}; + +/*********************************************************************** + * Power Management * + ***********************************************************************/ +static int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg) +{ + struct fb_info *info = pci_get_drvdata(dev); + struct i810fb_par *par = info->par; + + par->cur_state = mesg.event; + + switch (mesg.event) { + case PM_EVENT_FREEZE: + case PM_EVENT_PRETHAW: + dev->dev.power.power_state = mesg; + return 0; + } + + console_lock(); + fb_set_suspend(info, 1); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + i810fb_blank(FB_BLANK_POWERDOWN, info); + agp_unbind_memory(par->i810_gtt.i810_fb_memory); + agp_unbind_memory(par->i810_gtt.i810_cursor_memory); + + pci_save_state(dev); + pci_disable_device(dev); + pci_set_power_state(dev, pci_choose_state(dev, mesg)); + console_unlock(); + + return 0; +} + +static int i810fb_resume(struct pci_dev *dev) +{ + struct fb_info *info = pci_get_drvdata(dev); + struct i810fb_par *par = info->par; + int cur_state = par->cur_state; + + par->cur_state = PM_EVENT_ON; + + if (cur_state == PM_EVENT_FREEZE) { + pci_set_power_state(dev, PCI_D0); + return 0; + } + + console_lock(); + pci_set_power_state(dev, PCI_D0); + pci_restore_state(dev); + + if (pci_enable_device(dev)) + goto fail; + + pci_set_master(dev); + agp_bind_memory(par->i810_gtt.i810_fb_memory, + par->fb.offset); + agp_bind_memory(par->i810_gtt.i810_cursor_memory, + par->cursor_heap.offset); + i810fb_set_par(info); + fb_set_suspend (info, 0); + info->fbops->fb_blank(VESA_NO_BLANKING, info); +fail: + console_unlock(); + return 0; +} +/*********************************************************************** + * AGP resource allocation * + ***********************************************************************/ + +static void i810_fix_pointers(struct i810fb_par *par) +{ + par->fb.physical = par->aperture.physical+(par->fb.offset << 12); + par->fb.virtual = par->aperture.virtual+(par->fb.offset << 12); + par->iring.physical = par->aperture.physical + + (par->iring.offset << 12); + par->iring.virtual = par->aperture.virtual + + (par->iring.offset << 12); + par->cursor_heap.virtual = par->aperture.virtual+ + (par->cursor_heap.offset << 12); +} + +static void i810_fix_offsets(struct i810fb_par *par) +{ + if (vram + 1 > par->aperture.size >> 20) + vram = (par->aperture.size >> 20) - 1; + if (v_offset_default > (par->aperture.size >> 20)) + v_offset_default = (par->aperture.size >> 20); + if (vram + v_offset_default + 1 > par->aperture.size >> 20) + v_offset_default = (par->aperture.size >> 20) - (vram + 1); + + par->fb.size = vram << 20; + par->fb.offset = v_offset_default << 20; + par->fb.offset >>= 12; + + par->iring.offset = par->fb.offset + (par->fb.size >> 12); + par->iring.size = RINGBUFFER_SIZE; + + par->cursor_heap.offset = par->iring.offset + (RINGBUFFER_SIZE >> 12); + par->cursor_heap.size = 4096; +} + +static int i810_alloc_agp_mem(struct fb_info *info) +{ + struct i810fb_par *par = info->par; + int size; + struct agp_bridge_data *bridge; + + i810_fix_offsets(par); + size = par->fb.size + par->iring.size; + + if (!(bridge = agp_backend_acquire(par->dev))) { + dev_warn(&par->dev->dev, "cannot acquire agpgart\n"); + return -ENODEV; + } + if (!(par->i810_gtt.i810_fb_memory = + agp_allocate_memory(bridge, size >> 12, AGP_NORMAL_MEMORY))) { + dev_warn(&par->dev->dev, "can't allocate framebuffer " + "memory\n"); + agp_backend_release(bridge); + return -ENOMEM; + } + if (agp_bind_memory(par->i810_gtt.i810_fb_memory, + par->fb.offset)) { + dev_warn(&par->dev->dev, "can't bind framebuffer memory\n"); + agp_backend_release(bridge); + return -EBUSY; + } + + if (!(par->i810_gtt.i810_cursor_memory = + agp_allocate_memory(bridge, par->cursor_heap.size >> 12, + AGP_PHYSICAL_MEMORY))) { + dev_warn(&par->dev->dev, "can't allocate " + "cursor memory\n"); + agp_backend_release(bridge); + return -ENOMEM; + } + if (agp_bind_memory(par->i810_gtt.i810_cursor_memory, + par->cursor_heap.offset)) { + dev_warn(&par->dev->dev, "cannot bind cursor memory\n"); + agp_backend_release(bridge); + return -EBUSY; + } + + par->cursor_heap.physical = par->i810_gtt.i810_cursor_memory->physical; + + i810_fix_pointers(par); + + agp_backend_release(bridge); + + return 0; +} + +/*************************************************************** + * Initialization * + ***************************************************************/ + +/** + * i810_init_monspecs + * @info: pointer to device specific info structure + * + * DESCRIPTION: + * Sets the user monitor's horizontal and vertical + * frequency limits + */ +static void i810_init_monspecs(struct fb_info *info) +{ + if (!hsync1) + hsync1 = HFMIN; + if (!hsync2) + hsync2 = HFMAX; + if (!info->monspecs.hfmax) + info->monspecs.hfmax = hsync2; + if (!info->monspecs.hfmin) + info->monspecs.hfmin = hsync1; + if (hsync2 < hsync1) + info->monspecs.hfmin = hsync2; + + if (!vsync1) + vsync1 = VFMIN; + if (!vsync2) + vsync2 = VFMAX; + if (IS_DVT && vsync1 < 60) + vsync1 = 60; + if (!info->monspecs.vfmax) + info->monspecs.vfmax = vsync2; + if (!info->monspecs.vfmin) + info->monspecs.vfmin = vsync1; + if (vsync2 < vsync1) + info->monspecs.vfmin = vsync2; +} + +/** + * i810_init_defaults - initializes default values to use + * @par: pointer to i810fb_par structure + * @info: pointer to current fb_info structure + */ +static void i810_init_defaults(struct i810fb_par *par, struct fb_info *info) +{ + mutex_init(&par->open_lock); + + if (voffset) + v_offset_default = voffset; + else if (par->aperture.size > 32 * 1024 * 1024) + v_offset_default = 16; + else + v_offset_default = 8; + + if (!vram) + vram = 1; + + if (accel) + par->dev_flags |= HAS_ACCELERATION; + + if (sync) + par->dev_flags |= ALWAYS_SYNC; + + par->ddc_num = (ddc3 ? 3 : 2); + + if (bpp < 8) + bpp = 8; + + par->i810fb_ops = i810fb_ops; + + if (xres) + info->var.xres = xres; + else + info->var.xres = 640; + + if (yres) + info->var.yres = yres; + else + info->var.yres = 480; + + if (!vyres) + vyres = (vram << 20)/(info->var.xres*bpp >> 3); + + info->var.yres_virtual = vyres; + info->var.bits_per_pixel = bpp; + + if (dcolor) + info->var.nonstd = 1; + + if (par->dev_flags & HAS_ACCELERATION) + info->var.accel_flags = 1; + + i810_init_monspecs(info); +} + +/** + * i810_init_device - initialize device + * @par: pointer to i810fb_par structure + */ +static void i810_init_device(struct i810fb_par *par) +{ + u8 reg; + u8 __iomem *mmio = par->mmio_start_virtual; + + if (mtrr) + par->wc_cookie= arch_phys_wc_add((u32) par->aperture.physical, + par->aperture.size); + + i810_init_cursor(par); + + /* mvo: enable external vga-connector (for laptops) */ + if (extvga) { + i810_writel(HVSYNC, mmio, 0); + i810_writel(PWR_CLKC, mmio, 3); + } + + pci_read_config_byte(par->dev, 0x50, ®); + reg &= FREQ_MASK; + par->mem_freq = (reg) ? 133 : 100; + +} + +static int i810_allocate_pci_resource(struct i810fb_par *par, + const struct pci_device_id *entry) +{ + int err; + + if ((err = pci_enable_device(par->dev))) { + dev_err(&par->dev->dev, "cannot enable device\n"); + return err; + } + par->res_flags |= PCI_DEVICE_ENABLED; + + if (pci_resource_len(par->dev, 0) > 512 * 1024) { + par->aperture.physical = pci_resource_start(par->dev, 0); + par->aperture.size = pci_resource_len(par->dev, 0); + par->mmio_start_phys = pci_resource_start(par->dev, 1); + } else { + par->aperture.physical = pci_resource_start(par->dev, 1); + par->aperture.size = pci_resource_len(par->dev, 1); + par->mmio_start_phys = pci_resource_start(par->dev, 0); + } + if (!par->aperture.size) { + dev_warn(&par->dev->dev, "device is disabled\n"); + return -ENOMEM; + } + + if (!request_mem_region(par->aperture.physical, + par->aperture.size, + i810_pci_list[entry->driver_data])) { + dev_warn(&par->dev->dev, "cannot request framebuffer region\n"); + return -ENODEV; + } + par->res_flags |= FRAMEBUFFER_REQ; + + par->aperture.virtual = ioremap_wc(par->aperture.physical, + par->aperture.size); + if (!par->aperture.virtual) { + dev_warn(&par->dev->dev, "cannot remap framebuffer region\n"); + return -ENODEV; + } + + if (!request_mem_region(par->mmio_start_phys, + MMIO_SIZE, + i810_pci_list[entry->driver_data])) { + dev_warn(&par->dev->dev, "cannot request mmio region\n"); + return -ENODEV; + } + par->res_flags |= MMIO_REQ; + + par->mmio_start_virtual = ioremap(par->mmio_start_phys, + MMIO_SIZE); + if (!par->mmio_start_virtual) { + dev_warn(&par->dev->dev, "cannot remap mmio region\n"); + return -ENODEV; + } + + return 0; +} + +static void i810fb_find_init_mode(struct fb_info *info) +{ + struct fb_videomode mode; + struct fb_var_screeninfo var; + struct fb_monspecs *specs = &info->monspecs; + int found = 0; +#ifdef CONFIG_FB_I810_I2C + int i; + int err = 1; + struct i810fb_par *par = info->par; +#endif + + INIT_LIST_HEAD(&info->modelist); + memset(&mode, 0, sizeof(struct fb_videomode)); + var = info->var; +#ifdef CONFIG_FB_I810_I2C + i810_create_i2c_busses(par); + + for (i = 0; i < par->ddc_num + 1; i++) { + err = i810_probe_i2c_connector(info, &par->edid, i); + if (!err) + break; + } + + if (!err) + dev_info(&par->dev->dev, "DDC probe successful\n"); + + fb_edid_to_monspecs(par->edid, specs); + + if (specs->modedb == NULL) + dev_info(&par->dev->dev, "Unable to get Mode Database\n"); + + fb_videomode_to_modelist(specs->modedb, specs->modedb_len, + &info->modelist); + if (specs->modedb != NULL) { + const struct fb_videomode *m; + + if (xres && yres) { + if ((m = fb_find_best_mode(&var, &info->modelist))) { + mode = *m; + found = 1; + } + } + + if (!found) { + m = fb_find_best_display(&info->monspecs, &info->modelist); + mode = *m; + found = 1; + } + + fb_videomode_to_var(&var, &mode); + } +#endif + if (mode_option) + fb_find_mode(&var, info, mode_option, specs->modedb, + specs->modedb_len, (found) ? &mode : NULL, + info->var.bits_per_pixel); + + info->var = var; + fb_destroy_modedb(specs->modedb); + specs->modedb = NULL; +} + +#ifndef MODULE +static int i810fb_setup(char *options) +{ + char *this_opt, *suffix = NULL; + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "mtrr", 4)) + mtrr = true; + else if (!strncmp(this_opt, "accel", 5)) + accel = true; + else if (!strncmp(this_opt, "extvga", 6)) + extvga = true; + else if (!strncmp(this_opt, "sync", 4)) + sync = true; + else if (!strncmp(this_opt, "vram:", 5)) + vram = (simple_strtoul(this_opt+5, NULL, 0)); + else if (!strncmp(this_opt, "voffset:", 8)) + voffset = (simple_strtoul(this_opt+8, NULL, 0)); + else if (!strncmp(this_opt, "xres:", 5)) + xres = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "yres:", 5)) + yres = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "vyres:", 6)) + vyres = simple_strtoul(this_opt+6, NULL, 0); + else if (!strncmp(this_opt, "bpp:", 4)) + bpp = simple_strtoul(this_opt+4, NULL, 0); + else if (!strncmp(this_opt, "hsync1:", 7)) { + hsync1 = simple_strtoul(this_opt+7, &suffix, 0); + if (strncmp(suffix, "H", 1)) + hsync1 *= 1000; + } else if (!strncmp(this_opt, "hsync2:", 7)) { + hsync2 = simple_strtoul(this_opt+7, &suffix, 0); + if (strncmp(suffix, "H", 1)) + hsync2 *= 1000; + } else if (!strncmp(this_opt, "vsync1:", 7)) + vsync1 = simple_strtoul(this_opt+7, NULL, 0); + else if (!strncmp(this_opt, "vsync2:", 7)) + vsync2 = simple_strtoul(this_opt+7, NULL, 0); + else if (!strncmp(this_opt, "dcolor", 6)) + dcolor = true; + else if (!strncmp(this_opt, "ddc3", 4)) + ddc3 = true; + else + mode_option = this_opt; + } + return 0; +} +#endif + +static int i810fb_init_pci(struct pci_dev *dev, + const struct pci_device_id *entry) +{ + struct fb_info *info; + struct i810fb_par *par = NULL; + struct fb_videomode mode; + int err = -1, vfreq, hfreq, pixclock; + + err = aperture_remove_conflicting_pci_devices(dev, "i810fb"); + if (err) + return err; + + info = framebuffer_alloc(sizeof(struct i810fb_par), &dev->dev); + if (!info) + return -ENOMEM; + + par = info->par; + par->dev = dev; + + if (!(info->pixmap.addr = kzalloc(8*1024, GFP_KERNEL))) { + i810fb_release_resource(info, par); + return -ENOMEM; + } + info->pixmap.size = 8*1024; + info->pixmap.buf_align = 8; + info->pixmap.access_align = 32; + info->pixmap.flags = FB_PIXMAP_SYSTEM; + + if ((err = i810_allocate_pci_resource(par, entry))) { + i810fb_release_resource(info, par); + return err; + } + + i810_init_defaults(par, info); + + if ((err = i810_alloc_agp_mem(info))) { + i810fb_release_resource(info, par); + return err; + } + + i810_init_device(par); + + info->screen_base = par->fb.virtual; + info->fbops = &par->i810fb_ops; + info->pseudo_palette = par->pseudo_palette; + fb_alloc_cmap(&info->cmap, 256, 0); + i810fb_find_init_mode(info); + + if ((err = info->fbops->fb_check_var(&info->var, info))) { + i810fb_release_resource(info, par); + return err; + } + + fb_var_to_videomode(&mode, &info->var); + fb_add_videomode(&mode, &info->modelist); + + i810fb_init_ringbuffer(info); + err = register_framebuffer(info); + + if (err < 0) { + i810fb_release_resource(info, par); + dev_warn(&par->dev->dev, "cannot register framebuffer device\n"); + return err; + } + + pci_set_drvdata(dev, info); + pixclock = 1000000000/(info->var.pixclock); + pixclock *= 1000; + hfreq = pixclock/(info->var.xres + info->var.left_margin + + info->var.hsync_len + info->var.right_margin); + vfreq = hfreq/(info->var.yres + info->var.upper_margin + + info->var.vsync_len + info->var.lower_margin); + + dev_info(&par->dev->dev, "fb%d : %s v%d.%d.%d%s\n" + "Video RAM : %dK\n" + "Monitor : H: %d-%d KHz V: %d-%d Hz\n" + "Mode : %dx%d-%dbpp@%dHz\n", + info->node, + i810_pci_list[entry->driver_data], + VERSION_MAJOR, VERSION_MINOR, VERSION_TEENIE, BRANCH_VERSION, + (int) par->fb.size>>10, info->monspecs.hfmin/1000, + info->monspecs.hfmax/1000, info->monspecs.vfmin, + info->monspecs.vfmax, info->var.xres, + info->var.yres, info->var.bits_per_pixel, vfreq); + return 0; +} + +/*************************************************************** + * De-initialization * + ***************************************************************/ + +static void i810fb_release_resource(struct fb_info *info, + struct i810fb_par *par) +{ + struct gtt_data *gtt = &par->i810_gtt; + arch_phys_wc_del(par->wc_cookie); + + i810_delete_i2c_busses(par); + + if (par->i810_gtt.i810_cursor_memory) + agp_free_memory(gtt->i810_cursor_memory); + if (par->i810_gtt.i810_fb_memory) + agp_free_memory(gtt->i810_fb_memory); + + if (par->mmio_start_virtual) + iounmap(par->mmio_start_virtual); + if (par->aperture.virtual) + iounmap(par->aperture.virtual); + kfree(par->edid); + if (par->res_flags & FRAMEBUFFER_REQ) + release_mem_region(par->aperture.physical, + par->aperture.size); + if (par->res_flags & MMIO_REQ) + release_mem_region(par->mmio_start_phys, MMIO_SIZE); + + framebuffer_release(info); + +} + +static void i810fb_remove_pci(struct pci_dev *dev) +{ + struct fb_info *info = pci_get_drvdata(dev); + struct i810fb_par *par = info->par; + + unregister_framebuffer(info); + i810fb_release_resource(info, par); + dev_info(&par->dev->dev, "unloaded i810 framebuffer device\n"); +} + +#ifndef MODULE +static int i810fb_init(void) +{ + char *option = NULL; + + if (fb_modesetting_disabled("i810fb")) + return -ENODEV; + + if (fb_get_options("i810fb", &option)) + return -ENODEV; + i810fb_setup(option); + + return pci_register_driver(&i810fb_driver); +} +#endif + +/********************************************************************* + * Modularization * + *********************************************************************/ + +#ifdef MODULE + +static int i810fb_init(void) +{ + if (fb_modesetting_disabled("i810fb")) + return -ENODEV; + + hsync1 *= 1000; + hsync2 *= 1000; + + return pci_register_driver(&i810fb_driver); +} + +module_param(vram, int, 0); +MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB" + " (default=4)"); +module_param(voffset, int, 0); +MODULE_PARM_DESC(voffset, "at what offset to place start of framebuffer " + "memory (0 to maximum aperture size), in MiB (default = 48)"); +module_param(bpp, int, 0); +MODULE_PARM_DESC(bpp, "Color depth for display in bits per pixel" + " (default = 8)"); +module_param(xres, int, 0); +MODULE_PARM_DESC(xres, "Horizontal resolution in pixels (default = 640)"); +module_param(yres, int, 0); +MODULE_PARM_DESC(yres, "Vertical resolution in scanlines (default = 480)"); +module_param(vyres,int, 0); +MODULE_PARM_DESC(vyres, "Virtual vertical resolution in scanlines" + " (default = 480)"); +module_param(hsync1, int, 0); +MODULE_PARM_DESC(hsync1, "Minimum horizontal frequency of monitor in KHz" + " (default = 29)"); +module_param(hsync2, int, 0); +MODULE_PARM_DESC(hsync2, "Maximum horizontal frequency of monitor in KHz" + " (default = 30)"); +module_param(vsync1, int, 0); +MODULE_PARM_DESC(vsync1, "Minimum vertical frequency of monitor in Hz" + " (default = 50)"); +module_param(vsync2, int, 0); +MODULE_PARM_DESC(vsync2, "Maximum vertical frequency of monitor in Hz" + " (default = 60)"); +module_param(accel, bool, 0); +MODULE_PARM_DESC(accel, "Use Acceleration (BLIT) engine (default = 0)"); +module_param(mtrr, bool, 0); +MODULE_PARM_DESC(mtrr, "Use MTRR (default = 0)"); +module_param(extvga, bool, 0); +MODULE_PARM_DESC(extvga, "Enable external VGA connector (default = 0)"); +module_param(sync, bool, 0); +MODULE_PARM_DESC(sync, "wait for accel engine to finish drawing" + " (default = 0)"); +module_param(dcolor, bool, 0); +MODULE_PARM_DESC(dcolor, "use DirectColor visuals" + " (default = 0 = TrueColor)"); +module_param(ddc3, bool, 0); +MODULE_PARM_DESC(ddc3, "Probe DDC bus 3 (default = 0 = no)"); +module_param(mode_option, charp, 0); +MODULE_PARM_DESC(mode_option, "Specify initial video mode"); + +MODULE_AUTHOR("Tony A. Daplas"); +MODULE_DESCRIPTION("Framebuffer device for the Intel 810/815 and" + " compatible cards"); +MODULE_LICENSE("GPL"); + +static void __exit i810fb_exit(void) +{ + pci_unregister_driver(&i810fb_driver); +} +module_exit(i810fb_exit); + +#endif /* MODULE */ + +module_init(i810fb_init); diff --git a/drivers/video/fbdev/i810/i810_main.h b/drivers/video/fbdev/i810/i810_main.h new file mode 100644 index 000000000..7bfaaad1d --- /dev/null +++ b/drivers/video/fbdev/i810/i810_main.h @@ -0,0 +1,69 @@ +/*-*- linux-c -*- + * linux/drivers/video/i810fb_main.h -- Intel 810 frame buffer device + * main header file + * + * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#ifndef __I810_MAIN_H__ +#define __I810_MAIN_H__ + +/* Video Timings */ +extern void round_off_xres (u32 *xres); +extern void round_off_yres (u32 *xres, u32 *yres); +extern u32 i810_get_watermark (const struct fb_var_screeninfo *var, + struct i810fb_par *par); +extern void i810fb_encode_registers(const struct fb_var_screeninfo *var, + struct i810fb_par *par, u32 xres, u32 yres); +extern void i810fb_fill_var_timings(struct fb_var_screeninfo *var); + +/* Accelerated Functions */ +extern void i810fb_fillrect (struct fb_info *p, + const struct fb_fillrect *rect); +extern void i810fb_copyarea (struct fb_info *p, + const struct fb_copyarea *region); +extern void i810fb_imageblit(struct fb_info *p, const struct fb_image *image); +extern int i810fb_sync (struct fb_info *p); + +extern void i810fb_init_ringbuffer(struct fb_info *info); +extern void i810fb_load_front (u32 offset, struct fb_info *info); + +#ifdef CONFIG_FB_I810_I2C +/* I2C */ +extern int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, + int conn); +extern void i810_create_i2c_busses(struct i810fb_par *par); +extern void i810_delete_i2c_busses(struct i810fb_par *par); +#else +static inline int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, + int conn) +{ + return 1; +} +static inline void i810_create_i2c_busses(struct i810fb_par *par) { } +static inline void i810_delete_i2c_busses(struct i810fb_par *par) { } +#endif + +/* Conditionals */ +#ifdef CONFIG_X86 +static inline void flush_cache(void) +{ + asm volatile ("wbinvd":::"memory"); +} +#else +#define flush_cache() do { } while(0) +#endif + +#ifdef CONFIG_FB_I810_GTF +#define IS_DVT (0) +#else +#define IS_DVT (1) +#endif + +#endif /* __I810_MAIN_H__ */ diff --git a/drivers/video/fbdev/i810/i810_regs.h b/drivers/video/fbdev/i810/i810_regs.h new file mode 100644 index 000000000..91c6bd9d0 --- /dev/null +++ b/drivers/video/fbdev/i810/i810_regs.h @@ -0,0 +1,275 @@ +/*-*- linux-c -*- + * linux/drivers/video/i810_regs.h -- Intel 810/815 Register List + * + * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net> + * All Rights Reserved + * + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + + +/* + * Intel 810 Chipset Family PRM 15 3.1 + * GC Register Memory Address Map + * + * Based on: + * Intel (R) 810 Chipset Family + * Programmer s Reference Manual + * November 1999 + * Revision 1.0 + * Order Number: 298026-001 R + * + * All GC registers are memory-mapped. In addition, the VGA and extended VGA registers + * are I/O mapped. + */ + +#ifndef __I810_REGS_H__ +#define __I810_REGS_H__ + +/* Instruction and Interrupt Control Registers (01000h 02FFFh) */ +#define FENCE 0x02000 +#define PGTBL_CTL 0x02020 +#define PGTBL_ER 0x02024 +#define LRING 0x02030 +#define IRING 0x02040 +#define HWS_PGA 0x02080 +#define IPEIR 0x02088 +#define IPEHR 0x0208C +#define INSTDONE 0x02090 +#define NOPID 0x02094 +#define HWSTAM 0x02098 +#define IER 0x020A0 +#define IIR 0x020A4 +#define IMR 0x020A8 +#define ISR 0x020AC +#define EIR 0x020B0 +#define EMR 0x020B4 +#define ESR 0x020B8 +#define INSTPM 0x020C0 +#define INSTPS 0x020C4 +#define BBP_PTR 0x020C8 +#define ABB_SRT 0x020CC +#define ABB_END 0x020D0 +#define DMA_FADD 0x020D4 +#define FW_BLC 0x020D8 +#define MEM_MODE 0x020DC + +/* Memory Control Registers (03000h 03FFFh) */ +#define DRT 0x03000 +#define DRAMCL 0x03001 +#define DRAMCH 0x03002 + + +/* Span Cursor Registers (04000h 04FFFh) */ +#define UI_SC_CTL 0x04008 + +/* I/O Control Registers (05000h 05FFFh) */ +#define HVSYNC 0x05000 +#define GPIOA 0x05010 +#define GPIOB 0x05014 +#define GPIOC 0x0501C + +/* Clock Control and Power Management Registers (06000h 06FFFh) */ +#define DCLK_0D 0x06000 +#define DCLK_1D 0x06004 +#define DCLK_2D 0x06008 +#define LCD_CLKD 0x0600C +#define DCLK_0DS 0x06010 +#define PWR_CLKC 0x06014 + +/* Graphics Translation Table Range Definition (10000h 1FFFFh) */ +#define GTT 0x10000 + +/* Overlay Registers (30000h 03FFFFh) */ +#define OVOADDR 0x30000 +#define DOVOSTA 0x30008 +#define GAMMA 0x30010 +#define OBUF_0Y 0x30100 +#define OBUF_1Y 0x30104 +#define OBUF_0U 0x30108 +#define OBUF_0V 0x3010C +#define OBUF_1U 0x30110 +#define OBUF_1V 0x30114 +#define OVOSTRIDE 0x30118 +#define YRGB_VPH 0x3011C +#define UV_VPH 0x30120 +#define HORZ_PH 0x30124 +#define INIT_PH 0x30128 +#define DWINPOS 0x3012C +#define DWINSZ 0x30130 +#define SWID 0x30134 +#define SWIDQW 0x30138 +#define SHEIGHT 0x3013F +#define YRGBSCALE 0x30140 +#define UVSCALE 0x30144 +#define OVOCLRCO 0x30148 +#define OVOCLRC1 0x3014C +#define DCLRKV 0x30150 +#define DLCRKM 0x30154 +#define SCLRKVH 0x30158 +#define SCLRKVL 0x3015C +#define SCLRKM 0x30160 +#define OVOCONF 0x30164 +#define OVOCMD 0x30168 +#define AWINPOS 0x30170 +#define AWINZ 0x30174 + +/* BLT Engine Status (40000h 4FFFFh) (Software Debug) */ +#define BR00 0x40000 +#define BRO1 0x40004 +#define BR02 0x40008 +#define BR03 0x4000C +#define BR04 0x40010 +#define BR05 0x40014 +#define BR06 0x40018 +#define BR07 0x4001C +#define BR08 0x40020 +#define BR09 0x40024 +#define BR10 0x40028 +#define BR11 0x4002C +#define BR12 0x40030 +#define BR13 0x40034 +#define BR14 0x40038 +#define BR15 0x4003C +#define BR16 0x40040 +#define BR17 0x40044 +#define BR18 0x40048 +#define BR19 0x4004C +#define SSLADD 0x40074 +#define DSLH 0x40078 +#define DSLRADD 0x4007C + + +/* LCD/TV-Out and HW DVD Registers (60000h 6FFFFh) */ +/* LCD/TV-Out */ +#define HTOTAL 0x60000 +#define HBLANK 0x60004 +#define HSYNC 0x60008 +#define VTOTAL 0x6000C +#define VBLANK 0x60010 +#define VSYNC 0x60014 +#define LCDTV_C 0x60018 +#define OVRACT 0x6001C +#define BCLRPAT 0x60020 + +/* Display and Cursor Control Registers (70000h 7FFFFh) */ +#define DISP_SL 0x70000 +#define DISP_SLC 0x70004 +#define PIXCONF 0x70008 +#define PIXCONF1 0x70009 +#define BLTCNTL 0x7000C +#define SWF 0x70014 +#define DPLYBASE 0x70020 +#define DPLYSTAS 0x70024 +#define CURCNTR 0x70080 +#define CURBASE 0x70084 +#define CURPOS 0x70088 + + +/* VGA Registers */ + +/* SMRAM Registers */ +#define SMRAM 0x10 + +/* Graphics Control Registers */ +#define GR_INDEX 0x3CE +#define GR_DATA 0x3CF + +#define GR10 0x10 +#define GR11 0x11 + +/* CRT Controller Registers */ +#define CR_INDEX_MDA 0x3B4 +#define CR_INDEX_CGA 0x3D4 +#define CR_DATA_MDA 0x3B5 +#define CR_DATA_CGA 0x3D5 + +#define CR30 0x30 +#define CR31 0x31 +#define CR32 0x32 +#define CR33 0x33 +#define CR35 0x35 +#define CR39 0x39 +#define CR40 0x40 +#define CR41 0x41 +#define CR42 0x42 +#define CR70 0x70 +#define CR80 0x80 +#define CR81 0x82 + +/* Extended VGA Registers */ + +/* General Control and Status Registers */ +#define ST00 0x3C2 +#define ST01_MDA 0x3BA +#define ST01_CGA 0x3DA +#define FRC_READ 0x3CA +#define FRC_WRITE_MDA 0x3BA +#define FRC_WRITE_CGA 0x3DA +#define MSR_READ 0x3CC +#define MSR_WRITE 0x3C2 + +/* Sequencer Registers */ +#define SR_INDEX 0x3C4 +#define SR_DATA 0x3C5 + +#define SR01 0x01 +#define SR02 0x02 +#define SR03 0x03 +#define SR04 0x04 +#define SR07 0x07 + +/* Graphics Controller Registers */ +#define GR00 0x00 +#define GR01 0x01 +#define GR02 0x02 +#define GR03 0x03 +#define GR04 0x04 +#define GR05 0x05 +#define GR06 0x06 +#define GR07 0x07 +#define GR08 0x08 + +/* Attribute Controller Registers */ +#define ATTR_WRITE 0x3C0 +#define ATTR_READ 0x3C1 + +/* VGA Color Palette Registers */ + +/* CLUT */ +#define CLUT_DATA 0x3C9 /* DACDATA */ +#define CLUT_INDEX_READ 0x3C7 /* DACRX */ +#define CLUT_INDEX_WRITE 0x3C8 /* DACWX */ +#define DACMASK 0x3C6 + +/* CRT Controller Registers */ +#define CR00 0x00 +#define CR01 0x01 +#define CR02 0x02 +#define CR03 0x03 +#define CR04 0x04 +#define CR05 0x05 +#define CR06 0x06 +#define CR07 0x07 +#define CR08 0x08 +#define CR09 0x09 +#define CR0A 0x0A +#define CR0B 0x0B +#define CR0C 0x0C +#define CR0D 0x0D +#define CR0E 0x0E +#define CR0F 0x0F +#define CR10 0x10 +#define CR11 0x11 +#define CR12 0x12 +#define CR13 0x13 +#define CR14 0x14 +#define CR15 0x15 +#define CR16 0x16 +#define CR17 0x17 +#define CR18 0x18 + +#endif /* __I810_REGS_H__ */ |
