aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/fbdev/i810
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2014-02-13 08:31:38 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2014-04-17 01:10:19 -0400
commitf7018c21350204c4cf628462f229d44d03545254 (patch)
tree408787177164cf51cc06f7aabdb04fcff8d2b6aa /drivers/video/fbdev/i810
parentc26ef3eb3c11274bad1b64498d0a134f85755250 (diff)
video: move fbdev to drivers/video/fbdev
The drivers/video directory is a mess. It contains generic video related files, directories for backlight, console, linux logo, lots of fbdev device drivers, fbdev framework files. Make some order into the chaos by creating drivers/video/fbdev directory, and move all fbdev related files there. No functionality is changed, although I guess it is possible that some subtle Makefile build order related issue could be created by this patch. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Acked-by: Rob Clark <robdclark@gmail.com> Acked-by: Jingoo Han <jg1.han@samsung.com> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/video/fbdev/i810')
-rw-r--r--drivers/video/fbdev/i810/Makefile17
-rw-r--r--drivers/video/fbdev/i810/i810-i2c.c175
-rw-r--r--drivers/video/fbdev/i810/i810.h299
-rw-r--r--drivers/video/fbdev/i810/i810_accel.c456
-rw-r--r--drivers/video/fbdev/i810/i810_dvt.c312
-rw-r--r--drivers/video/fbdev/i810/i810_gtf.c276
-rw-r--r--drivers/video/fbdev/i810/i810_main.c2218
-rw-r--r--drivers/video/fbdev/i810/i810_main.h95
-rw-r--r--drivers/video/fbdev/i810/i810_regs.h275
9 files changed, 4123 insertions, 0 deletions
diff --git a/drivers/video/fbdev/i810/Makefile b/drivers/video/fbdev/i810/Makefile
new file mode 100644
index 000000000000..96e08c8ded97
--- /dev/null
+++ b/drivers/video/fbdev/i810/Makefile
@@ -0,0 +1,17 @@
1#
2# Makefile for the Intel 810/815 framebuffer driver
3#
4
5obj-$(CONFIG_FB_I810) += i810fb.o
6
7i810fb-objs := i810_main.o i810_accel.o
8
9ifdef CONFIG_FB_I810_GTF
10i810fb-objs += i810_gtf.o
11else
12i810fb-objs += i810_dvt.o
13endif
14
15ifdef CONFIG_FB_I810_I2C
16i810fb-objs += i810-i2c.o
17endif
diff --git a/drivers/video/fbdev/i810/i810-i2c.c b/drivers/video/fbdev/i810/i810-i2c.c
new file mode 100644
index 000000000000..7db17d0d8a8c
--- /dev/null
+++ b/drivers/video/fbdev/i810/i810-i2c.c
@@ -0,0 +1,175 @@
1 /*-*- linux-c -*-
2 * linux/drivers/video/i810-i2c.c -- Intel 810/815 I2C support
3 *
4 * Copyright (C) 2004 Antonino Daplas<adaplas@pol.net>
5 * All Rights Reserved
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file COPYING in the main directory of this archive for
9 * more details.
10 */
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/delay.h>
14#include <linux/gfp.h>
15#include <linux/pci.h>
16#include <linux/fb.h>
17#include "i810.h"
18#include "i810_regs.h"
19#include "i810_main.h"
20#include "../edid.h"
21
22/* bit locations in the registers */
23#define SCL_DIR_MASK 0x0001
24#define SCL_DIR 0x0002
25#define SCL_VAL_MASK 0x0004
26#define SCL_VAL_OUT 0x0008
27#define SCL_VAL_IN 0x0010
28#define SDA_DIR_MASK 0x0100
29#define SDA_DIR 0x0200
30#define SDA_VAL_MASK 0x0400
31#define SDA_VAL_OUT 0x0800
32#define SDA_VAL_IN 0x1000
33
34#define DEBUG /* define this for verbose EDID parsing output */
35
36#ifdef DEBUG
37#define DPRINTK(fmt, args...) printk(fmt,## args)
38#else
39#define DPRINTK(fmt, args...)
40#endif
41
42static void i810i2c_setscl(void *data, int state)
43{
44 struct i810fb_i2c_chan *chan = data;
45 struct i810fb_par *par = chan->par;
46 u8 __iomem *mmio = par->mmio_start_virtual;
47
48 if (state)
49 i810_writel(mmio, chan->ddc_base, SCL_DIR_MASK | SCL_VAL_MASK);
50 else
51 i810_writel(mmio, chan->ddc_base, SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK);
52 i810_readl(mmio, chan->ddc_base); /* flush posted write */
53}
54
55static void i810i2c_setsda(void *data, int state)
56{
57 struct i810fb_i2c_chan *chan = data;
58 struct i810fb_par *par = chan->par;
59 u8 __iomem *mmio = par->mmio_start_virtual;
60
61 if (state)
62 i810_writel(mmio, chan->ddc_base, SDA_DIR_MASK | SDA_VAL_MASK);
63 else
64 i810_writel(mmio, chan->ddc_base, SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK);
65 i810_readl(mmio, chan->ddc_base); /* flush posted write */
66}
67
68static int i810i2c_getscl(void *data)
69{
70 struct i810fb_i2c_chan *chan = data;
71 struct i810fb_par *par = chan->par;
72 u8 __iomem *mmio = par->mmio_start_virtual;
73
74 i810_writel(mmio, chan->ddc_base, SCL_DIR_MASK);
75 i810_writel(mmio, chan->ddc_base, 0);
76 return ((i810_readl(mmio, chan->ddc_base) & SCL_VAL_IN) != 0);
77}
78
79static int i810i2c_getsda(void *data)
80{
81 struct i810fb_i2c_chan *chan = data;
82 struct i810fb_par *par = chan->par;
83 u8 __iomem *mmio = par->mmio_start_virtual;
84
85 i810_writel(mmio, chan->ddc_base, SDA_DIR_MASK);
86 i810_writel(mmio, chan->ddc_base, 0);
87 return ((i810_readl(mmio, chan->ddc_base) & SDA_VAL_IN) != 0);
88}
89
90static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name)
91{
92 int rc;
93
94 strcpy(chan->adapter.name, name);
95 chan->adapter.owner = THIS_MODULE;
96 chan->adapter.algo_data = &chan->algo;
97 chan->adapter.dev.parent = &chan->par->dev->dev;
98 chan->algo.setsda = i810i2c_setsda;
99 chan->algo.setscl = i810i2c_setscl;
100 chan->algo.getsda = i810i2c_getsda;
101 chan->algo.getscl = i810i2c_getscl;
102 chan->algo.udelay = 10;
103 chan->algo.timeout = (HZ/2);
104 chan->algo.data = chan;
105
106 i2c_set_adapdata(&chan->adapter, chan);
107
108 /* Raise SCL and SDA */
109 chan->algo.setsda(chan, 1);
110 chan->algo.setscl(chan, 1);
111 udelay(20);
112
113 rc = i2c_bit_add_bus(&chan->adapter);
114
115 if (rc == 0)
116 dev_dbg(&chan->par->dev->dev, "I2C bus %s registered.\n",name);
117 else {
118 dev_warn(&chan->par->dev->dev, "Failed to register I2C bus "
119 "%s.\n", name);
120 chan->par = NULL;
121 }
122
123 return rc;
124}
125
126void i810_create_i2c_busses(struct i810fb_par *par)
127{
128 par->chan[0].par = par;
129 par->chan[1].par = par;
130 par->chan[2].par = par;
131
132 par->chan[0].ddc_base = GPIOA;
133 i810_setup_i2c_bus(&par->chan[0], "I810-DDC");
134 par->chan[1].ddc_base = GPIOB;
135 i810_setup_i2c_bus(&par->chan[1], "I810-I2C");
136 par->chan[2].ddc_base = GPIOC;
137 i810_setup_i2c_bus(&par->chan[2], "I810-GPIOC");
138}
139
140void i810_delete_i2c_busses(struct i810fb_par *par)
141{
142 if (par->chan[0].par)
143 i2c_del_adapter(&par->chan[0].adapter);
144 par->chan[0].par = NULL;
145
146 if (par->chan[1].par)
147 i2c_del_adapter(&par->chan[1].adapter);
148 par->chan[1].par = NULL;
149
150 if (par->chan[2].par)
151 i2c_del_adapter(&par->chan[2].adapter);
152 par->chan[2].par = NULL;
153}
154
155int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn)
156{
157 struct i810fb_par *par = info->par;
158 u8 *edid = NULL;
159
160 DPRINTK("i810-i2c: Probe DDC%i Bus\n", conn+1);
161 if (conn < par->ddc_num) {
162 edid = fb_ddc_read(&par->chan[conn].adapter);
163 } else {
164 const u8 *e = fb_firmware_edid(info->device);
165
166 if (e != NULL) {
167 DPRINTK("i810-i2c: Getting EDID from BIOS\n");
168 edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL);
169 }
170 }
171
172 *out_edid = edid;
173
174 return (edid) ? 0 : 1;
175}
diff --git a/drivers/video/fbdev/i810/i810.h b/drivers/video/fbdev/i810/i810.h
new file mode 100644
index 000000000000..1414b73ac55b
--- /dev/null
+++ b/drivers/video/fbdev/i810/i810.h
@@ -0,0 +1,299 @@
1/*-*- linux-c -*-
2 * linux/drivers/video/i810.h -- Intel 810 General Definitions/Declarations
3 *
4 * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
5 * All Rights Reserved
6 *
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file COPYING in the main directory of this archive for
10 * more details.
11 */
12
13#ifndef __I810_H__
14#define __I810_H__
15
16#include <linux/list.h>
17#include <linux/agp_backend.h>
18#include <linux/fb.h>
19#include <linux/i2c.h>
20#include <linux/i2c-algo-bit.h>
21#include <video/vga.h>
22
23/* Fence */
24#define TILEWALK_X (0 << 12)
25#define TILEWALK_Y (1 << 12)
26
27/* Raster ops */
28#define COLOR_COPY_ROP 0xF0
29#define PAT_COPY_ROP 0xCC
30#define CLEAR_ROP 0x00
31#define WHITE_ROP 0xFF
32#define INVERT_ROP 0x55
33#define XOR_ROP 0x5A
34
35/* 2D Engine definitions */
36#define SOLIDPATTERN 0x80000000
37#define NONSOLID 0x00000000
38#define BPP8 (0 << 24)
39#define BPP16 (1 << 24)
40#define BPP24 (2 << 24)
41
42#define PIXCONF8 (2 << 16)
43#define PIXCONF15 (4 << 16)
44#define PIXCONF16 (5 << 16)
45#define PIXCONF24 (6 << 16)
46#define PIXCONF32 (7 << 16)
47
48#define DYN_COLOR_EN (1 << 26)
49#define DYN_COLOR_DIS (0 << 26)
50#define INCREMENT 0x00000000
51#define DECREMENT (0x01 << 30)
52#define ARB_ON 0x00000001
53#define ARB_OFF 0x00000000
54#define SYNC_FLIP 0x00000000
55#define ASYNC_FLIP 0x00000040
56#define OPTYPE_MASK 0xE0000000
57#define PARSER_MASK 0x001F8000
58#define D2_MASK 0x001FC000 /* 2D mask */
59
60/* Instruction type */
61/* There are more but pertains to 3D */
62#define PARSER 0x00000000
63#define BLIT (0x02 << 29)
64#define RENDER (0x03 << 29)
65
66/* Parser */
67#define NOP 0x00 /* No operation, padding */
68#define BP_INT (0x01 << 23) /* Breakpoint interrupt */
69#define USR_INT (0x02 << 23) /* User interrupt */
70#define WAIT_FOR_EVNT (0x03 << 23) /* Wait for event */
71#define FLUSH (0x04 << 23)
72#define CONTEXT_SEL (0x05 << 23)
73#define REPORT_HEAD (0x07 << 23)
74#define ARB_ON_OFF (0x08 << 23)
75#define OVERLAY_FLIP (0x11 << 23)
76#define LOAD_SCAN_INC (0x12 << 23)
77#define LOAD_SCAN_EX (0x13 << 23)
78#define FRONT_BUFFER (0x14 << 23)
79#define DEST_BUFFER (0x15 << 23)
80#define Z_BUFFER (0x16 << 23)
81
82#define STORE_DWORD_IMM (0x20 << 23)
83#define STORE_DWORD_IDX (0x21 << 23)
84#define BATCH_BUFFER (0x30 << 23)
85
86/* Blit */
87#define SETUP_BLIT 0x00
88#define SETUP_MONO_PATTERN_SL_BLT (0x10 << 22)
89#define PIXEL_BLT (0x20 << 22)
90#define SCANLINE_BLT (0x21 << 22)
91#define TEXT_BLT (0x22 << 22)
92#define TEXT_IMM_BLT (0x30 << 22)
93#define COLOR_BLT (0x40 << 22)
94#define MONO_PAT_BLIT (0x42 << 22)
95#define SOURCE_COPY_BLIT (0x43 << 22)
96#define MONO_SOURCE_COPY_BLIT (0x44 << 22)
97#define SOURCE_COPY_IMMEDIATE (0x60 << 22)
98#define MONO_SOURCE_COPY_IMMEDIATE (0x61 << 22)
99
100#define VERSION_MAJOR 0
101#define VERSION_MINOR 9
102#define VERSION_TEENIE 0
103#define BRANCH_VERSION ""
104
105
106/* mvo: intel i815 */
107#ifndef PCI_DEVICE_ID_INTEL_82815_100
108 #define PCI_DEVICE_ID_INTEL_82815_100 0x1102
109#endif
110#ifndef PCI_DEVICE_ID_INTEL_82815_NOAGP
111 #define PCI_DEVICE_ID_INTEL_82815_NOAGP 0x1112
112#endif
113#ifndef PCI_DEVICE_ID_INTEL_82815_FULL_CTRL
114 #define PCI_DEVICE_ID_INTEL_82815_FULL_CTRL 0x1130
115#endif
116
117/* General Defines */
118#define I810_PAGESIZE 4096
119#define MAX_DMA_SIZE (1024 * 4096)
120#define SAREA_SIZE 4096
121#define PCI_I810_MISCC 0x72
122#define MMIO_SIZE (512*1024)
123#define GTT_SIZE (16*1024)
124#define RINGBUFFER_SIZE (64*1024)
125#define CURSOR_SIZE 4096
126#define OFF 0
127#define ON 1
128#define MAX_KEY 256
129#define WAIT_COUNT 10000000
130#define IRING_PAD 8
131#define FONTDATAMAX 8192
132/* Masks (AND ops) and OR's */
133#define FB_START_MASK (0x3f << (32 - 6))
134#define MMIO_ADDR_MASK (0x1FFF << (32 - 13))
135#define FREQ_MASK (1 << 4)
136#define SCR_OFF 0x20
137#define DRAM_ON 0x08
138#define DRAM_OFF 0xE7
139#define PG_ENABLE_MASK 0x01
140#define RING_SIZE_MASK (RINGBUFFER_SIZE - 1)
141
142/* defines for restoring registers partially */
143#define ADDR_MAP_MASK (0x07 << 5)
144#define DISP_CTRL ~0
145#define PIXCONF_0 (0x64 << 8)
146#define PIXCONF_2 (0xF3 << 24)
147#define PIXCONF_1 (0xF0 << 16)
148#define MN_MASK 0x3FF03FF
149#define P_OR (0x7 << 4)
150#define DAC_BIT (1 << 16)
151#define INTERLACE_BIT (1 << 7)
152#define IER_MASK (3 << 13)
153#define IMR_MASK (3 << 13)
154
155/* Power Management */
156#define DPMS_MASK 0xF0000
157#define POWERON 0x00000
158#define STANDBY 0x20000
159#define SUSPEND 0x80000
160#define POWERDOWN 0xA0000
161#define EMR_MASK ~0x3F
162#define FW_BLC_MASK ~(0x3F|(7 << 8)|(0x3F << 12)|(7 << 20))
163
164/* Ringbuffer */
165#define RBUFFER_START_MASK 0xFFFFF000
166#define RBUFFER_SIZE_MASK 0x001FF000
167#define RBUFFER_HEAD_MASK 0x001FFFFC
168#define RBUFFER_TAIL_MASK 0x001FFFF8
169
170/* Video Timings */
171#define REF_FREQ 24000000
172#define TARGET_N_MAX 30
173
174#define MAX_PIXELCLOCK 230000000
175#define MIN_PIXELCLOCK 15000000
176#define VFMAX 60
177#define VFMIN 60
178#define HFMAX 30000
179#define HFMIN 29000
180
181/* Cursor */
182#define CURSOR_ENABLE_MASK 0x1000
183#define CURSOR_MODE_64_TRANS 4
184#define CURSOR_MODE_64_XOR 5
185#define CURSOR_MODE_64_3C 6
186#define COORD_INACTIVE 0
187#define COORD_ACTIVE (1 << 4)
188#define EXTENDED_PALETTE 1
189
190/* AGP Memory Types*/
191#define AGP_NORMAL_MEMORY 0
192#define AGP_DCACHE_MEMORY 1
193#define AGP_PHYSICAL_MEMORY 2
194
195/* Allocated resource Flags */
196#define FRAMEBUFFER_REQ 1
197#define MMIO_REQ 2
198#define PCI_DEVICE_ENABLED 4
199#define HAS_FONTCACHE 8
200
201/* driver flags */
202#define HAS_MTRR 1
203#define HAS_ACCELERATION 2
204#define ALWAYS_SYNC 4
205#define LOCKUP 8
206
207struct gtt_data {
208 struct agp_memory *i810_fb_memory;
209 struct agp_memory *i810_cursor_memory;
210};
211
212struct mode_registers {
213 u32 pixclock, M, N, P;
214 u8 cr00, cr01, cr02, cr03;
215 u8 cr04, cr05, cr06, cr07;
216 u8 cr09, cr10, cr11, cr12;
217 u8 cr13, cr15, cr16, cr30;
218 u8 cr31, cr32, cr33, cr35, cr39;
219 u32 bpp8_100, bpp16_100;
220 u32 bpp24_100, bpp8_133;
221 u32 bpp16_133, bpp24_133;
222 u8 msr;
223};
224
225struct heap_data {
226 unsigned long physical;
227 __u8 __iomem *virtual;
228 u32 offset;
229 u32 size;
230};
231
232struct state_registers {
233 u32 dclk_1d, dclk_2d, dclk_0ds;
234 u32 pixconf, fw_blc, pgtbl_ctl;
235 u32 fence0, hws_pga, dplystas;
236 u16 bltcntl, hwstam, ier, iir, imr;
237 u8 cr00, cr01, cr02, cr03, cr04;
238 u8 cr05, cr06, cr07, cr08, cr09;
239 u8 cr10, cr11, cr12, cr13, cr14;
240 u8 cr15, cr16, cr17, cr80, gr10;
241 u8 cr30, cr31, cr32, cr33, cr35;
242 u8 cr39, cr41, cr70, sr01, msr;
243};
244
245struct i810fb_par;
246
247struct i810fb_i2c_chan {
248 struct i810fb_par *par;
249 struct i2c_adapter adapter;
250 struct i2c_algo_bit_data algo;
251 unsigned long ddc_base;
252};
253
254struct i810fb_par {
255 struct mode_registers regs;
256 struct state_registers hw_state;
257 struct gtt_data i810_gtt;
258 struct fb_ops i810fb_ops;
259 struct pci_dev *dev;
260 struct heap_data aperture;
261 struct heap_data fb;
262 struct heap_data iring;
263 struct heap_data cursor_heap;
264 struct vgastate state;
265 struct i810fb_i2c_chan chan[3];
266 struct mutex open_lock;
267 unsigned int use_count;
268 u32 pseudo_palette[16];
269 unsigned long mmio_start_phys;
270 u8 __iomem *mmio_start_virtual;
271 u8 *edid;
272 u32 pitch;
273 u32 pixconf;
274 u32 watermark;
275 u32 mem_freq;
276 u32 res_flags;
277 u32 dev_flags;
278 u32 cur_tail;
279 u32 depth;
280 u32 blit_bpp;
281 u32 ovract;
282 u32 cur_state;
283 u32 ddc_num;
284 int mtrr_reg;
285 u16 bltcntl;
286 u8 interlace;
287};
288
289/*
290 * Register I/O
291 */
292#define i810_readb(where, mmio) readb(mmio + where)
293#define i810_readw(where, mmio) readw(mmio + where)
294#define i810_readl(where, mmio) readl(mmio + where)
295#define i810_writeb(where, mmio, val) writeb(val, mmio + where)
296#define i810_writew(where, mmio, val) writew(val, mmio + where)
297#define i810_writel(where, mmio, val) writel(val, mmio + where)
298
299#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 000000000000..7672d2ea9b35
--- /dev/null
+++ b/drivers/video/fbdev/i810/i810_accel.c
@@ -0,0 +1,456 @@
1/*-*- linux-c -*-
2 * linux/drivers/video/i810_accel.c -- Hardware Acceleration
3 *
4 * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
5 * All Rights Reserved
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file COPYING in the main directory of this archive for
9 * more details.
10 */
11#include <linux/kernel.h>
12#include <linux/string.h>
13#include <linux/fb.h>
14
15#include "i810_regs.h"
16#include "i810.h"
17#include "i810_main.h"
18
19static u32 i810fb_rop[] = {
20 COLOR_COPY_ROP, /* ROP_COPY */
21 XOR_ROP /* ROP_XOR */
22};
23
24/* Macros */
25#define PUT_RING(n) { \
26 i810_writel(par->cur_tail, par->iring.virtual, n); \
27 par->cur_tail += 4; \
28 par->cur_tail &= RING_SIZE_MASK; \
29}
30
31extern void flush_cache(void);
32
33/************************************************************/
34
35/* BLT Engine Routines */
36static inline void i810_report_error(u8 __iomem *mmio)
37{
38 printk("IIR : 0x%04x\n"
39 "EIR : 0x%04x\n"
40 "PGTBL_ER: 0x%04x\n"
41 "IPEIR : 0x%04x\n"
42 "IPEHR : 0x%04x\n",
43 i810_readw(IIR, mmio),
44 i810_readb(EIR, mmio),
45 i810_readl(PGTBL_ER, mmio),
46 i810_readl(IPEIR, mmio),
47 i810_readl(IPEHR, mmio));
48}
49
50/**
51 * wait_for_space - check ring buffer free space
52 * @space: amount of ringbuffer space needed in bytes
53 * @par: pointer to i810fb_par structure
54 *
55 * DESCRIPTION:
56 * The function waits until a free space from the ringbuffer
57 * is available
58 */
59static inline int wait_for_space(struct fb_info *info, u32 space)
60{
61 struct i810fb_par *par = info->par;
62 u32 head, count = WAIT_COUNT, tail;
63 u8 __iomem *mmio = par->mmio_start_virtual;
64
65 tail = par->cur_tail;
66 while (count--) {
67 head = i810_readl(IRING + 4, mmio) & RBUFFER_HEAD_MASK;
68 if ((tail == head) ||
69 (tail > head &&
70 (par->iring.size - tail + head) >= space) ||
71 (tail < head && (head - tail) >= space)) {
72 return 0;
73 }
74 }
75 printk("ringbuffer lockup!!!\n");
76 i810_report_error(mmio);
77 par->dev_flags |= LOCKUP;
78 info->pixmap.scan_align = 1;
79 return 1;
80}
81
82/**
83 * wait_for_engine_idle - waits for all hardware engines to finish
84 * @par: pointer to i810fb_par structure
85 *
86 * DESCRIPTION:
87 * This waits for lring(0), iring(1), and batch(3), etc to finish and
88 * waits until ringbuffer is empty.
89 */
90static inline int wait_for_engine_idle(struct fb_info *info)
91{
92 struct i810fb_par *par = info->par;
93 u8 __iomem *mmio = par->mmio_start_virtual;
94 int count = WAIT_COUNT;
95
96 if (wait_for_space(info, par->iring.size)) /* flush */
97 return 1;
98
99 while((i810_readw(INSTDONE, mmio) & 0x7B) != 0x7B && --count);
100 if (count) return 0;
101
102 printk("accel engine lockup!!!\n");
103 printk("INSTDONE: 0x%04x\n", i810_readl(INSTDONE, mmio));
104 i810_report_error(mmio);
105 par->dev_flags |= LOCKUP;
106 info->pixmap.scan_align = 1;
107 return 1;
108}
109
110/* begin_iring - prepares the ringbuffer
111 * @space: length of sequence in dwords
112 * @par: pointer to i810fb_par structure
113 *
114 * DESCRIPTION:
115 * Checks/waits for sufficient space in ringbuffer of size
116 * space. Returns the tail of the buffer
117 */
118static inline u32 begin_iring(struct fb_info *info, u32 space)
119{
120 struct i810fb_par *par = info->par;
121
122 if (par->dev_flags & ALWAYS_SYNC)
123 wait_for_engine_idle(info);
124 return wait_for_space(info, space);
125}
126
127/**
128 * end_iring - advances the buffer
129 * @par: pointer to i810fb_par structure
130 *
131 * DESCRIPTION:
132 * This advances the tail of the ringbuffer, effectively
133 * beginning the execution of the graphics instruction sequence.
134 */
135static inline void end_iring(struct i810fb_par *par)
136{
137 u8 __iomem *mmio = par->mmio_start_virtual;
138
139 i810_writel(IRING, mmio, par->cur_tail);
140}
141
142/**
143 * source_copy_blit - BLIT transfer operation
144 * @dwidth: width of rectangular graphics data
145 * @dheight: height of rectangular graphics data
146 * @dpitch: bytes per line of destination buffer
147 * @xdir: direction of copy (left to right or right to left)
148 * @src: address of first pixel to read from
149 * @dest: address of first pixel to write to
150 * @from: source address
151 * @where: destination address
152 * @rop: raster operation
153 * @blit_bpp: pixel format which can be different from the
154 * framebuffer's pixelformat
155 * @par: pointer to i810fb_par structure
156 *
157 * DESCRIPTION:
158 * This is a BLIT operation typically used when doing
159 * a 'Copy and Paste'
160 */
161static inline void source_copy_blit(int dwidth, int dheight, int dpitch,
162 int xdir, int src, int dest, int rop,
163 int blit_bpp, struct fb_info *info)
164{
165 struct i810fb_par *par = info->par;
166
167 if (begin_iring(info, 24 + IRING_PAD)) return;
168
169 PUT_RING(BLIT | SOURCE_COPY_BLIT | 4);
170 PUT_RING(xdir | rop << 16 | dpitch | DYN_COLOR_EN | blit_bpp);
171 PUT_RING(dheight << 16 | dwidth);
172 PUT_RING(dest);
173 PUT_RING(dpitch);
174 PUT_RING(src);
175
176 end_iring(par);
177}
178
179/**
180 * color_blit - solid color BLIT operation
181 * @width: width of destination
182 * @height: height of destination
183 * @pitch: pixels per line of the buffer
184 * @dest: address of first pixel to write to
185 * @where: destination
186 * @rop: raster operation
187 * @what: color to transfer
188 * @blit_bpp: pixel format which can be different from the
189 * framebuffer's pixelformat
190 * @par: pointer to i810fb_par structure
191 *
192 * DESCRIPTION:
193 * A BLIT operation which can be used for color fill/rectangular fill
194 */
195static inline void color_blit(int width, int height, int pitch, int dest,
196 int rop, int what, int blit_bpp,
197 struct fb_info *info)
198{
199 struct i810fb_par *par = info->par;
200
201 if (begin_iring(info, 24 + IRING_PAD)) return;
202
203 PUT_RING(BLIT | COLOR_BLT | 3);
204 PUT_RING(rop << 16 | pitch | SOLIDPATTERN | DYN_COLOR_EN | blit_bpp);
205 PUT_RING(height << 16 | width);
206 PUT_RING(dest);
207 PUT_RING(what);
208 PUT_RING(NOP);
209
210 end_iring(par);
211}
212
213/**
214 * mono_src_copy_imm_blit - color expand from system memory to framebuffer
215 * @dwidth: width of destination
216 * @dheight: height of destination
217 * @dpitch: pixels per line of the buffer
218 * @dsize: size of bitmap in double words
219 * @dest: address of first byte of pixel;
220 * @rop: raster operation
221 * @blit_bpp: pixelformat to use which can be different from the
222 * framebuffer's pixelformat
223 * @src: address of image data
224 * @bg: backgound color
225 * @fg: forground color
226 * @par: pointer to i810fb_par structure
227 *
228 * DESCRIPTION:
229 * A color expand operation where the source data is placed in the
230 * ringbuffer itself. Useful for drawing text.
231 *
232 * REQUIREMENT:
233 * The end of a scanline must be padded to the next word.
234 */
235static inline void mono_src_copy_imm_blit(int dwidth, int dheight, int dpitch,
236 int dsize, int blit_bpp, int rop,
237 int dest, const u32 *src, int bg,
238 int fg, struct fb_info *info)
239{
240 struct i810fb_par *par = info->par;
241
242 if (begin_iring(info, 24 + (dsize << 2) + IRING_PAD)) return;
243
244 PUT_RING(BLIT | MONO_SOURCE_COPY_IMMEDIATE | (4 + dsize));
245 PUT_RING(DYN_COLOR_EN | blit_bpp | rop << 16 | dpitch);
246 PUT_RING(dheight << 16 | dwidth);
247 PUT_RING(dest);
248 PUT_RING(bg);
249 PUT_RING(fg);
250 while (dsize--)
251 PUT_RING(*src++);
252
253 end_iring(par);
254}
255
256static inline void load_front(int offset, struct fb_info *info)
257{
258 struct i810fb_par *par = info->par;
259
260 if (begin_iring(info, 8 + IRING_PAD)) return;
261
262 PUT_RING(PARSER | FLUSH);
263 PUT_RING(NOP);
264
265 end_iring(par);
266
267 if (begin_iring(info, 8 + IRING_PAD)) return;
268
269 PUT_RING(PARSER | FRONT_BUFFER | ((par->pitch >> 3) << 8));
270 PUT_RING((par->fb.offset << 12) + offset);
271
272 end_iring(par);
273}
274
275/**
276 * i810fb_iring_enable - enables/disables the ringbuffer
277 * @mode: enable or disable
278 * @par: pointer to i810fb_par structure
279 *
280 * DESCRIPTION:
281 * Enables or disables the ringbuffer, effectively enabling or
282 * disabling the instruction/acceleration engine.
283 */
284static inline void i810fb_iring_enable(struct i810fb_par *par, u32 mode)
285{
286 u32 tmp;
287 u8 __iomem *mmio = par->mmio_start_virtual;
288
289 tmp = i810_readl(IRING + 12, mmio);
290 if (mode == OFF)
291 tmp &= ~1;
292 else
293 tmp |= 1;
294 flush_cache();
295 i810_writel(IRING + 12, mmio, tmp);
296}
297
298void i810fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
299{
300 struct i810fb_par *par = info->par;
301 u32 dx, dy, width, height, dest, rop = 0, color = 0;
302
303 if (!info->var.accel_flags || par->dev_flags & LOCKUP ||
304 par->depth == 4) {
305 cfb_fillrect(info, rect);
306 return;
307 }
308
309 if (par->depth == 1)
310 color = rect->color;
311 else
312 color = ((u32 *) (info->pseudo_palette))[rect->color];
313
314 rop = i810fb_rop[rect->rop];
315
316 dx = rect->dx * par->depth;
317 width = rect->width * par->depth;
318 dy = rect->dy;
319 height = rect->height;
320
321 dest = info->fix.smem_start + (dy * info->fix.line_length) + dx;
322 color_blit(width, height, info->fix.line_length, dest, rop, color,
323 par->blit_bpp, info);
324}
325
326void i810fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
327{
328 struct i810fb_par *par = info->par;
329 u32 sx, sy, dx, dy, pitch, width, height, src, dest, xdir;
330
331 if (!info->var.accel_flags || par->dev_flags & LOCKUP ||
332 par->depth == 4) {
333 cfb_copyarea(info, region);
334 return;
335 }
336
337 dx = region->dx * par->depth;
338 sx = region->sx * par->depth;
339 width = region->width * par->depth;
340 sy = region->sy;
341 dy = region->dy;
342 height = region->height;
343
344 if (dx <= sx) {
345 xdir = INCREMENT;
346 }
347 else {
348 xdir = DECREMENT;
349 sx += width - 1;
350 dx += width - 1;
351 }
352 if (dy <= sy) {
353 pitch = info->fix.line_length;
354 }
355 else {
356 pitch = (-(info->fix.line_length)) & 0xFFFF;
357 sy += height - 1;
358 dy += height - 1;
359 }
360 src = info->fix.smem_start + (sy * info->fix.line_length) + sx;
361 dest = info->fix.smem_start + (dy * info->fix.line_length) + dx;
362
363 source_copy_blit(width, height, pitch, xdir, src, dest,
364 PAT_COPY_ROP, par->blit_bpp, info);
365}
366
367void i810fb_imageblit(struct fb_info *info, const struct fb_image *image)
368{
369 struct i810fb_par *par = info->par;
370 u32 fg = 0, bg = 0, size, dst;
371
372 if (!info->var.accel_flags || par->dev_flags & LOCKUP ||
373 par->depth == 4 || image->depth != 1) {
374 cfb_imageblit(info, image);
375 return;
376 }
377
378 switch (info->var.bits_per_pixel) {
379 case 8:
380 fg = image->fg_color;
381 bg = image->bg_color;
382 break;
383 case 16:
384 case 24:
385 fg = ((u32 *)(info->pseudo_palette))[image->fg_color];
386 bg = ((u32 *)(info->pseudo_palette))[image->bg_color];
387 break;
388 }
389
390 dst = info->fix.smem_start + (image->dy * info->fix.line_length) +
391 (image->dx * par->depth);
392
393 size = (image->width+7)/8 + 1;
394 size &= ~1;
395 size *= image->height;
396 size += 7;
397 size &= ~7;
398 mono_src_copy_imm_blit(image->width * par->depth,
399 image->height, info->fix.line_length,
400 size/4, par->blit_bpp,
401 PAT_COPY_ROP, dst, (u32 *) image->data,
402 bg, fg, info);
403}
404
405int i810fb_sync(struct fb_info *info)
406{
407 struct i810fb_par *par = info->par;
408
409 if (!info->var.accel_flags || par->dev_flags & LOCKUP)
410 return 0;
411
412 return wait_for_engine_idle(info);
413}
414
415void i810fb_load_front(u32 offset, struct fb_info *info)
416{
417 struct i810fb_par *par = info->par;
418 u8 __iomem *mmio = par->mmio_start_virtual;
419
420 if (!info->var.accel_flags || par->dev_flags & LOCKUP)
421 i810_writel(DPLYBASE, mmio, par->fb.physical + offset);
422 else
423 load_front(offset, info);
424}
425
426/**
427 * i810fb_init_ringbuffer - initialize the ringbuffer
428 * @par: pointer to i810fb_par structure
429 *
430 * DESCRIPTION:
431 * Initializes the ringbuffer by telling the device the
432 * size and location of the ringbuffer. It also sets
433 * the head and tail pointers = 0
434 */
435void i810fb_init_ringbuffer(struct fb_info *info)
436{
437 struct i810fb_par *par = info->par;
438 u32 tmp1, tmp2;
439 u8 __iomem *mmio = par->mmio_start_virtual;
440
441 wait_for_engine_idle(info);
442 i810fb_iring_enable(par, OFF);
443 i810_writel(IRING, mmio, 0);
444 i810_writel(IRING + 4, mmio, 0);
445 par->cur_tail = 0;
446
447 tmp2 = i810_readl(IRING + 8, mmio) & ~RBUFFER_START_MASK;
448 tmp1 = par->iring.physical;
449 i810_writel(IRING + 8, mmio, tmp2 | tmp1);
450
451 tmp1 = i810_readl(IRING + 12, mmio);
452 tmp1 &= ~RBUFFER_SIZE_MASK;
453 tmp2 = (par->iring.size - I810_PAGESIZE) & RBUFFER_SIZE_MASK;
454 i810_writel(IRING + 12, mmio, tmp1 | tmp2);
455 i810fb_iring_enable(par, ON);
456}
diff --git a/drivers/video/fbdev/i810/i810_dvt.c b/drivers/video/fbdev/i810/i810_dvt.c
new file mode 100644
index 000000000000..b4b3670667ab
--- /dev/null
+++ b/drivers/video/fbdev/i810/i810_dvt.c
@@ -0,0 +1,312 @@
1/*-*- linux-c -*-
2 * linux/drivers/video/i810_dvt.c -- Intel 810 Discrete Video Timings (Intel)
3 *
4 * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
5 * All Rights Reserved
6 *
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file COPYING in the main directory of this archive for
10 * more details.
11 */
12
13#include <linux/kernel.h>
14
15#include "i810_regs.h"
16#include "i810.h"
17
18struct mode_registers std_modes[] = {
19 /* 640x480 @ 60Hz */
20 { 25000, 0x0013, 0x0003, 0x40, 0x5F, 0x4F, 0x50, 0x82, 0x51, 0x9D,
21 0x0B, 0x10, 0x40, 0xE9, 0x0B, 0xDF, 0x50, 0xE7, 0x04, 0x02,
22 0x01, 0x01, 0x01, 0x00, 0x01, 0x22002000, 0x22004000, 0x22006000,
23 0x22002000, 0x22004000, 0x22006000, 0xC0 },
24
25 /* 640x480 @ 70Hz */
26 { 28000, 0x0053, 0x0010, 0x40, 0x61, 0x4F, 0x4F, 0x85, 0x52, 0x9A,
27 0xF2, 0x10, 0x40, 0xE0, 0x03, 0xDF, 0x50, 0xDF, 0xF3, 0x01,
28 0x01, 0x01, 0x01, 0x00, 0x01, 0x22002000, 0x22004000, 0x22005000,
29 0x22002000, 0x22004000, 0x22005000, 0xC0 },
30
31 /* 640x480 @ 72Hz */
32 { 31000, 0x0013, 0x0002, 0x40, 0x63, 0x4F, 0x4F, 0x87, 0x52, 0x97,
33 0x06, 0x0F, 0x40, 0xE8, 0x0B, 0xDF, 0x50, 0xDF, 0x07, 0x02,
34 0x01, 0x01, 0x01, 0x00, 0x01, 0x22003000, 0x22005000, 0x22007000,
35 0x22003000, 0x22005000, 0x22007000, 0xC0 },
36
37 /* 640x480 @ 75Hz */
38 { 31000, 0x0013, 0x0002, 0x40, 0x64, 0x4F, 0x4F, 0x88, 0x51, 0x99,
39 0xF2, 0x10, 0x40, 0xE0, 0x03, 0xDF, 0x50, 0xDF, 0xF3, 0x01,
40 0x01, 0x01, 0x01, 0x00, 0x01, 0x22003000, 0x22005000, 0x22007000,
41 0x22003000, 0x22005000, 0x22007000, 0xC0 },
42
43 /* 640x480 @ 85Hz */
44 { 36000, 0x0010, 0x0001, 0x40, 0x63, 0x4F, 0x4F, 0x87, 0x56, 0x9D,
45 0xFB, 0x10, 0x40, 0xE0, 0x03, 0xDF, 0x50, 0xDF, 0xFC, 0x01,
46 0x01, 0x01, 0x01, 0x00, 0x01, 0x22003000, 0x22005000, 0x22107000,
47 0x22003000, 0x22005000, 0x22107000, 0xC0 },
48
49 /* 800x600 @ 56Hz */
50 { 36000, 0x0010, 0x0001, 0x40, 0x7B, 0x63, 0x63, 0x9F, 0x66, 0x8F,
51 0x6F, 0x10, 0x40, 0x58, 0x0A, 0x57, 0xC8, 0x57, 0x70, 0x02,
52 0x02, 0x02, 0x02, 0x00, 0x01, 0x22003000, 0x22005000, 0x22107000,
53 0x22003000, 0x22005000, 0x22107000, 0x00 },
54
55 /* 800x600 @ 60Hz */
56 { 40000, 0x0008, 0x0001, 0x30, 0x7F, 0x63, 0x63, 0x83, 0x68, 0x18,
57 0x72, 0x10, 0x40, 0x58, 0x0C, 0x57, 0xC8, 0x57, 0x73, 0x02,
58 0x02, 0x02, 0x02, 0x00, 0x00, 0x22003000, 0x22006000, 0x22108000,
59 0x22003000, 0x22006000, 0x22108000, 0x00 },
60
61 /* 800x600 @ 70Hz */
62 { 45000, 0x0054, 0x0015, 0x30, 0x7D, 0x63, 0x63, 0x81, 0x68, 0x12,
63 0x6f, 0x10, 0x40, 0x58, 0x0b, 0x57, 0x64, 0x57, 0x70, 0x02,
64 0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22007000, 0x2210A000,
65 0x22004000, 0x22007000, 0x2210A000, 0x00 },
66
67 /* 800x600 @ 72Hz */
68 { 50000, 0x0017, 0x0004, 0x30, 0x7D, 0x63, 0x63, 0x81, 0x6A, 0x19,
69 0x98, 0x10, 0x40, 0x7C, 0x02, 0x57, 0xC8, 0x57, 0x99, 0x02,
70 0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22007000, 0x2210A000,
71 0x22004000, 0x22007000, 0x2210A000, 0x00 },
72
73 /* 800x600 @ 75Hz */
74 { 49000, 0x001F, 0x0006, 0x30, 0x7F, 0x63, 0x63, 0x83, 0x65, 0x0F,
75 0x6F, 0x10, 0x40, 0x58, 0x0B, 0x57, 0xC8, 0x57, 0x70, 0x02,
76 0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22007000, 0x2210B000,
77 0x22004000, 0x22007000, 0x2210B000, 0x00 },
78
79 /* 800x600 @ 85Hz */
80 { 56000, 0x0049, 0x000E, 0x30, 0x7E, 0x63, 0x63, 0x82, 0x67, 0x0F,
81 0x75, 0x10, 0x40, 0x58, 0x0B, 0x57, 0xC8, 0x57, 0x76, 0x02,
82 0x02, 0x02, 0x02, 0x00, 0x00, 0x22004000, 0x22108000, 0x2210b000,
83 0x22004000, 0x22108000, 0x2210b000, 0x00 },
84
85 /* 1024x768 @ 60Hz */
86 { 65000, 0x003F, 0x000A, 0x30, 0xA3, 0x7F, 0x7F, 0x87, 0x83, 0x94,
87 0x24, 0x10, 0x40, 0x02, 0x08, 0xFF, 0x80, 0xFF, 0x25, 0x03,
88 0x02, 0x03, 0x02, 0x00, 0x00, 0x22005000, 0x22109000, 0x2220D000,
89 0x22005000, 0x22109000, 0x2220D000, 0xC0 },
90
91 /* 1024x768 @ 70Hz */
92 { 75000, 0x0017, 0x0002, 0x30, 0xA1, 0x7F, 0x7F, 0x85, 0x82, 0x93,
93 0x24, 0x10, 0x40, 0x02, 0x08, 0xFF, 0x80, 0xFF, 0x25, 0x03,
94 0x02, 0x03, 0x02, 0x00, 0x00, 0x22005000, 0x2210A000, 0x2220F000,
95 0x22005000, 0x2210A000, 0x2220F000, 0xC0 },
96
97 /* 1024x768 @ 75Hz */
98 { 78000, 0x0050, 0x0017, 0x20, 0x9F, 0x7F, 0x7F, 0x83, 0x81, 0x8D,
99 0x1E, 0x10, 0x40, 0x00, 0x03, 0xFF, 0x80, 0xFF, 0x1F, 0x03,
100 0x02, 0x03, 0x02, 0x00, 0x00, 0x22006000, 0x2210B000, 0x22210000,
101 0x22006000, 0x2210B000, 0x22210000, 0x00 },
102
103 /* 1024x768 @ 85Hz */
104 { 94000, 0x003D, 0x000E, 0x20, 0xA7, 0x7F, 0x7F, 0x8B, 0x85, 0x91,
105 0x26, 0x10, 0x40, 0x00, 0x03, 0xFF, 0x80, 0xFF, 0x27, 0x03,
106 0x02, 0x03, 0x02, 0x00, 0x00, 0x22007000, 0x2220E000, 0x22212000,
107 0x22007000, 0x2220E000, 0x22212000, 0x00 },
108
109 /* 1152x864 @ 60Hz */
110 { 80000, 0x0008, 0x0001, 0x20, 0xB3, 0x8F, 0x8F, 0x97, 0x93, 0x9f,
111 0x87, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5f, 0x88, 0x03,
112 0x03, 0x03, 0x03, 0x00, 0x00, 0x2220C000, 0x22210000, 0x22415000,
113 0x2220C000, 0x22210000, 0x22415000, 0x00 },
114
115 /* 1152x864 @ 70Hz */
116 { 96000, 0x000a, 0x0001, 0x20, 0xbb, 0x8F, 0x8F, 0x9f, 0x98, 0x87,
117 0x82, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x83, 0x03,
118 0x03, 0x03, 0x03, 0x00, 0x00, 0x22107000, 0x22210000, 0x22415000,
119 0x22107000, 0x22210000, 0x22415000, 0x00 },
120
121 /* 1152x864 @ 72Hz */
122 { 99000, 0x001f, 0x0006, 0x20, 0xbb, 0x8F, 0x8F, 0x9f, 0x98, 0x87,
123 0x83, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x84, 0x03,
124 0x03, 0x03, 0x03, 0x00, 0x00, 0x22107000, 0x22210000, 0x22415000,
125 0x22107000, 0x22210000, 0x22415000, 0x00 },
126
127 /* 1152x864 @ 75Hz */
128 { 108000, 0x0010, 0x0002, 0x20, 0xC3, 0x8F, 0x8F, 0x87, 0x97, 0x07,
129 0x82, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x83, 0x03,
130 0x03, 0x03, 0x03, 0x00, 0x01, 0x22107000, 0x22210000, 0x22415000,
131 0x22107000, 0x22210000, 0x22415000, 0x00 },
132
133 /* 1152x864 @ 85Hz */
134 { 121000, 0x006D, 0x0014, 0x20, 0xc0, 0x8F, 0x8F, 0x84, 0x97, 0x07,
135 0x93, 0x10, 0x40, 0x60, 0x03, 0x5F, 0x90, 0x5F, 0x94, 0x03,
136 0x03, 0x03, 0x03, 0x00, 0x01, 0x2220C000, 0x22210000, 0x22415000,
137 0x2220C000, 0x22210000, 0x22415000, 0x0 },
138
139 /* 1280x960 @ 60Hz */
140 { 108000, 0x0010, 0x0002, 0x20, 0xDC, 0x9F, 0x9F, 0x80, 0xAB, 0x99,
141 0xE6, 0x10, 0x40, 0xC0, 0x03, 0xBF, 0xA0, 0xBF, 0xE7, 0x03,
142 0x03, 0x03, 0x03, 0x00, 0x01, 0x2210A000, 0x22210000, 0x22415000,
143 0x2210A000, 0x22210000, 0x22415000, 0x00 },
144
145 /* 1280x960 @ 75Hz */
146 { 129000, 0x0029, 0x0006, 0x20, 0xD3, 0x9F, 0x9F, 0x97, 0xaa, 0x1b,
147 0xE8, 0x10, 0x40, 0xC0, 0x03, 0xBF, 0xA0, 0xBF, 0xE9, 0x03,
148 0x03, 0x03, 0x03, 0x00, 0x01, 0x2210A000, 0x22210000, 0x2241B000,
149 0x2210A000, 0x22210000, 0x2241B000, 0x00 },
150
151 /* 1280x960 @ 85Hz */
152 { 148000, 0x0042, 0x0009, 0x20, 0xD3, 0x9F, 0x9F, 0x97, 0xA7, 0x1B,
153 0xF1, 0x10, 0x40, 0xC0, 0x03, 0xBF, 0xA0, 0xBF, 0xF2, 0x03,
154 0x03, 0x03, 0x03, 0x00, 0x01, 0x2210A000, 0x22220000, 0x2241D000,
155 0x2210A000, 0x22220000, 0x2241D000, 0x00 },
156
157 /* 1600x1200 @ 60Hz */
158 { 162000, 0x0019, 0x0006, 0x10, 0x09, 0xC7, 0xC7, 0x8D, 0xcf, 0x07,
159 0xE0, 0x10, 0x40, 0xB0, 0x03, 0xAF, 0xC8, 0xAF, 0xE1, 0x04,
160 0x04, 0x04, 0x04, 0x01, 0x00, 0x2210b000, 0x22416000, 0x44419000,
161 0x2210b000, 0x22416000, 0x44419000, 0x00 },
162
163 /* 1600x1200 @ 65 Hz */
164 { 175000, 0x005d, 0x0018, 0x10, 0x09, 0xC7, 0xC7, 0x8D, 0xcf, 0x07,
165 0xE0, 0x10, 0x40, 0xB0, 0x03, 0xAF, 0xC8, 0xAF, 0xE1, 0x04,
166 0x04, 0x04, 0x04, 0x01, 0x00, 0x2210c000, 0x22416000, 0x44419000,
167 0x2210c000, 0x22416000, 0x44419000, 0x00 },
168
169 /* 1600x1200 @ 70 Hz */
170 { 189000, 0x003D, 0x000e, 0x10, 0x09, 0xC7, 0xC7, 0x8d, 0xcf, 0x07,
171 0xE0, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xE1, 0x04,
172 0x04, 0x04, 0x04, 0x01, 0x00, 0x2220e000, 0x22416000, 0x44419000,
173 0x2220e000, 0x22416000, 0x44419000, 0x00 },
174
175 /* 1600x1200 @ 72 Hz */
176 { 195000, 0x003f, 0x000e, 0x10, 0x0b, 0xC7, 0xC7, 0x8f, 0xd5, 0x0b,
177 0xE1, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xe2, 0x04, 0x04,
178 0x04, 0x04, 0x01, 0x00, 0x2220e000, 0x22416000, 0x44419000,
179 0x2220e000, 0x22416000, 0x44419000, 0x00 },
180
181 /* 1600x1200 @ 75 Hz */
182 { 202000, 0x0024, 0x0007, 0x10, 0x09, 0xC7, 0xC7, 0x8d, 0xcf, 0x07,
183 0xE0, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xE1, 0x04, 0x04,
184 0x04, 0x04, 0x01, 0x00, 0x2220e000, 0x22416000, 0x44419000,
185 0x2220e000, 0x22416000, 0x44419000, 0x00 },
186
187 /* 1600x1200 @ 85 Hz */
188 { 229000, 0x0029, 0x0007, 0x10, 0x09, 0xC7, 0xC7, 0x8d, 0xcf, 0x07,
189 0xE0, 0x10, 0x40, 0xb0, 0x03, 0xAF, 0xC8, 0xaf, 0xE1, 0x04, 0x04,
190 0x04, 0x04, 0x01, 0x00, 0x22210000, 0x22416000, 0x0,
191 0x22210000, 0x22416000, 0x0, 0x00 },
192};
193
194void round_off_xres(u32 *xres)
195{
196 if (*xres <= 640)
197 *xres = 640;
198 else if (*xres <= 800)
199 *xres = 800;
200 else if (*xres <= 1024)
201 *xres = 1024;
202 else if (*xres <= 1152)
203 *xres = 1152;
204 else if (*xres <= 1280)
205 *xres = 1280;
206 else
207 *xres = 1600;
208}
209
210inline void round_off_yres(u32 *xres, u32 *yres)
211{
212 *yres = (*xres * 3) >> 2;
213}
214
215static int i810fb_find_best_mode(u32 xres, u32 yres, u32 pixclock)
216{
217 u32 diff = 0, diff_best = 0xFFFFFFFF, i = 0, i_best = 0;
218 u8 hfl = (u8) ((xres >> 3) - 1);
219
220 for (i = 0; i < ARRAY_SIZE(std_modes); i++) {
221 if (std_modes[i].cr01 == hfl) {
222 if (std_modes[i].pixclock <= pixclock)
223 diff = pixclock - std_modes[i].pixclock;
224 if (diff < diff_best) {
225 i_best = i;
226 diff_best = diff;
227 }
228 }
229 }
230 return i_best;
231}
232
233void i810fb_encode_registers(const struct fb_var_screeninfo *var,
234 struct i810fb_par *par, u32 xres, u32 yres)
235{
236 u32 i_best = i810fb_find_best_mode(xres, yres, par->regs.pixclock);
237
238 par->regs = std_modes[i_best];
239
240 /* overlay */
241 par->ovract = ((xres + var->right_margin + var->hsync_len +
242 var->left_margin - 32) | ((xres - 32) << 16));
243}
244
245void i810fb_fill_var_timings(struct fb_var_screeninfo *var)
246{
247 u32 total, xres, yres;
248 u32 mode, pixclock;
249
250 xres = var->xres;
251 yres = var->yres;
252
253 pixclock = 1000000000 / var->pixclock;
254 mode = i810fb_find_best_mode(xres, yres, pixclock);
255
256 total = (std_modes[mode].cr00 | (std_modes[mode].cr35 & 1) << 8) + 3;
257 total <<= 3;
258
259 var->pixclock = 1000000000 / std_modes[mode].pixclock;
260 var->right_margin = (std_modes[mode].cr04 << 3) - xres;
261 var->hsync_len = ((std_modes[mode].cr05 & 0x1F) -
262 (std_modes[mode].cr04 & 0x1F)) << 3;
263 var->left_margin = (total - (xres + var->right_margin +
264 var->hsync_len));
265 var->sync = FB_SYNC_ON_GREEN;
266 if (~(std_modes[mode].msr & (1 << 6)))
267 var->sync |= FB_SYNC_HOR_HIGH_ACT;
268 if (~(std_modes[mode].msr & (1 << 7)))
269 var->sync |= FB_SYNC_VERT_HIGH_ACT;
270
271 total = (std_modes[mode].cr06 | (std_modes[mode].cr30 & 0xF) << 8) + 2;
272 var->lower_margin = (std_modes[mode].cr10 |
273 (std_modes[mode].cr32 & 0x0F) << 8) - yres;
274 var->vsync_len = (std_modes[mode].cr11 & 0x0F) -
275 (var->lower_margin & 0x0F);
276 var->upper_margin = total - (yres + var->lower_margin + var->vsync_len);
277}
278
279u32 i810_get_watermark(struct fb_var_screeninfo *var,
280 struct i810fb_par *par)
281{
282 struct mode_registers *params = &par->regs;
283 u32 wmark = 0;
284
285 if (par->mem_freq == 100) {
286 switch (var->bits_per_pixel) {
287 case 8:
288 wmark = params->bpp8_100;
289 break;
290 case 16:
291 wmark = params->bpp16_100;
292 break;
293 case 24:
294 case 32:
295 wmark = params->bpp24_100;
296 }
297 } else {
298 switch (var->bits_per_pixel) {
299 case 8:
300 wmark = params->bpp8_133;
301 break;
302 case 16:
303 wmark = params->bpp16_133;
304 break;
305 case 24:
306 case 32:
307 wmark = params->bpp24_133;
308 }
309 }
310 return wmark;
311}
312
diff --git a/drivers/video/fbdev/i810/i810_gtf.c b/drivers/video/fbdev/i810/i810_gtf.c
new file mode 100644
index 000000000000..9743d51e7f8c
--- /dev/null
+++ b/drivers/video/fbdev/i810/i810_gtf.c
@@ -0,0 +1,276 @@
1/*-*- linux-c -*-
2 * linux/drivers/video/i810_main.h -- Intel 810 Non-discrete Video Timings
3 * (VESA GTF)
4 *
5 * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
6 * All Rights Reserved
7 *
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file COPYING in the main directory of this archive for
11 * more details.
12 */
13#include <linux/kernel.h>
14
15#include "i810_regs.h"
16#include "i810.h"
17#include "i810_main.h"
18
19/*
20 * FIFO and Watermark tables - based almost wholly on i810_wmark.c in
21 * XFree86 v4.03 by Precision Insight. Slightly modified for integer
22 * operation, instead of float
23 */
24
25struct wm_info {
26 u32 freq;
27 u32 wm;
28};
29
30static struct wm_info i810_wm_8_100[] = {
31 { 15, 0x0070c000 }, { 19, 0x0070c000 }, { 25, 0x22003000 },
32 { 28, 0x22003000 }, { 31, 0x22003000 }, { 36, 0x22007000 },
33 { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22008000 },
34 { 50, 0x22008000 }, { 56, 0x22008000 }, { 65, 0x22008000 },
35 { 75, 0x22008000 }, { 78, 0x22008000 }, { 80, 0x22008000 },
36 { 94, 0x22008000 }, { 96, 0x22107000 }, { 99, 0x22107000 },
37 { 108, 0x22107000 }, { 121, 0x22107000 }, { 128, 0x22107000 },
38 { 132, 0x22109000 }, { 135, 0x22109000 }, { 157, 0x2210b000 },
39 { 162, 0x2210b000 }, { 175, 0x2210b000 }, { 189, 0x2220e000 },
40 { 195, 0x2220e000 }, { 202, 0x2220e000 }, { 204, 0x2220e000 },
41 { 218, 0x2220f000 }, { 229, 0x22210000 }, { 234, 0x22210000 },
42};
43
44static struct wm_info i810_wm_16_100[] = {
45 { 15, 0x0070c000 }, { 19, 0x0020c000 }, { 25, 0x22006000 },
46 { 28, 0x22006000 }, { 31, 0x22007000 }, { 36, 0x22007000 },
47 { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22009000 },
48 { 50, 0x22009000 }, { 56, 0x22108000 }, { 65, 0x2210e000 },
49 { 75, 0x2210e000 }, { 78, 0x2210e000 }, { 80, 0x22210000 },
50 { 94, 0x22210000 }, { 96, 0x22210000 }, { 99, 0x22210000 },
51 { 108, 0x22210000 }, { 121, 0x22210000 }, { 128, 0x22210000 },
52 { 132, 0x22314000 }, { 135, 0x22314000 }, { 157, 0x22415000 },
53 { 162, 0x22416000 }, { 175, 0x22416000 }, { 189, 0x22416000 },
54 { 195, 0x22416000 }, { 202, 0x22416000 }, { 204, 0x22416000 },
55 { 218, 0x22416000 }, { 229, 0x22416000 },
56};
57
58static struct wm_info i810_wm_24_100[] = {
59 { 15, 0x0020c000 }, { 19, 0x0040c000 }, { 25, 0x22009000 },
60 { 28, 0x22009000 }, { 31, 0x2200a000 }, { 36, 0x2210c000 },
61 { 40, 0x2210c000 }, { 45, 0x2210c000 }, { 49, 0x22111000 },
62 { 50, 0x22111000 }, { 56, 0x22111000 }, { 65, 0x22214000 },
63 { 75, 0x22214000 }, { 78, 0x22215000 }, { 80, 0x22216000 },
64 { 94, 0x22218000 }, { 96, 0x22418000 }, { 99, 0x22418000 },
65 { 108, 0x22418000 }, { 121, 0x22418000 }, { 128, 0x22419000 },
66 { 132, 0x22519000 }, { 135, 0x4441d000 }, { 157, 0x44419000 },
67 { 162, 0x44419000 }, { 175, 0x44419000 }, { 189, 0x44419000 },
68 { 195, 0x44419000 }, { 202, 0x44419000 }, { 204, 0x44419000 },
69};
70
71static struct wm_info i810_wm_8_133[] = {
72 { 15, 0x0070c000 }, { 19, 0x0070c000 }, { 25, 0x22003000 },
73 { 28, 0x22003000 }, { 31, 0x22003000 }, { 36, 0x22007000 },
74 { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22008000 },
75 { 50, 0x22008000 }, { 56, 0x22008000 }, { 65, 0x22008000 },
76 { 75, 0x22008000 }, { 78, 0x22008000 }, { 80, 0x22008000 },
77 { 94, 0x22008000 }, { 96, 0x22107000 }, { 99, 0x22107000 },
78 { 108, 0x22107000 }, { 121, 0x22107000 }, { 128, 0x22107000 },
79 { 132, 0x22109000 }, { 135, 0x22109000 }, { 157, 0x2210b000 },
80 { 162, 0x2210b000 }, { 175, 0x2210b000 }, { 189, 0x2220e000 },
81 { 195, 0x2220e000 }, { 202, 0x2220e000 }, { 204, 0x2220e000 },
82 { 218, 0x2220f000 }, { 229, 0x22210000 }, { 234, 0x22210000 },
83};
84
85static struct wm_info i810_wm_16_133[] = {
86 { 15, 0x0020c000 }, { 19, 0x0020c000 }, { 25, 0x22006000 },
87 { 28, 0x22006000 }, { 31, 0x22007000 }, { 36, 0x22007000 },
88 { 40, 0x22007000 }, { 45, 0x22007000 }, { 49, 0x22009000 },
89 { 50, 0x22009000 }, { 56, 0x22108000 }, { 65, 0x2210e000 },
90 { 75, 0x2210e000 }, { 78, 0x2210e000 }, { 80, 0x22210000 },
91 { 94, 0x22210000 }, { 96, 0x22210000 }, { 99, 0x22210000 },
92 { 108, 0x22210000 }, { 121, 0x22210000 }, { 128, 0x22210000 },
93 { 132, 0x22314000 }, { 135, 0x22314000 }, { 157, 0x22415000 },
94 { 162, 0x22416000 }, { 175, 0x22416000 }, { 189, 0x22416000 },
95 { 195, 0x22416000 }, { 202, 0x22416000 }, { 204, 0x22416000 },
96 { 218, 0x22416000 }, { 229, 0x22416000 },
97};
98
99static struct wm_info i810_wm_24_133[] = {
100 { 15, 0x0020c000 }, { 19, 0x00408000 }, { 25, 0x22009000 },
101 { 28, 0x22009000 }, { 31, 0x2200a000 }, { 36, 0x2210c000 },
102 { 40, 0x2210c000 }, { 45, 0x2210c000 }, { 49, 0x22111000 },
103 { 50, 0x22111000 }, { 56, 0x22111000 }, { 65, 0x22214000 },
104 { 75, 0x22214000 }, { 78, 0x22215000 }, { 80, 0x22216000 },
105 { 94, 0x22218000 }, { 96, 0x22418000 }, { 99, 0x22418000 },
106 { 108, 0x22418000 }, { 121, 0x22418000 }, { 128, 0x22419000 },
107 { 132, 0x22519000 }, { 135, 0x4441d000 }, { 157, 0x44419000 },
108 { 162, 0x44419000 }, { 175, 0x44419000 }, { 189, 0x44419000 },
109 { 195, 0x44419000 }, { 202, 0x44419000 }, { 204, 0x44419000 },
110};
111
112void round_off_xres(u32 *xres) { }
113void round_off_yres(u32 *xres, u32 *yres) { }
114
115/**
116 * i810fb_encode_registers - encode @var to hardware register values
117 * @var: pointer to var structure
118 * @par: pointer to hardware par structure
119 *
120 * DESCRIPTION:
121 * Timing values in @var will be converted to appropriate
122 * register values of @par.
123 */
124void i810fb_encode_registers(const struct fb_var_screeninfo *var,
125 struct i810fb_par *par, u32 xres, u32 yres)
126{
127 int n, blank_s, blank_e;
128 u8 __iomem *mmio = par->mmio_start_virtual;
129 u8 msr = 0;
130
131 /* Horizontal */
132 /* htotal */
133 n = ((xres + var->right_margin + var->hsync_len +
134 var->left_margin) >> 3) - 5;
135 par->regs.cr00 = (u8) n;
136 par->regs.cr35 = (u8) ((n >> 8) & 1);
137
138 /* xres */
139 par->regs.cr01 = (u8) ((xres >> 3) - 1);
140
141 /* hblank */
142 blank_e = (xres + var->right_margin + var->hsync_len +
143 var->left_margin) >> 3;
144 blank_e--;
145 blank_s = blank_e - 127;
146 if (blank_s < (xres >> 3))
147 blank_s = xres >> 3;
148 par->regs.cr02 = (u8) blank_s;
149 par->regs.cr03 = (u8) (blank_e & 0x1F);
150 par->regs.cr05 = (u8) ((blank_e & (1 << 5)) << 2);
151 par->regs.cr39 = (u8) ((blank_e >> 6) & 1);
152
153 /* hsync */
154 par->regs.cr04 = (u8) ((xres + var->right_margin) >> 3);
155 par->regs.cr05 |= (u8) (((xres + var->right_margin +
156 var->hsync_len) >> 3) & 0x1F);
157
158 /* Vertical */
159 /* vtotal */
160 n = yres + var->lower_margin + var->vsync_len + var->upper_margin - 2;
161 par->regs.cr06 = (u8) (n & 0xFF);
162 par->regs.cr30 = (u8) ((n >> 8) & 0x0F);
163
164 /* vsync */
165 n = yres + var->lower_margin;
166 par->regs.cr10 = (u8) (n & 0xFF);
167 par->regs.cr32 = (u8) ((n >> 8) & 0x0F);
168 par->regs.cr11 = i810_readb(CR11, mmio) & ~0x0F;
169 par->regs.cr11 |= (u8) ((yres + var->lower_margin +
170 var->vsync_len) & 0x0F);
171
172 /* yres */
173 n = yres - 1;
174 par->regs.cr12 = (u8) (n & 0xFF);
175 par->regs.cr31 = (u8) ((n >> 8) & 0x0F);
176
177 /* vblank */
178 blank_e = yres + var->lower_margin + var->vsync_len +
179 var->upper_margin;
180 blank_e--;
181 blank_s = blank_e - 127;
182 if (blank_s < yres)
183 blank_s = yres;
184 par->regs.cr15 = (u8) (blank_s & 0xFF);
185 par->regs.cr33 = (u8) ((blank_s >> 8) & 0x0F);
186 par->regs.cr16 = (u8) (blank_e & 0xFF);
187 par->regs.cr09 = 0;
188
189 /* sync polarity */
190 if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
191 msr |= 1 << 6;
192 if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
193 msr |= 1 << 7;
194 par->regs.msr = msr;
195
196 /* interlace */
197 if (var->vmode & FB_VMODE_INTERLACED)
198 par->interlace = (1 << 7) | ((u8) (var->yres >> 4));
199 else
200 par->interlace = 0;
201
202 if (var->vmode & FB_VMODE_DOUBLE)
203 par->regs.cr09 |= 1 << 7;
204
205 /* overlay */
206 par->ovract = ((var->xres + var->right_margin + var->hsync_len +
207 var->left_margin - 32) | ((var->xres - 32) << 16));
208}
209
210void i810fb_fill_var_timings(struct fb_var_screeninfo *var) { }
211
212/**
213 * i810_get_watermark - gets watermark
214 * @var: pointer to fb_var_screeninfo
215 * @par: pointer to i810fb_par structure
216 *
217 * DESCRIPTION:
218 * Gets the required watermark based on
219 * pixelclock and RAMBUS frequency.
220 *
221 * RETURNS:
222 * watermark
223 */
224u32 i810_get_watermark(const struct fb_var_screeninfo *var,
225 struct i810fb_par *par)
226{
227 struct wm_info *wmark = NULL;
228 u32 i, size = 0, pixclock, wm_best = 0, min, diff;
229
230 if (par->mem_freq == 100) {
231 switch (var->bits_per_pixel) {
232 case 8:
233 wmark = i810_wm_8_100;
234 size = ARRAY_SIZE(i810_wm_8_100);
235 break;
236 case 16:
237 wmark = i810_wm_16_100;
238 size = ARRAY_SIZE(i810_wm_16_100);
239 break;
240 case 24:
241 case 32:
242 wmark = i810_wm_24_100;
243 size = ARRAY_SIZE(i810_wm_24_100);
244 }
245 } else {
246 switch(var->bits_per_pixel) {
247 case 8:
248 wmark = i810_wm_8_133;
249 size = ARRAY_SIZE(i810_wm_8_133);
250 break;
251 case 16:
252 wmark = i810_wm_16_133;
253 size = ARRAY_SIZE(i810_wm_16_133);
254 break;
255 case 24:
256 case 32:
257 wmark = i810_wm_24_133;
258 size = ARRAY_SIZE(i810_wm_24_133);
259 }
260 }
261
262 pixclock = 1000000/var->pixclock;
263 min = ~0;
264 for (i = 0; i < size; i++) {
265 if (pixclock <= wmark[i].freq)
266 diff = wmark[i].freq - pixclock;
267 else
268 diff = pixclock - wmark[i].freq;
269 if (diff < min) {
270 wm_best = wmark[i].wm;
271 min = diff;
272 }
273 }
274 return wm_best;
275}
276
diff --git a/drivers/video/fbdev/i810/i810_main.c b/drivers/video/fbdev/i810/i810_main.c
new file mode 100644
index 000000000000..bb674e431741
--- /dev/null
+++ b/drivers/video/fbdev/i810/i810_main.c
@@ -0,0 +1,2218 @@
1 /*-*- linux-c -*-
2 * linux/drivers/video/i810_main.c -- Intel 810 frame buffer device
3 *
4 * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
5 * All Rights Reserved
6 *
7 * Contributors:
8 * Michael Vogt <mvogt@acm.org> - added support for Intel 815 chipsets
9 * and enabling the power-on state of
10 * external VGA connectors for
11 * secondary displays
12 *
13 * Fredrik Andersson <krueger@shell.linux.se> - alpha testing of
14 * the VESA GTF
15 *
16 * Brad Corrion <bcorrion@web-co.com> - alpha testing of customized
17 * timings support
18 *
19 * The code framework is a modification of vfb.c by Geert Uytterhoeven.
20 * DotClock and PLL calculations are partly based on i810_driver.c
21 * in xfree86 v4.0.3 by Precision Insight.
22 * Watermark calculation and tables are based on i810_wmark.c
23 * in xfre86 v4.0.3 by Precision Insight. Slight modifications
24 * only to allow for integer operations instead of floating point.
25 *
26 * This file is subject to the terms and conditions of the GNU General Public
27 * License. See the file COPYING in the main directory of this archive for
28 * more details.
29 */
30
31#include <linux/module.h>
32#include <linux/kernel.h>
33#include <linux/errno.h>
34#include <linux/string.h>
35#include <linux/mm.h>
36#include <linux/slab.h>
37#include <linux/fb.h>
38#include <linux/init.h>
39#include <linux/pci.h>
40#include <linux/pci_ids.h>
41#include <linux/resource.h>
42#include <linux/unistd.h>
43#include <linux/console.h>
44
45#include <asm/io.h>
46#include <asm/div64.h>
47#include <asm/page.h>
48
49#include "i810_regs.h"
50#include "i810.h"
51#include "i810_main.h"
52
53/*
54 * voffset - framebuffer offset in MiB from aperture start address. In order for
55 * the driver to work with X, we must try to use memory holes left untouched by X. The
56 * following table lists where X's different surfaces start at.
57 *
58 * ---------------------------------------------
59 * : : 64 MiB : 32 MiB :
60 * ----------------------------------------------
61 * : FrontBuffer : 0 : 0 :
62 * : DepthBuffer : 48 : 16 :
63 * : BackBuffer : 56 : 24 :
64 * ----------------------------------------------
65 *
66 * So for chipsets with 64 MiB Aperture sizes, 32 MiB for v_offset is okay, allowing up to
67 * 15 + 1 MiB of Framebuffer memory. For 32 MiB Aperture sizes, a v_offset of 8 MiB should
68 * work, allowing 7 + 1 MiB of Framebuffer memory.
69 * Note, the size of the hole may change depending on how much memory you allocate to X,
70 * and how the memory is split up between these surfaces.
71 *
72 * Note: Anytime the DepthBuffer or FrontBuffer is overlapped, X would still run but with
73 * DRI disabled. But if the Frontbuffer is overlapped, X will fail to load.
74 *
75 * Experiment with v_offset to find out which works best for you.
76 */
77static u32 v_offset_default; /* For 32 MiB Aper size, 8 should be the default */
78static u32 voffset;
79
80static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor);
81static int i810fb_init_pci(struct pci_dev *dev,
82 const struct pci_device_id *entry);
83static void __exit i810fb_remove_pci(struct pci_dev *dev);
84static int i810fb_resume(struct pci_dev *dev);
85static int i810fb_suspend(struct pci_dev *dev, pm_message_t state);
86
87/* Chipset Specific Functions */
88static int i810fb_set_par (struct fb_info *info);
89static int i810fb_getcolreg (u8 regno, u8 *red, u8 *green, u8 *blue,
90 u8 *transp, struct fb_info *info);
91static int i810fb_setcolreg (unsigned regno, unsigned red, unsigned green, unsigned blue,
92 unsigned transp, struct fb_info *info);
93static int i810fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
94static int i810fb_blank (int blank_mode, struct fb_info *info);
95
96/* Initialization */
97static void i810fb_release_resource (struct fb_info *info, struct i810fb_par *par);
98
99/* PCI */
100static const char * const i810_pci_list[] = {
101 "Intel(R) 810 Framebuffer Device" ,
102 "Intel(R) 810-DC100 Framebuffer Device" ,
103 "Intel(R) 810E Framebuffer Device" ,
104 "Intel(R) 815 (Internal Graphics 100Mhz FSB) Framebuffer Device" ,
105 "Intel(R) 815 (Internal Graphics only) Framebuffer Device" ,
106 "Intel(R) 815 (Internal Graphics with AGP) Framebuffer Device"
107};
108
109static struct pci_device_id i810fb_pci_tbl[] = {
110 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG1,
111 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
112 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3,
113 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
114 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810E_IG,
115 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
116 /* mvo: added i815 PCI-ID */
117 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_100,
118 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
119 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_NOAGP,
120 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
121 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC,
122 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
123 { 0 },
124};
125
126static struct pci_driver i810fb_driver = {
127 .name = "i810fb",
128 .id_table = i810fb_pci_tbl,
129 .probe = i810fb_init_pci,
130 .remove = __exit_p(i810fb_remove_pci),
131 .suspend = i810fb_suspend,
132 .resume = i810fb_resume,
133};
134
135static char *mode_option = NULL;
136static int vram = 4;
137static int bpp = 8;
138static bool mtrr;
139static bool accel;
140static int hsync1;
141static int hsync2;
142static int vsync1;
143static int vsync2;
144static int xres;
145static int yres;
146static int vyres;
147static bool sync;
148static bool extvga;
149static bool dcolor;
150static bool ddc3;
151
152/*------------------------------------------------------------*/
153
154/**************************************************************
155 * Hardware Low Level Routines *
156 **************************************************************/
157
158/**
159 * i810_screen_off - turns off/on display
160 * @mmio: address of register space
161 * @mode: on or off
162 *
163 * DESCRIPTION:
164 * Blanks/unblanks the display
165 */
166static void i810_screen_off(u8 __iomem *mmio, u8 mode)
167{
168 u32 count = WAIT_COUNT;
169 u8 val;
170
171 i810_writeb(SR_INDEX, mmio, SR01);
172 val = i810_readb(SR_DATA, mmio);
173 val = (mode == OFF) ? val | SCR_OFF :
174 val & ~SCR_OFF;
175
176 while((i810_readw(DISP_SL, mmio) & 0xFFF) && count--);
177 i810_writeb(SR_INDEX, mmio, SR01);
178 i810_writeb(SR_DATA, mmio, val);
179}
180
181/**
182 * i810_dram_off - turns off/on dram refresh
183 * @mmio: address of register space
184 * @mode: on or off
185 *
186 * DESCRIPTION:
187 * Turns off DRAM refresh. Must be off for only 2 vsyncs
188 * before data becomes corrupt
189 */
190static void i810_dram_off(u8 __iomem *mmio, u8 mode)
191{
192 u8 val;
193
194 val = i810_readb(DRAMCH, mmio);
195 val &= DRAM_OFF;
196 val = (mode == OFF) ? val : val | DRAM_ON;
197 i810_writeb(DRAMCH, mmio, val);
198}
199
200/**
201 * i810_protect_regs - allows rw/ro mode of certain VGA registers
202 * @mmio: address of register space
203 * @mode: protect/unprotect
204 *
205 * DESCRIPTION:
206 * The IBM VGA standard allows protection of certain VGA registers.
207 * This will protect or unprotect them.
208 */
209static void i810_protect_regs(u8 __iomem *mmio, int mode)
210{
211 u8 reg;
212
213 i810_writeb(CR_INDEX_CGA, mmio, CR11);
214 reg = i810_readb(CR_DATA_CGA, mmio);
215 reg = (mode == OFF) ? reg & ~0x80 :
216 reg | 0x80;
217
218 i810_writeb(CR_INDEX_CGA, mmio, CR11);
219 i810_writeb(CR_DATA_CGA, mmio, reg);
220}
221
222/**
223 * i810_load_pll - loads values for the hardware PLL clock
224 * @par: pointer to i810fb_par structure
225 *
226 * DESCRIPTION:
227 * Loads the P, M, and N registers.
228 */
229static void i810_load_pll(struct i810fb_par *par)
230{
231 u32 tmp1, tmp2;
232 u8 __iomem *mmio = par->mmio_start_virtual;
233
234 tmp1 = par->regs.M | par->regs.N << 16;
235 tmp2 = i810_readl(DCLK_2D, mmio);
236 tmp2 &= ~MN_MASK;
237 i810_writel(DCLK_2D, mmio, tmp1 | tmp2);
238
239 tmp1 = par->regs.P;
240 tmp2 = i810_readl(DCLK_0DS, mmio);
241 tmp2 &= ~(P_OR << 16);
242 i810_writel(DCLK_0DS, mmio, (tmp1 << 16) | tmp2);
243
244 i810_writeb(MSR_WRITE, mmio, par->regs.msr | 0xC8 | 1);
245
246}
247
248/**
249 * i810_load_vga - load standard VGA registers
250 * @par: pointer to i810fb_par structure
251 *
252 * DESCRIPTION:
253 * Load values to VGA registers
254 */
255static void i810_load_vga(struct i810fb_par *par)
256{
257 u8 __iomem *mmio = par->mmio_start_virtual;
258
259 /* interlace */
260 i810_writeb(CR_INDEX_CGA, mmio, CR70);
261 i810_writeb(CR_DATA_CGA, mmio, par->interlace);
262
263 i810_writeb(CR_INDEX_CGA, mmio, CR00);
264 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr00);
265 i810_writeb(CR_INDEX_CGA, mmio, CR01);
266 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr01);
267 i810_writeb(CR_INDEX_CGA, mmio, CR02);
268 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr02);
269 i810_writeb(CR_INDEX_CGA, mmio, CR03);
270 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr03);
271 i810_writeb(CR_INDEX_CGA, mmio, CR04);
272 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr04);
273 i810_writeb(CR_INDEX_CGA, mmio, CR05);
274 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr05);
275 i810_writeb(CR_INDEX_CGA, mmio, CR06);
276 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr06);
277 i810_writeb(CR_INDEX_CGA, mmio, CR09);
278 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr09);
279 i810_writeb(CR_INDEX_CGA, mmio, CR10);
280 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr10);
281 i810_writeb(CR_INDEX_CGA, mmio, CR11);
282 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr11);
283 i810_writeb(CR_INDEX_CGA, mmio, CR12);
284 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr12);
285 i810_writeb(CR_INDEX_CGA, mmio, CR15);
286 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr15);
287 i810_writeb(CR_INDEX_CGA, mmio, CR16);
288 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr16);
289}
290
291/**
292 * i810_load_vgax - load extended VGA registers
293 * @par: pointer to i810fb_par structure
294 *
295 * DESCRIPTION:
296 * Load values to extended VGA registers
297 */
298static void i810_load_vgax(struct i810fb_par *par)
299{
300 u8 __iomem *mmio = par->mmio_start_virtual;
301
302 i810_writeb(CR_INDEX_CGA, mmio, CR30);
303 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr30);
304 i810_writeb(CR_INDEX_CGA, mmio, CR31);
305 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr31);
306 i810_writeb(CR_INDEX_CGA, mmio, CR32);
307 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr32);
308 i810_writeb(CR_INDEX_CGA, mmio, CR33);
309 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr33);
310 i810_writeb(CR_INDEX_CGA, mmio, CR35);
311 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr35);
312 i810_writeb(CR_INDEX_CGA, mmio, CR39);
313 i810_writeb(CR_DATA_CGA, mmio, par->regs.cr39);
314}
315
316/**
317 * i810_load_2d - load grahics registers
318 * @par: pointer to i810fb_par structure
319 *
320 * DESCRIPTION:
321 * Load values to graphics registers
322 */
323static void i810_load_2d(struct i810fb_par *par)
324{
325 u32 tmp;
326 u8 tmp8;
327 u8 __iomem *mmio = par->mmio_start_virtual;
328
329 i810_writel(FW_BLC, mmio, par->watermark);
330 tmp = i810_readl(PIXCONF, mmio);
331 tmp |= 1 | 1 << 20;
332 i810_writel(PIXCONF, mmio, tmp);
333
334 i810_writel(OVRACT, mmio, par->ovract);
335
336 i810_writeb(GR_INDEX, mmio, GR10);
337 tmp8 = i810_readb(GR_DATA, mmio);
338 tmp8 |= 2;
339 i810_writeb(GR_INDEX, mmio, GR10);
340 i810_writeb(GR_DATA, mmio, tmp8);
341}
342
343/**
344 * i810_hires - enables high resolution mode
345 * @mmio: address of register space
346 */
347static void i810_hires(u8 __iomem *mmio)
348{
349 u8 val;
350
351 i810_writeb(CR_INDEX_CGA, mmio, CR80);
352 val = i810_readb(CR_DATA_CGA, mmio);
353 i810_writeb(CR_INDEX_CGA, mmio, CR80);
354 i810_writeb(CR_DATA_CGA, mmio, val | 1);
355 /* Stop LCD displays from flickering */
356 i810_writel(MEM_MODE, mmio, i810_readl(MEM_MODE, mmio) | 4);
357}
358
359/**
360 * i810_load_pitch - loads the characters per line of the display
361 * @par: pointer to i810fb_par structure
362 *
363 * DESCRIPTION:
364 * Loads the characters per line
365 */
366static void i810_load_pitch(struct i810fb_par *par)
367{
368 u32 tmp, pitch;
369 u8 val;
370 u8 __iomem *mmio = par->mmio_start_virtual;
371
372 pitch = par->pitch >> 3;
373 i810_writeb(SR_INDEX, mmio, SR01);
374 val = i810_readb(SR_DATA, mmio);
375 val &= 0xE0;
376 val |= 1 | 1 << 2;
377 i810_writeb(SR_INDEX, mmio, SR01);
378 i810_writeb(SR_DATA, mmio, val);
379
380 tmp = pitch & 0xFF;
381 i810_writeb(CR_INDEX_CGA, mmio, CR13);
382 i810_writeb(CR_DATA_CGA, mmio, (u8) tmp);
383
384 tmp = pitch >> 8;
385 i810_writeb(CR_INDEX_CGA, mmio, CR41);
386 val = i810_readb(CR_DATA_CGA, mmio) & ~0x0F;
387 i810_writeb(CR_INDEX_CGA, mmio, CR41);
388 i810_writeb(CR_DATA_CGA, mmio, (u8) tmp | val);
389}
390
391/**
392 * i810_load_color - loads the color depth of the display
393 * @par: pointer to i810fb_par structure
394 *
395 * DESCRIPTION:
396 * Loads the color depth of the display and the graphics engine
397 */
398static void i810_load_color(struct i810fb_par *par)
399{
400 u8 __iomem *mmio = par->mmio_start_virtual;
401 u32 reg1;
402 u16 reg2;
403
404 reg1 = i810_readl(PIXCONF, mmio) & ~(0xF0000 | 1 << 27);
405 reg2 = i810_readw(BLTCNTL, mmio) & ~0x30;
406
407 reg1 |= 0x8000 | par->pixconf;
408 reg2 |= par->bltcntl;
409 i810_writel(PIXCONF, mmio, reg1);
410 i810_writew(BLTCNTL, mmio, reg2);
411}
412
413/**
414 * i810_load_regs - loads all registers for the mode
415 * @par: pointer to i810fb_par structure
416 *
417 * DESCRIPTION:
418 * Loads registers
419 */
420static void i810_load_regs(struct i810fb_par *par)
421{
422 u8 __iomem *mmio = par->mmio_start_virtual;
423
424 i810_screen_off(mmio, OFF);
425 i810_protect_regs(mmio, OFF);
426 i810_dram_off(mmio, OFF);
427 i810_load_pll(par);
428 i810_load_vga(par);
429 i810_load_vgax(par);
430 i810_dram_off(mmio, ON);
431 i810_load_2d(par);
432 i810_hires(mmio);
433 i810_screen_off(mmio, ON);
434 i810_protect_regs(mmio, ON);
435 i810_load_color(par);
436 i810_load_pitch(par);
437}
438
439static void i810_write_dac(u8 regno, u8 red, u8 green, u8 blue,
440 u8 __iomem *mmio)
441{
442 i810_writeb(CLUT_INDEX_WRITE, mmio, regno);
443 i810_writeb(CLUT_DATA, mmio, red);
444 i810_writeb(CLUT_DATA, mmio, green);
445 i810_writeb(CLUT_DATA, mmio, blue);
446}
447
448static void i810_read_dac(u8 regno, u8 *red, u8 *green, u8 *blue,
449 u8 __iomem *mmio)
450{
451 i810_writeb(CLUT_INDEX_READ, mmio, regno);
452 *red = i810_readb(CLUT_DATA, mmio);
453 *green = i810_readb(CLUT_DATA, mmio);
454 *blue = i810_readb(CLUT_DATA, mmio);
455}
456
457/************************************************************
458 * VGA State Restore *
459 ************************************************************/
460static void i810_restore_pll(struct i810fb_par *par)
461{
462 u32 tmp1, tmp2;
463 u8 __iomem *mmio = par->mmio_start_virtual;
464
465 tmp1 = par->hw_state.dclk_2d;
466 tmp2 = i810_readl(DCLK_2D, mmio);
467 tmp1 &= ~MN_MASK;
468 tmp2 &= MN_MASK;
469 i810_writel(DCLK_2D, mmio, tmp1 | tmp2);
470
471 tmp1 = par->hw_state.dclk_1d;
472 tmp2 = i810_readl(DCLK_1D, mmio);
473 tmp1 &= ~MN_MASK;
474 tmp2 &= MN_MASK;
475 i810_writel(DCLK_1D, mmio, tmp1 | tmp2);
476
477 i810_writel(DCLK_0DS, mmio, par->hw_state.dclk_0ds);
478}
479
480static void i810_restore_dac(struct i810fb_par *par)
481{
482 u32 tmp1, tmp2;
483 u8 __iomem *mmio = par->mmio_start_virtual;
484
485 tmp1 = par->hw_state.pixconf;
486 tmp2 = i810_readl(PIXCONF, mmio);
487 tmp1 &= DAC_BIT;
488 tmp2 &= ~DAC_BIT;
489 i810_writel(PIXCONF, mmio, tmp1 | tmp2);
490}
491
492static void i810_restore_vgax(struct i810fb_par *par)
493{
494 u8 i, j;
495 u8 __iomem *mmio = par->mmio_start_virtual;
496
497 for (i = 0; i < 4; i++) {
498 i810_writeb(CR_INDEX_CGA, mmio, CR30+i);
499 i810_writeb(CR_DATA_CGA, mmio, *(&(par->hw_state.cr30) + i));
500 }
501 i810_writeb(CR_INDEX_CGA, mmio, CR35);
502 i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr35);
503 i810_writeb(CR_INDEX_CGA, mmio, CR39);
504 i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr39);
505 i810_writeb(CR_INDEX_CGA, mmio, CR41);
506 i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr39);
507
508 /*restore interlace*/
509 i810_writeb(CR_INDEX_CGA, mmio, CR70);
510 i = par->hw_state.cr70;
511 i &= INTERLACE_BIT;
512 j = i810_readb(CR_DATA_CGA, mmio);
513 i810_writeb(CR_INDEX_CGA, mmio, CR70);
514 i810_writeb(CR_DATA_CGA, mmio, j | i);
515
516 i810_writeb(CR_INDEX_CGA, mmio, CR80);
517 i810_writeb(CR_DATA_CGA, mmio, par->hw_state.cr80);
518 i810_writeb(MSR_WRITE, mmio, par->hw_state.msr);
519 i810_writeb(SR_INDEX, mmio, SR01);
520 i = (par->hw_state.sr01) & ~0xE0 ;
521 j = i810_readb(SR_DATA, mmio) & 0xE0;
522 i810_writeb(SR_INDEX, mmio, SR01);
523 i810_writeb(SR_DATA, mmio, i | j);
524}
525
526static void i810_restore_vga(struct i810fb_par *par)
527{
528 u8 i;
529 u8 __iomem *mmio = par->mmio_start_virtual;
530
531 for (i = 0; i < 10; i++) {
532 i810_writeb(CR_INDEX_CGA, mmio, CR00 + i);
533 i810_writeb(CR_DATA_CGA, mmio, *((&par->hw_state.cr00) + i));
534 }
535 for (i = 0; i < 8; i++) {
536 i810_writeb(CR_INDEX_CGA, mmio, CR10 + i);
537 i810_writeb(CR_DATA_CGA, mmio, *((&par->hw_state.cr10) + i));
538 }
539}
540
541static void i810_restore_addr_map(struct i810fb_par *par)
542{
543 u8 tmp;
544 u8 __iomem *mmio = par->mmio_start_virtual;
545
546 i810_writeb(GR_INDEX, mmio, GR10);
547 tmp = i810_readb(GR_DATA, mmio);
548 tmp &= ADDR_MAP_MASK;
549 tmp |= par->hw_state.gr10;
550 i810_writeb(GR_INDEX, mmio, GR10);
551 i810_writeb(GR_DATA, mmio, tmp);
552}
553
554static void i810_restore_2d(struct i810fb_par *par)
555{
556 u32 tmp_long;
557 u16 tmp_word;
558 u8 __iomem *mmio = par->mmio_start_virtual;
559
560 tmp_word = i810_readw(BLTCNTL, mmio);
561 tmp_word &= ~(3 << 4);
562 tmp_word |= par->hw_state.bltcntl;
563 i810_writew(BLTCNTL, mmio, tmp_word);
564
565 i810_dram_off(mmio, OFF);
566 i810_writel(PIXCONF, mmio, par->hw_state.pixconf);
567 i810_dram_off(mmio, ON);
568
569 tmp_word = i810_readw(HWSTAM, mmio);
570 tmp_word &= 3 << 13;
571 tmp_word |= par->hw_state.hwstam;
572 i810_writew(HWSTAM, mmio, tmp_word);
573
574 tmp_long = i810_readl(FW_BLC, mmio);
575 tmp_long &= FW_BLC_MASK;
576 tmp_long |= par->hw_state.fw_blc;
577 i810_writel(FW_BLC, mmio, tmp_long);
578
579 i810_writel(HWS_PGA, mmio, par->hw_state.hws_pga);
580 i810_writew(IER, mmio, par->hw_state.ier);
581 i810_writew(IMR, mmio, par->hw_state.imr);
582 i810_writel(DPLYSTAS, mmio, par->hw_state.dplystas);
583}
584
585static void i810_restore_vga_state(struct i810fb_par *par)
586{
587 u8 __iomem *mmio = par->mmio_start_virtual;
588
589 i810_screen_off(mmio, OFF);
590 i810_protect_regs(mmio, OFF);
591 i810_dram_off(mmio, OFF);
592 i810_restore_pll(par);
593 i810_restore_dac(par);
594 i810_restore_vga(par);
595 i810_restore_vgax(par);
596 i810_restore_addr_map(par);
597 i810_dram_off(mmio, ON);
598 i810_restore_2d(par);
599 i810_screen_off(mmio, ON);
600 i810_protect_regs(mmio, ON);
601}
602
603/***********************************************************************
604 * VGA State Save *
605 ***********************************************************************/
606
607static void i810_save_vgax(struct i810fb_par *par)
608{
609 u8 i;
610 u8 __iomem *mmio = par->mmio_start_virtual;
611
612 for (i = 0; i < 4; i++) {
613 i810_writeb(CR_INDEX_CGA, mmio, CR30 + i);
614 *(&(par->hw_state.cr30) + i) = i810_readb(CR_DATA_CGA, mmio);
615 }
616 i810_writeb(CR_INDEX_CGA, mmio, CR35);
617 par->hw_state.cr35 = i810_readb(CR_DATA_CGA, mmio);
618 i810_writeb(CR_INDEX_CGA, mmio, CR39);
619 par->hw_state.cr39 = i810_readb(CR_DATA_CGA, mmio);
620 i810_writeb(CR_INDEX_CGA, mmio, CR41);
621 par->hw_state.cr41 = i810_readb(CR_DATA_CGA, mmio);
622 i810_writeb(CR_INDEX_CGA, mmio, CR70);
623 par->hw_state.cr70 = i810_readb(CR_DATA_CGA, mmio);
624 par->hw_state.msr = i810_readb(MSR_READ, mmio);
625 i810_writeb(CR_INDEX_CGA, mmio, CR80);
626 par->hw_state.cr80 = i810_readb(CR_DATA_CGA, mmio);
627 i810_writeb(SR_INDEX, mmio, SR01);
628 par->hw_state.sr01 = i810_readb(SR_DATA, mmio);
629}
630
631static void i810_save_vga(struct i810fb_par *par)
632{
633 u8 i;
634 u8 __iomem *mmio = par->mmio_start_virtual;
635
636 for (i = 0; i < 10; i++) {
637 i810_writeb(CR_INDEX_CGA, mmio, CR00 + i);
638 *((&par->hw_state.cr00) + i) = i810_readb(CR_DATA_CGA, mmio);
639 }
640 for (i = 0; i < 8; i++) {
641 i810_writeb(CR_INDEX_CGA, mmio, CR10 + i);
642 *((&par->hw_state.cr10) + i) = i810_readb(CR_DATA_CGA, mmio);
643 }
644}
645
646static void i810_save_2d(struct i810fb_par *par)
647{
648 u8 __iomem *mmio = par->mmio_start_virtual;
649
650 par->hw_state.dclk_2d = i810_readl(DCLK_2D, mmio);
651 par->hw_state.dclk_1d = i810_readl(DCLK_1D, mmio);
652 par->hw_state.dclk_0ds = i810_readl(DCLK_0DS, mmio);
653 par->hw_state.pixconf = i810_readl(PIXCONF, mmio);
654 par->hw_state.fw_blc = i810_readl(FW_BLC, mmio);
655 par->hw_state.bltcntl = i810_readw(BLTCNTL, mmio);
656 par->hw_state.hwstam = i810_readw(HWSTAM, mmio);
657 par->hw_state.hws_pga = i810_readl(HWS_PGA, mmio);
658 par->hw_state.ier = i810_readw(IER, mmio);
659 par->hw_state.imr = i810_readw(IMR, mmio);
660 par->hw_state.dplystas = i810_readl(DPLYSTAS, mmio);
661}
662
663static void i810_save_vga_state(struct i810fb_par *par)
664{
665 i810_save_vga(par);
666 i810_save_vgax(par);
667 i810_save_2d(par);
668}
669
670/************************************************************
671 * Helpers *
672 ************************************************************/
673/**
674 * get_line_length - calculates buffer pitch in bytes
675 * @par: pointer to i810fb_par structure
676 * @xres_virtual: virtual resolution of the frame
677 * @bpp: bits per pixel
678 *
679 * DESCRIPTION:
680 * Calculates buffer pitch in bytes.
681 */
682static u32 get_line_length(struct i810fb_par *par, int xres_virtual, int bpp)
683{
684 u32 length;
685
686 length = xres_virtual*bpp;
687 length = (length+31)&-32;
688 length >>= 3;
689 return length;
690}
691
692/**
693 * i810_calc_dclk - calculates the P, M, and N values of a pixelclock value
694 * @freq: target pixelclock in picoseconds
695 * @m: where to write M register
696 * @n: where to write N register
697 * @p: where to write P register
698 *
699 * DESCRIPTION:
700 * Based on the formula Freq_actual = (4*M*Freq_ref)/(N^P)
701 * Repeatedly computes the Freq until the actual Freq is equal to
702 * the target Freq or until the loop count is zero. In the latter
703 * case, the actual frequency nearest the target will be used.
704 */
705static void i810_calc_dclk(u32 freq, u32 *m, u32 *n, u32 *p)
706{
707 u32 m_reg, n_reg, p_divisor, n_target_max;
708 u32 m_target, n_target, p_target, n_best, m_best, mod;
709 u32 f_out, target_freq, diff = 0, mod_min, diff_min;
710
711 diff_min = mod_min = 0xFFFFFFFF;
712 n_best = m_best = m_target = f_out = 0;
713
714 target_freq = freq;
715 n_target_max = 30;
716
717 /*
718 * find P such that target freq is 16x reference freq (Hz).
719 */
720 p_divisor = 1;
721 p_target = 0;
722 while(!((1000000 * p_divisor)/(16 * 24 * target_freq)) &&
723 p_divisor <= 32) {
724 p_divisor <<= 1;
725 p_target++;
726 }
727
728 n_reg = m_reg = n_target = 3;
729 while (diff_min && mod_min && (n_target < n_target_max)) {
730 f_out = (p_divisor * n_reg * 1000000)/(4 * 24 * m_reg);
731 mod = (p_divisor * n_reg * 1000000) % (4 * 24 * m_reg);
732 m_target = m_reg;
733 n_target = n_reg;
734 if (f_out <= target_freq) {
735 n_reg++;
736 diff = target_freq - f_out;
737 } else {
738 m_reg++;
739 diff = f_out - target_freq;
740 }
741
742 if (diff_min > diff) {
743 diff_min = diff;
744 n_best = n_target;
745 m_best = m_target;
746 }
747
748 if (!diff && mod_min > mod) {
749 mod_min = mod;
750 n_best = n_target;
751 m_best = m_target;
752 }
753 }
754 if (m) *m = (m_best - 2) & 0x3FF;
755 if (n) *n = (n_best - 2) & 0x3FF;
756 if (p) *p = (p_target << 4);
757}
758
759/*************************************************************
760 * Hardware Cursor Routines *
761 *************************************************************/
762
763/**
764 * i810_enable_cursor - show or hide the hardware cursor
765 * @mmio: address of register space
766 * @mode: show (1) or hide (0)
767 *
768 * Description:
769 * Shows or hides the hardware cursor
770 */
771static void i810_enable_cursor(u8 __iomem *mmio, int mode)
772{
773 u32 temp;
774
775 temp = i810_readl(PIXCONF, mmio);
776 temp = (mode == ON) ? temp | CURSOR_ENABLE_MASK :
777 temp & ~CURSOR_ENABLE_MASK;
778
779 i810_writel(PIXCONF, mmio, temp);
780}
781
782static void i810_reset_cursor_image(struct i810fb_par *par)
783{
784 u8 __iomem *addr = par->cursor_heap.virtual;
785 int i, j;
786
787 for (i = 64; i--; ) {
788 for (j = 0; j < 8; j++) {
789 i810_writeb(j, addr, 0xff);
790 i810_writeb(j+8, addr, 0x00);
791 }
792 addr +=16;
793 }
794}
795
796static void i810_load_cursor_image(int width, int height, u8 *data,
797 struct i810fb_par *par)
798{
799 u8 __iomem *addr = par->cursor_heap.virtual;
800 int i, j, w = width/8;
801 int mod = width % 8, t_mask, d_mask;
802
803 t_mask = 0xff >> mod;
804 d_mask = ~(0xff >> mod);
805 for (i = height; i--; ) {
806 for (j = 0; j < w; j++) {
807 i810_writeb(j+0, addr, 0x00);
808 i810_writeb(j+8, addr, *data++);
809 }
810 if (mod) {
811 i810_writeb(j+0, addr, t_mask);
812 i810_writeb(j+8, addr, *data++ & d_mask);
813 }
814 addr += 16;
815 }
816}
817
818static void i810_load_cursor_colors(int fg, int bg, struct fb_info *info)
819{
820 struct i810fb_par *par = info->par;
821 u8 __iomem *mmio = par->mmio_start_virtual;
822 u8 red, green, blue, trans, temp;
823
824 i810fb_getcolreg(bg, &red, &green, &blue, &trans, info);
825
826 temp = i810_readb(PIXCONF1, mmio);
827 i810_writeb(PIXCONF1, mmio, temp | EXTENDED_PALETTE);
828
829 i810_write_dac(4, red, green, blue, mmio);
830
831 i810_writeb(PIXCONF1, mmio, temp);
832
833 i810fb_getcolreg(fg, &red, &green, &blue, &trans, info);
834 temp = i810_readb(PIXCONF1, mmio);
835 i810_writeb(PIXCONF1, mmio, temp | EXTENDED_PALETTE);
836
837 i810_write_dac(5, red, green, blue, mmio);
838
839 i810_writeb(PIXCONF1, mmio, temp);
840}
841
842/**
843 * i810_init_cursor - initializes the cursor
844 * @par: pointer to i810fb_par structure
845 *
846 * DESCRIPTION:
847 * Initializes the cursor registers
848 */
849static void i810_init_cursor(struct i810fb_par *par)
850{
851 u8 __iomem *mmio = par->mmio_start_virtual;
852
853 i810_enable_cursor(mmio, OFF);
854 i810_writel(CURBASE, mmio, par->cursor_heap.physical);
855 i810_writew(CURCNTR, mmio, COORD_ACTIVE | CURSOR_MODE_64_XOR);
856}
857
858/*********************************************************************
859 * Framebuffer hook helpers *
860 *********************************************************************/
861/**
862 * i810_round_off - Round off values to capability of hardware
863 * @var: pointer to fb_var_screeninfo structure
864 *
865 * DESCRIPTION:
866 * @var contains user-defined information for the mode to be set.
867 * This will try modify those values to ones nearest the
868 * capability of the hardware
869 */
870static void i810_round_off(struct fb_var_screeninfo *var)
871{
872 u32 xres, yres, vxres, vyres;
873
874 /*
875 * Presently supports only these configurations
876 */
877
878 xres = var->xres;
879 yres = var->yres;
880 vxres = var->xres_virtual;
881 vyres = var->yres_virtual;
882
883 var->bits_per_pixel += 7;
884 var->bits_per_pixel &= ~7;
885
886 if (var->bits_per_pixel < 8)
887 var->bits_per_pixel = 8;
888 if (var->bits_per_pixel > 32)
889 var->bits_per_pixel = 32;
890
891 round_off_xres(&xres);
892 if (xres < 40)
893 xres = 40;
894 if (xres > 2048)
895 xres = 2048;
896 xres = (xres + 7) & ~7;
897
898 if (vxres < xres)
899 vxres = xres;
900
901 round_off_yres(&xres, &yres);
902 if (yres < 1)
903 yres = 1;
904 if (yres >= 2048)
905 yres = 2048;
906
907 if (vyres < yres)
908 vyres = yres;
909
910 if (var->bits_per_pixel == 32)
911 var->accel_flags = 0;
912
913 /* round of horizontal timings to nearest 8 pixels */
914 var->left_margin = (var->left_margin + 4) & ~7;
915 var->right_margin = (var->right_margin + 4) & ~7;
916 var->hsync_len = (var->hsync_len + 4) & ~7;
917
918 if (var->vmode & FB_VMODE_INTERLACED) {
919 if (!((yres + var->upper_margin + var->vsync_len +
920 var->lower_margin) & 1))
921 var->upper_margin++;
922 }
923
924 var->xres = xres;
925 var->yres = yres;
926 var->xres_virtual = vxres;
927 var->yres_virtual = vyres;
928}
929
930/**
931 * set_color_bitfields - sets rgba fields
932 * @var: pointer to fb_var_screeninfo
933 *
934 * DESCRIPTION:
935 * The length, offset and ordering for each color field
936 * (red, green, blue) will be set as specified
937 * by the hardware
938 */
939static void set_color_bitfields(struct fb_var_screeninfo *var)
940{
941 switch (var->bits_per_pixel) {
942 case 8:
943 var->red.offset = 0;
944 var->red.length = 8;
945 var->green.offset = 0;
946 var->green.length = 8;
947 var->blue.offset = 0;
948 var->blue.length = 8;
949 var->transp.offset = 0;
950 var->transp.length = 0;
951 break;
952 case 16:
953 var->green.length = (var->green.length == 5) ? 5 : 6;
954 var->red.length = 5;
955 var->blue.length = 5;
956 var->transp.length = 6 - var->green.length;
957 var->blue.offset = 0;
958 var->green.offset = 5;
959 var->red.offset = 5 + var->green.length;
960 var->transp.offset = (5 + var->red.offset) & 15;
961 break;
962 case 24: /* RGB 888 */
963 case 32: /* RGBA 8888 */
964 var->red.offset = 16;
965 var->red.length = 8;
966 var->green.offset = 8;
967 var->green.length = 8;
968 var->blue.offset = 0;
969 var->blue.length = 8;
970 var->transp.length = var->bits_per_pixel - 24;
971 var->transp.offset = (var->transp.length) ? 24 : 0;
972 break;
973 }
974 var->red.msb_right = 0;
975 var->green.msb_right = 0;
976 var->blue.msb_right = 0;
977 var->transp.msb_right = 0;
978}
979
980/**
981 * i810_check_params - check if contents in var are valid
982 * @var: pointer to fb_var_screeninfo
983 * @info: pointer to fb_info
984 *
985 * DESCRIPTION:
986 * This will check if the framebuffer size is sufficient
987 * for the current mode and if the user's monitor has the
988 * required specifications to display the current mode.
989 */
990static int i810_check_params(struct fb_var_screeninfo *var,
991 struct fb_info *info)
992{
993 struct i810fb_par *par = info->par;
994 int line_length, vidmem, mode_valid = 0, retval = 0;
995 u32 vyres = var->yres_virtual, vxres = var->xres_virtual;
996
997 /*
998 * Memory limit
999 */
1000 line_length = get_line_length(par, vxres, var->bits_per_pixel);
1001 vidmem = line_length*vyres;
1002
1003 if (vidmem > par->fb.size) {
1004 vyres = par->fb.size/line_length;
1005 if (vyres < var->yres) {
1006 vyres = info->var.yres;
1007 vxres = par->fb.size/vyres;
1008 vxres /= var->bits_per_pixel >> 3;
1009 line_length = get_line_length(par, vxres,
1010 var->bits_per_pixel);
1011 vidmem = line_length * info->var.yres;
1012 if (vxres < var->xres) {
1013 printk("i810fb: required video memory, "
1014 "%d bytes, for %dx%d-%d (virtual) "
1015 "is out of range\n",
1016 vidmem, vxres, vyres,
1017 var->bits_per_pixel);
1018 return -ENOMEM;
1019 }
1020 }
1021 }
1022
1023 var->xres_virtual = vxres;
1024 var->yres_virtual = vyres;
1025
1026 /*
1027 * Monitor limit
1028 */
1029 switch (var->bits_per_pixel) {
1030 case 8:
1031 info->monspecs.dclkmax = 234000000;
1032 break;
1033 case 16:
1034 info->monspecs.dclkmax = 229000000;
1035 break;
1036 case 24:
1037 case 32:
1038 info->monspecs.dclkmax = 204000000;
1039 break;
1040 }
1041
1042 info->monspecs.dclkmin = 15000000;
1043
1044 if (!fb_validate_mode(var, info))
1045 mode_valid = 1;
1046
1047#ifdef CONFIG_FB_I810_I2C
1048 if (!mode_valid && info->monspecs.gtf &&
1049 !fb_get_mode(FB_MAXTIMINGS, 0, var, info))
1050 mode_valid = 1;
1051
1052 if (!mode_valid && info->monspecs.modedb_len) {
1053 const struct fb_videomode *mode;
1054
1055 mode = fb_find_best_mode(var, &info->modelist);
1056 if (mode) {
1057 fb_videomode_to_var(var, mode);
1058 mode_valid = 1;
1059 }
1060 }
1061#endif
1062 if (!mode_valid && info->monspecs.modedb_len == 0) {
1063 if (fb_get_mode(FB_MAXTIMINGS, 0, var, info)) {
1064 int default_sync = (info->monspecs.hfmin-HFMIN)
1065 |(info->monspecs.hfmax-HFMAX)
1066 |(info->monspecs.vfmin-VFMIN)
1067 |(info->monspecs.vfmax-VFMAX);
1068 printk("i810fb: invalid video mode%s\n",
1069 default_sync ? "" : ". Specifying "
1070 "vsyncN/hsyncN parameters may help");
1071 retval = -EINVAL;
1072 }
1073 }
1074
1075 return retval;
1076}
1077
1078/**
1079 * encode_fix - fill up fb_fix_screeninfo structure
1080 * @fix: pointer to fb_fix_screeninfo
1081 * @info: pointer to fb_info
1082 *
1083 * DESCRIPTION:
1084 * This will set up parameters that are unmodifiable by the user.
1085 */
1086static int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
1087{
1088 struct i810fb_par *par = info->par;
1089
1090 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1091
1092 strcpy(fix->id, "I810");
1093 mutex_lock(&info->mm_lock);
1094 fix->smem_start = par->fb.physical;
1095 fix->smem_len = par->fb.size;
1096 mutex_unlock(&info->mm_lock);
1097 fix->type = FB_TYPE_PACKED_PIXELS;
1098 fix->type_aux = 0;
1099 fix->xpanstep = 8;
1100 fix->ypanstep = 1;
1101
1102 switch (info->var.bits_per_pixel) {
1103 case 8:
1104 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1105 break;
1106 case 16:
1107 case 24:
1108 case 32:
1109 if (info->var.nonstd)
1110 fix->visual = FB_VISUAL_DIRECTCOLOR;
1111 else
1112 fix->visual = FB_VISUAL_TRUECOLOR;
1113 break;
1114 default:
1115 return -EINVAL;
1116 }
1117 fix->ywrapstep = 0;
1118 fix->line_length = par->pitch;
1119 fix->mmio_start = par->mmio_start_phys;
1120 fix->mmio_len = MMIO_SIZE;
1121 fix->accel = FB_ACCEL_I810;
1122
1123 return 0;
1124}
1125
1126/**
1127 * decode_var - modify par according to contents of var
1128 * @var: pointer to fb_var_screeninfo
1129 * @par: pointer to i810fb_par
1130 *
1131 * DESCRIPTION:
1132 * Based on the contents of @var, @par will be dynamically filled up.
1133 * @par contains all information necessary to modify the hardware.
1134*/
1135static void decode_var(const struct fb_var_screeninfo *var,
1136 struct i810fb_par *par)
1137{
1138 u32 xres, yres, vxres, vyres;
1139
1140 xres = var->xres;
1141 yres = var->yres;
1142 vxres = var->xres_virtual;
1143 vyres = var->yres_virtual;
1144
1145 switch (var->bits_per_pixel) {
1146 case 8:
1147 par->pixconf = PIXCONF8;
1148 par->bltcntl = 0;
1149 par->depth = 1;
1150 par->blit_bpp = BPP8;
1151 break;
1152 case 16:
1153 if (var->green.length == 5)
1154 par->pixconf = PIXCONF15;
1155 else
1156 par->pixconf = PIXCONF16;
1157 par->bltcntl = 16;
1158 par->depth = 2;
1159 par->blit_bpp = BPP16;
1160 break;
1161 case 24:
1162 par->pixconf = PIXCONF24;
1163 par->bltcntl = 32;
1164 par->depth = 3;
1165 par->blit_bpp = BPP24;
1166 break;
1167 case 32:
1168 par->pixconf = PIXCONF32;
1169 par->bltcntl = 0;
1170 par->depth = 4;
1171 par->blit_bpp = 3 << 24;
1172 break;
1173 }
1174 if (var->nonstd && var->bits_per_pixel != 8)
1175 par->pixconf |= 1 << 27;
1176
1177 i810_calc_dclk(var->pixclock, &par->regs.M,
1178 &par->regs.N, &par->regs.P);
1179 i810fb_encode_registers(var, par, xres, yres);
1180
1181 par->watermark = i810_get_watermark(var, par);
1182 par->pitch = get_line_length(par, vxres, var->bits_per_pixel);
1183}
1184
1185/**
1186 * i810fb_getcolreg - gets red, green and blue values of the hardware DAC
1187 * @regno: DAC index
1188 * @red: red
1189 * @green: green
1190 * @blue: blue
1191 * @transp: transparency (alpha)
1192 * @info: pointer to fb_info
1193 *
1194 * DESCRIPTION:
1195 * Gets the red, green and blue values of the hardware DAC as pointed by @regno
1196 * and writes them to @red, @green and @blue respectively
1197 */
1198static int i810fb_getcolreg(u8 regno, u8 *red, u8 *green, u8 *blue,
1199 u8 *transp, struct fb_info *info)
1200{
1201 struct i810fb_par *par = info->par;
1202 u8 __iomem *mmio = par->mmio_start_virtual;
1203 u8 temp;
1204
1205 if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
1206 if ((info->var.green.length == 5 && regno > 31) ||
1207 (info->var.green.length == 6 && regno > 63))
1208 return 1;
1209 }
1210
1211 temp = i810_readb(PIXCONF1, mmio);
1212 i810_writeb(PIXCONF1, mmio, temp & ~EXTENDED_PALETTE);
1213
1214 if (info->fix.visual == FB_VISUAL_DIRECTCOLOR &&
1215 info->var.green.length == 5)
1216 i810_read_dac(regno * 8, red, green, blue, mmio);
1217
1218 else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR &&
1219 info->var.green.length == 6) {
1220 u8 tmp;
1221
1222 i810_read_dac(regno * 8, red, &tmp, blue, mmio);
1223 i810_read_dac(regno * 4, &tmp, green, &tmp, mmio);
1224 }
1225 else
1226 i810_read_dac(regno, red, green, blue, mmio);
1227
1228 *transp = 0;
1229 i810_writeb(PIXCONF1, mmio, temp);
1230
1231 return 0;
1232}
1233
1234/******************************************************************
1235 * Framebuffer device-specific hooks *
1236 ******************************************************************/
1237
1238static int i810fb_open(struct fb_info *info, int user)
1239{
1240 struct i810fb_par *par = info->par;
1241
1242 mutex_lock(&par->open_lock);
1243 if (par->use_count == 0) {
1244 memset(&par->state, 0, sizeof(struct vgastate));
1245 par->state.flags = VGA_SAVE_CMAP;
1246 par->state.vgabase = par->mmio_start_virtual;
1247 save_vga(&par->state);
1248
1249 i810_save_vga_state(par);
1250 }
1251
1252 par->use_count++;
1253 mutex_unlock(&par->open_lock);
1254
1255 return 0;
1256}
1257
1258static int i810fb_release(struct fb_info *info, int user)
1259{
1260 struct i810fb_par *par = info->par;
1261
1262 mutex_lock(&par->open_lock);
1263 if (par->use_count == 0) {
1264 mutex_unlock(&par->open_lock);
1265 return -EINVAL;
1266 }
1267
1268 if (par->use_count == 1) {
1269 i810_restore_vga_state(par);
1270 restore_vga(&par->state);
1271 }
1272
1273 par->use_count--;
1274 mutex_unlock(&par->open_lock);
1275
1276 return 0;
1277}
1278
1279
1280static int i810fb_setcolreg(unsigned regno, unsigned red, unsigned green,
1281 unsigned blue, unsigned transp,
1282 struct fb_info *info)
1283{
1284 struct i810fb_par *par = info->par;
1285 u8 __iomem *mmio = par->mmio_start_virtual;
1286 u8 temp;
1287 int i;
1288
1289 if (regno > 255) return 1;
1290
1291 if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
1292 if ((info->var.green.length == 5 && regno > 31) ||
1293 (info->var.green.length == 6 && regno > 63))
1294 return 1;
1295 }
1296
1297 if (info->var.grayscale)
1298 red = green = blue = (19595 * red + 38470 * green +
1299 7471 * blue) >> 16;
1300
1301 temp = i810_readb(PIXCONF1, mmio);
1302 i810_writeb(PIXCONF1, mmio, temp & ~EXTENDED_PALETTE);
1303
1304 if (info->fix.visual == FB_VISUAL_DIRECTCOLOR &&
1305 info->var.green.length == 5) {
1306 for (i = 0; i < 8; i++)
1307 i810_write_dac((u8) (regno * 8) + i, (u8) red,
1308 (u8) green, (u8) blue, mmio);
1309 } else if (info->fix.visual == FB_VISUAL_DIRECTCOLOR &&
1310 info->var.green.length == 6) {
1311 u8 r, g, b;
1312
1313 if (regno < 32) {
1314 for (i = 0; i < 8; i++)
1315 i810_write_dac((u8) (regno * 8) + i,
1316 (u8) red, (u8) green,
1317 (u8) blue, mmio);
1318 }
1319 i810_read_dac((u8) (regno*4), &r, &g, &b, mmio);
1320 for (i = 0; i < 4; i++)
1321 i810_write_dac((u8) (regno*4) + i, r, (u8) green,
1322 b, mmio);
1323 } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
1324 i810_write_dac((u8) regno, (u8) red, (u8) green,
1325 (u8) blue, mmio);
1326 }
1327
1328 i810_writeb(PIXCONF1, mmio, temp);
1329
1330 if (regno < 16) {
1331 switch (info->var.bits_per_pixel) {
1332 case 16:
1333 if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
1334 if (info->var.green.length == 5)
1335 ((u32 *)info->pseudo_palette)[regno] =
1336 (regno << 10) | (regno << 5) |
1337 regno;
1338 else
1339 ((u32 *)info->pseudo_palette)[regno] =
1340 (regno << 11) | (regno << 5) |
1341 regno;
1342 } else {
1343 if (info->var.green.length == 5) {
1344 /* RGB 555 */
1345 ((u32 *)info->pseudo_palette)[regno] =
1346 ((red & 0xf800) >> 1) |
1347 ((green & 0xf800) >> 6) |
1348 ((blue & 0xf800) >> 11);
1349 } else {
1350 /* RGB 565 */
1351 ((u32 *)info->pseudo_palette)[regno] =
1352 (red & 0xf800) |
1353 ((green & 0xf800) >> 5) |
1354 ((blue & 0xf800) >> 11);
1355 }
1356 }
1357 break;
1358 case 24: /* RGB 888 */
1359 case 32: /* RGBA 8888 */
1360 if (info->fix.visual == FB_VISUAL_DIRECTCOLOR)
1361 ((u32 *)info->pseudo_palette)[regno] =
1362 (regno << 16) | (regno << 8) |
1363 regno;
1364 else
1365 ((u32 *)info->pseudo_palette)[regno] =
1366 ((red & 0xff00) << 8) |
1367 (green & 0xff00) |
1368 ((blue & 0xff00) >> 8);
1369 break;
1370 }
1371 }
1372 return 0;
1373}
1374
1375static int i810fb_pan_display(struct fb_var_screeninfo *var,
1376 struct fb_info *info)
1377{
1378 struct i810fb_par *par = info->par;
1379 u32 total;
1380
1381 total = var->xoffset * par->depth +
1382 var->yoffset * info->fix.line_length;
1383 i810fb_load_front(total, info);
1384
1385 return 0;
1386}
1387
1388static int i810fb_blank (int blank_mode, struct fb_info *info)
1389{
1390 struct i810fb_par *par = info->par;
1391 u8 __iomem *mmio = par->mmio_start_virtual;
1392 int mode = 0, pwr, scr_off = 0;
1393
1394 pwr = i810_readl(PWR_CLKC, mmio);
1395
1396 switch (blank_mode) {
1397 case FB_BLANK_UNBLANK:
1398 mode = POWERON;
1399 pwr |= 1;
1400 scr_off = ON;
1401 break;
1402 case FB_BLANK_NORMAL:
1403 mode = POWERON;
1404 pwr |= 1;
1405 scr_off = OFF;
1406 break;
1407 case FB_BLANK_VSYNC_SUSPEND:
1408 mode = STANDBY;
1409 pwr |= 1;
1410 scr_off = OFF;
1411 break;
1412 case FB_BLANK_HSYNC_SUSPEND:
1413 mode = SUSPEND;
1414 pwr |= 1;
1415 scr_off = OFF;
1416 break;
1417 case FB_BLANK_POWERDOWN:
1418 mode = POWERDOWN;
1419 pwr &= ~1;
1420 scr_off = OFF;
1421 break;
1422 default:
1423 return -EINVAL;
1424 }
1425
1426 i810_screen_off(mmio, scr_off);
1427 i810_writel(HVSYNC, mmio, mode);
1428 i810_writel(PWR_CLKC, mmio, pwr);
1429
1430 return 0;
1431}
1432
1433static int i810fb_set_par(struct fb_info *info)
1434{
1435 struct i810fb_par *par = info->par;
1436
1437 decode_var(&info->var, par);
1438 i810_load_regs(par);
1439 i810_init_cursor(par);
1440 encode_fix(&info->fix, info);
1441
1442 if (info->var.accel_flags && !(par->dev_flags & LOCKUP)) {
1443 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
1444 FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
1445 FBINFO_HWACCEL_IMAGEBLIT;
1446 info->pixmap.scan_align = 2;
1447 } else {
1448 info->pixmap.scan_align = 1;
1449 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
1450 }
1451 return 0;
1452}
1453
1454static int i810fb_check_var(struct fb_var_screeninfo *var,
1455 struct fb_info *info)
1456{
1457 int err;
1458
1459 if (IS_DVT) {
1460 var->vmode &= ~FB_VMODE_MASK;
1461 var->vmode |= FB_VMODE_NONINTERLACED;
1462 }
1463 if (var->vmode & FB_VMODE_DOUBLE) {
1464 var->vmode &= ~FB_VMODE_MASK;
1465 var->vmode |= FB_VMODE_NONINTERLACED;
1466 }
1467
1468 i810_round_off(var);
1469 if ((err = i810_check_params(var, info)))
1470 return err;
1471
1472 i810fb_fill_var_timings(var);
1473 set_color_bitfields(var);
1474 return 0;
1475}
1476
1477static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
1478{
1479 struct i810fb_par *par = info->par;
1480 u8 __iomem *mmio = par->mmio_start_virtual;
1481
1482 if (par->dev_flags & LOCKUP)
1483 return -ENXIO;
1484
1485 if (cursor->image.width > 64 || cursor->image.height > 64)
1486 return -ENXIO;
1487
1488 if ((i810_readl(CURBASE, mmio) & 0xf) != par->cursor_heap.physical) {
1489 i810_init_cursor(par);
1490 cursor->set |= FB_CUR_SETALL;
1491 }
1492
1493 i810_enable_cursor(mmio, OFF);
1494
1495 if (cursor->set & FB_CUR_SETPOS) {
1496 u32 tmp;
1497
1498 tmp = (cursor->image.dx - info->var.xoffset) & 0xffff;
1499 tmp |= (cursor->image.dy - info->var.yoffset) << 16;
1500 i810_writel(CURPOS, mmio, tmp);
1501 }
1502
1503 if (cursor->set & FB_CUR_SETSIZE)
1504 i810_reset_cursor_image(par);
1505
1506 if (cursor->set & FB_CUR_SETCMAP)
1507 i810_load_cursor_colors(cursor->image.fg_color,
1508 cursor->image.bg_color,
1509 info);
1510
1511 if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
1512 int size = ((cursor->image.width + 7) >> 3) *
1513 cursor->image.height;
1514 int i;
1515 u8 *data = kmalloc(64 * 8, GFP_ATOMIC);
1516
1517 if (data == NULL)
1518 return -ENOMEM;
1519
1520 switch (cursor->rop) {
1521 case ROP_XOR:
1522 for (i = 0; i < size; i++)
1523 data[i] = cursor->image.data[i] ^ cursor->mask[i];
1524 break;
1525 case ROP_COPY:
1526 default:
1527 for (i = 0; i < size; i++)
1528 data[i] = cursor->image.data[i] & cursor->mask[i];
1529 break;
1530 }
1531
1532 i810_load_cursor_image(cursor->image.width,
1533 cursor->image.height, data,
1534 par);
1535 kfree(data);
1536 }
1537
1538 if (cursor->enable)
1539 i810_enable_cursor(mmio, ON);
1540
1541 return 0;
1542}
1543
1544static struct fb_ops i810fb_ops = {
1545 .owner = THIS_MODULE,
1546 .fb_open = i810fb_open,
1547 .fb_release = i810fb_release,
1548 .fb_check_var = i810fb_check_var,
1549 .fb_set_par = i810fb_set_par,
1550 .fb_setcolreg = i810fb_setcolreg,
1551 .fb_blank = i810fb_blank,
1552 .fb_pan_display = i810fb_pan_display,
1553 .fb_fillrect = i810fb_fillrect,
1554 .fb_copyarea = i810fb_copyarea,
1555 .fb_imageblit = i810fb_imageblit,
1556 .fb_cursor = i810fb_cursor,
1557 .fb_sync = i810fb_sync,
1558};
1559
1560/***********************************************************************
1561 * Power Management *
1562 ***********************************************************************/
1563static int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg)
1564{
1565 struct fb_info *info = pci_get_drvdata(dev);
1566 struct i810fb_par *par = info->par;
1567
1568 par->cur_state = mesg.event;
1569
1570 switch (mesg.event) {
1571 case PM_EVENT_FREEZE:
1572 case PM_EVENT_PRETHAW:
1573 dev->dev.power.power_state = mesg;
1574 return 0;
1575 }
1576
1577 console_lock();
1578 fb_set_suspend(info, 1);
1579
1580 if (info->fbops->fb_sync)
1581 info->fbops->fb_sync(info);
1582
1583 i810fb_blank(FB_BLANK_POWERDOWN, info);
1584 agp_unbind_memory(par->i810_gtt.i810_fb_memory);
1585 agp_unbind_memory(par->i810_gtt.i810_cursor_memory);
1586
1587 pci_save_state(dev);
1588 pci_disable_device(dev);
1589 pci_set_power_state(dev, pci_choose_state(dev, mesg));
1590 console_unlock();
1591
1592 return 0;
1593}
1594
1595static int i810fb_resume(struct pci_dev *dev)
1596{
1597 struct fb_info *info = pci_get_drvdata(dev);
1598 struct i810fb_par *par = info->par;
1599 int cur_state = par->cur_state;
1600
1601 par->cur_state = PM_EVENT_ON;
1602
1603 if (cur_state == PM_EVENT_FREEZE) {
1604 pci_set_power_state(dev, PCI_D0);
1605 return 0;
1606 }
1607
1608 console_lock();
1609 pci_set_power_state(dev, PCI_D0);
1610 pci_restore_state(dev);
1611
1612 if (pci_enable_device(dev))
1613 goto fail;
1614
1615 pci_set_master(dev);
1616 agp_bind_memory(par->i810_gtt.i810_fb_memory,
1617 par->fb.offset);
1618 agp_bind_memory(par->i810_gtt.i810_cursor_memory,
1619 par->cursor_heap.offset);
1620 i810fb_set_par(info);
1621 fb_set_suspend (info, 0);
1622 info->fbops->fb_blank(VESA_NO_BLANKING, info);
1623fail:
1624 console_unlock();
1625 return 0;
1626}
1627/***********************************************************************
1628 * AGP resource allocation *
1629 ***********************************************************************/
1630
1631static void i810_fix_pointers(struct i810fb_par *par)
1632{
1633 par->fb.physical = par->aperture.physical+(par->fb.offset << 12);
1634 par->fb.virtual = par->aperture.virtual+(par->fb.offset << 12);
1635 par->iring.physical = par->aperture.physical +
1636 (par->iring.offset << 12);
1637 par->iring.virtual = par->aperture.virtual +
1638 (par->iring.offset << 12);
1639 par->cursor_heap.virtual = par->aperture.virtual+
1640 (par->cursor_heap.offset << 12);
1641}
1642
1643static void i810_fix_offsets(struct i810fb_par *par)
1644{
1645 if (vram + 1 > par->aperture.size >> 20)
1646 vram = (par->aperture.size >> 20) - 1;
1647 if (v_offset_default > (par->aperture.size >> 20))
1648 v_offset_default = (par->aperture.size >> 20);
1649 if (vram + v_offset_default + 1 > par->aperture.size >> 20)
1650 v_offset_default = (par->aperture.size >> 20) - (vram + 1);
1651
1652 par->fb.size = vram << 20;
1653 par->fb.offset = v_offset_default << 20;
1654 par->fb.offset >>= 12;
1655
1656 par->iring.offset = par->fb.offset + (par->fb.size >> 12);
1657 par->iring.size = RINGBUFFER_SIZE;
1658
1659 par->cursor_heap.offset = par->iring.offset + (RINGBUFFER_SIZE >> 12);
1660 par->cursor_heap.size = 4096;
1661}
1662
1663static int i810_alloc_agp_mem(struct fb_info *info)
1664{
1665 struct i810fb_par *par = info->par;
1666 int size;
1667 struct agp_bridge_data *bridge;
1668
1669 i810_fix_offsets(par);
1670 size = par->fb.size + par->iring.size;
1671
1672 if (!(bridge = agp_backend_acquire(par->dev))) {
1673 printk("i810fb_alloc_fbmem: cannot acquire agpgart\n");
1674 return -ENODEV;
1675 }
1676 if (!(par->i810_gtt.i810_fb_memory =
1677 agp_allocate_memory(bridge, size >> 12, AGP_NORMAL_MEMORY))) {
1678 printk("i810fb_alloc_fbmem: can't allocate framebuffer "
1679 "memory\n");
1680 agp_backend_release(bridge);
1681 return -ENOMEM;
1682 }
1683 if (agp_bind_memory(par->i810_gtt.i810_fb_memory,
1684 par->fb.offset)) {
1685 printk("i810fb_alloc_fbmem: can't bind framebuffer memory\n");
1686 agp_backend_release(bridge);
1687 return -EBUSY;
1688 }
1689
1690 if (!(par->i810_gtt.i810_cursor_memory =
1691 agp_allocate_memory(bridge, par->cursor_heap.size >> 12,
1692 AGP_PHYSICAL_MEMORY))) {
1693 printk("i810fb_alloc_cursormem: can't allocate"
1694 "cursor memory\n");
1695 agp_backend_release(bridge);
1696 return -ENOMEM;
1697 }
1698 if (agp_bind_memory(par->i810_gtt.i810_cursor_memory,
1699 par->cursor_heap.offset)) {
1700 printk("i810fb_alloc_cursormem: cannot bind cursor memory\n");
1701 agp_backend_release(bridge);
1702 return -EBUSY;
1703 }
1704
1705 par->cursor_heap.physical = par->i810_gtt.i810_cursor_memory->physical;
1706
1707 i810_fix_pointers(par);
1708
1709 agp_backend_release(bridge);
1710
1711 return 0;
1712}
1713
1714/***************************************************************
1715 * Initialization *
1716 ***************************************************************/
1717
1718/**
1719 * i810_init_monspecs
1720 * @info: pointer to device specific info structure
1721 *
1722 * DESCRIPTION:
1723 * Sets the user monitor's horizontal and vertical
1724 * frequency limits
1725 */
1726static void i810_init_monspecs(struct fb_info *info)
1727{
1728 if (!hsync1)
1729 hsync1 = HFMIN;
1730 if (!hsync2)
1731 hsync2 = HFMAX;
1732 if (!info->monspecs.hfmax)
1733 info->monspecs.hfmax = hsync2;
1734 if (!info->monspecs.hfmin)
1735 info->monspecs.hfmin = hsync1;
1736 if (hsync2 < hsync1)
1737 info->monspecs.hfmin = hsync2;
1738
1739 if (!vsync1)
1740 vsync1 = VFMIN;
1741 if (!vsync2)
1742 vsync2 = VFMAX;
1743 if (IS_DVT && vsync1 < 60)
1744 vsync1 = 60;
1745 if (!info->monspecs.vfmax)
1746 info->monspecs.vfmax = vsync2;
1747 if (!info->monspecs.vfmin)
1748 info->monspecs.vfmin = vsync1;
1749 if (vsync2 < vsync1)
1750 info->monspecs.vfmin = vsync2;
1751}
1752
1753/**
1754 * i810_init_defaults - initializes default values to use
1755 * @par: pointer to i810fb_par structure
1756 * @info: pointer to current fb_info structure
1757 */
1758static void i810_init_defaults(struct i810fb_par *par, struct fb_info *info)
1759{
1760 mutex_init(&par->open_lock);
1761
1762 if (voffset)
1763 v_offset_default = voffset;
1764 else if (par->aperture.size > 32 * 1024 * 1024)
1765 v_offset_default = 16;
1766 else
1767 v_offset_default = 8;
1768
1769 if (!vram)
1770 vram = 1;
1771
1772 if (accel)
1773 par->dev_flags |= HAS_ACCELERATION;
1774
1775 if (sync)
1776 par->dev_flags |= ALWAYS_SYNC;
1777
1778 par->ddc_num = (ddc3 ? 3 : 2);
1779
1780 if (bpp < 8)
1781 bpp = 8;
1782
1783 par->i810fb_ops = i810fb_ops;
1784
1785 if (xres)
1786 info->var.xres = xres;
1787 else
1788 info->var.xres = 640;
1789
1790 if (yres)
1791 info->var.yres = yres;
1792 else
1793 info->var.yres = 480;
1794
1795 if (!vyres)
1796 vyres = (vram << 20)/(info->var.xres*bpp >> 3);
1797
1798 info->var.yres_virtual = vyres;
1799 info->var.bits_per_pixel = bpp;
1800
1801 if (dcolor)
1802 info->var.nonstd = 1;
1803
1804 if (par->dev_flags & HAS_ACCELERATION)
1805 info->var.accel_flags = 1;
1806
1807 i810_init_monspecs(info);
1808}
1809
1810/**
1811 * i810_init_device - initialize device
1812 * @par: pointer to i810fb_par structure
1813 */
1814static void i810_init_device(struct i810fb_par *par)
1815{
1816 u8 reg;
1817 u8 __iomem *mmio = par->mmio_start_virtual;
1818
1819 if (mtrr) set_mtrr(par);
1820
1821 i810_init_cursor(par);
1822
1823 /* mvo: enable external vga-connector (for laptops) */
1824 if (extvga) {
1825 i810_writel(HVSYNC, mmio, 0);
1826 i810_writel(PWR_CLKC, mmio, 3);
1827 }
1828
1829 pci_read_config_byte(par->dev, 0x50, &reg);
1830 reg &= FREQ_MASK;
1831 par->mem_freq = (reg) ? 133 : 100;
1832
1833}
1834
1835static int i810_allocate_pci_resource(struct i810fb_par *par,
1836 const struct pci_device_id *entry)
1837{
1838 int err;
1839
1840 if ((err = pci_enable_device(par->dev))) {
1841 printk("i810fb_init: cannot enable device\n");
1842 return err;
1843 }
1844 par->res_flags |= PCI_DEVICE_ENABLED;
1845
1846 if (pci_resource_len(par->dev, 0) > 512 * 1024) {
1847 par->aperture.physical = pci_resource_start(par->dev, 0);
1848 par->aperture.size = pci_resource_len(par->dev, 0);
1849 par->mmio_start_phys = pci_resource_start(par->dev, 1);
1850 } else {
1851 par->aperture.physical = pci_resource_start(par->dev, 1);
1852 par->aperture.size = pci_resource_len(par->dev, 1);
1853 par->mmio_start_phys = pci_resource_start(par->dev, 0);
1854 }
1855 if (!par->aperture.size) {
1856 printk("i810fb_init: device is disabled\n");
1857 return -ENOMEM;
1858 }
1859
1860 if (!request_mem_region(par->aperture.physical,
1861 par->aperture.size,
1862 i810_pci_list[entry->driver_data])) {
1863 printk("i810fb_init: cannot request framebuffer region\n");
1864 return -ENODEV;
1865 }
1866 par->res_flags |= FRAMEBUFFER_REQ;
1867
1868 par->aperture.virtual = ioremap_nocache(par->aperture.physical,
1869 par->aperture.size);
1870 if (!par->aperture.virtual) {
1871 printk("i810fb_init: cannot remap framebuffer region\n");
1872 return -ENODEV;
1873 }
1874
1875 if (!request_mem_region(par->mmio_start_phys,
1876 MMIO_SIZE,
1877 i810_pci_list[entry->driver_data])) {
1878 printk("i810fb_init: cannot request mmio region\n");
1879 return -ENODEV;
1880 }
1881 par->res_flags |= MMIO_REQ;
1882
1883 par->mmio_start_virtual = ioremap_nocache(par->mmio_start_phys,
1884 MMIO_SIZE);
1885 if (!par->mmio_start_virtual) {
1886 printk("i810fb_init: cannot remap mmio region\n");
1887 return -ENODEV;
1888 }
1889
1890 return 0;
1891}
1892
1893static void i810fb_find_init_mode(struct fb_info *info)
1894{
1895 struct fb_videomode mode;
1896 struct fb_var_screeninfo var;
1897 struct fb_monspecs *specs = &info->monspecs;
1898 int found = 0;
1899#ifdef CONFIG_FB_I810_I2C
1900 int i;
1901 int err = 1;
1902 struct i810fb_par *par = info->par;
1903#endif
1904
1905 INIT_LIST_HEAD(&info->modelist);
1906 memset(&mode, 0, sizeof(struct fb_videomode));
1907 var = info->var;
1908#ifdef CONFIG_FB_I810_I2C
1909 i810_create_i2c_busses(par);
1910
1911 for (i = 0; i < par->ddc_num + 1; i++) {
1912 err = i810_probe_i2c_connector(info, &par->edid, i);
1913 if (!err)
1914 break;
1915 }
1916
1917 if (!err)
1918 printk("i810fb_init_pci: DDC probe successful\n");
1919
1920 fb_edid_to_monspecs(par->edid, specs);
1921
1922 if (specs->modedb == NULL)
1923 printk("i810fb_init_pci: Unable to get Mode Database\n");
1924
1925 fb_videomode_to_modelist(specs->modedb, specs->modedb_len,
1926 &info->modelist);
1927 if (specs->modedb != NULL) {
1928 const struct fb_videomode *m;
1929
1930 if (xres && yres) {
1931 if ((m = fb_find_best_mode(&var, &info->modelist))) {
1932 mode = *m;
1933 found = 1;
1934 }
1935 }
1936
1937 if (!found) {
1938 m = fb_find_best_display(&info->monspecs, &info->modelist);
1939 mode = *m;
1940 found = 1;
1941 }
1942
1943 fb_videomode_to_var(&var, &mode);
1944 }
1945#endif
1946 if (mode_option)
1947 fb_find_mode(&var, info, mode_option, specs->modedb,
1948 specs->modedb_len, (found) ? &mode : NULL,
1949 info->var.bits_per_pixel);
1950
1951 info->var = var;
1952 fb_destroy_modedb(specs->modedb);
1953 specs->modedb = NULL;
1954}
1955
1956#ifndef MODULE
1957static int i810fb_setup(char *options)
1958{
1959 char *this_opt, *suffix = NULL;
1960
1961 if (!options || !*options)
1962 return 0;
1963
1964 while ((this_opt = strsep(&options, ",")) != NULL) {
1965 if (!strncmp(this_opt, "mtrr", 4))
1966 mtrr = 1;
1967 else if (!strncmp(this_opt, "accel", 5))
1968 accel = 1;
1969 else if (!strncmp(this_opt, "extvga", 6))
1970 extvga = 1;
1971 else if (!strncmp(this_opt, "sync", 4))
1972 sync = 1;
1973 else if (!strncmp(this_opt, "vram:", 5))
1974 vram = (simple_strtoul(this_opt+5, NULL, 0));
1975 else if (!strncmp(this_opt, "voffset:", 8))
1976 voffset = (simple_strtoul(this_opt+8, NULL, 0));
1977 else if (!strncmp(this_opt, "xres:", 5))
1978 xres = simple_strtoul(this_opt+5, NULL, 0);
1979 else if (!strncmp(this_opt, "yres:", 5))
1980 yres = simple_strtoul(this_opt+5, NULL, 0);
1981 else if (!strncmp(this_opt, "vyres:", 6))
1982 vyres = simple_strtoul(this_opt+6, NULL, 0);
1983 else if (!strncmp(this_opt, "bpp:", 4))
1984 bpp = simple_strtoul(this_opt+4, NULL, 0);
1985 else if (!strncmp(this_opt, "hsync1:", 7)) {
1986 hsync1 = simple_strtoul(this_opt+7, &suffix, 0);
1987 if (strncmp(suffix, "H", 1))
1988 hsync1 *= 1000;
1989 } else if (!strncmp(this_opt, "hsync2:", 7)) {
1990 hsync2 = simple_strtoul(this_opt+7, &suffix, 0);
1991 if (strncmp(suffix, "H", 1))
1992 hsync2 *= 1000;
1993 } else if (!strncmp(this_opt, "vsync1:", 7))
1994 vsync1 = simple_strtoul(this_opt+7, NULL, 0);
1995 else if (!strncmp(this_opt, "vsync2:", 7))
1996 vsync2 = simple_strtoul(this_opt+7, NULL, 0);
1997 else if (!strncmp(this_opt, "dcolor", 6))
1998 dcolor = 1;
1999 else if (!strncmp(this_opt, "ddc3", 4))
2000 ddc3 = true;
2001 else
2002 mode_option = this_opt;
2003 }
2004 return 0;
2005}
2006#endif
2007
2008static int i810fb_init_pci(struct pci_dev *dev,
2009 const struct pci_device_id *entry)
2010{
2011 struct fb_info *info;
2012 struct i810fb_par *par = NULL;
2013 struct fb_videomode mode;
2014 int err = -1, vfreq, hfreq, pixclock;
2015
2016 info = framebuffer_alloc(sizeof(struct i810fb_par), &dev->dev);
2017 if (!info)
2018 return -ENOMEM;
2019
2020 par = info->par;
2021 par->dev = dev;
2022
2023 if (!(info->pixmap.addr = kzalloc(8*1024, GFP_KERNEL))) {
2024 i810fb_release_resource(info, par);
2025 return -ENOMEM;
2026 }
2027 info->pixmap.size = 8*1024;
2028 info->pixmap.buf_align = 8;
2029 info->pixmap.access_align = 32;
2030 info->pixmap.flags = FB_PIXMAP_SYSTEM;
2031
2032 if ((err = i810_allocate_pci_resource(par, entry))) {
2033 i810fb_release_resource(info, par);
2034 return err;
2035 }
2036
2037 i810_init_defaults(par, info);
2038
2039 if ((err = i810_alloc_agp_mem(info))) {
2040 i810fb_release_resource(info, par);
2041 return err;
2042 }
2043
2044 i810_init_device(par);
2045
2046 info->screen_base = par->fb.virtual;
2047 info->fbops = &par->i810fb_ops;
2048 info->pseudo_palette = par->pseudo_palette;
2049 fb_alloc_cmap(&info->cmap, 256, 0);
2050 i810fb_find_init_mode(info);
2051
2052 if ((err = info->fbops->fb_check_var(&info->var, info))) {
2053 i810fb_release_resource(info, par);
2054 return err;
2055 }
2056
2057 fb_var_to_videomode(&mode, &info->var);
2058 fb_add_videomode(&mode, &info->modelist);
2059
2060 i810fb_init_ringbuffer(info);
2061 err = register_framebuffer(info);
2062
2063 if (err < 0) {
2064 i810fb_release_resource(info, par);
2065 printk("i810fb_init: cannot register framebuffer device\n");
2066 return err;
2067 }
2068
2069 pci_set_drvdata(dev, info);
2070 pixclock = 1000000000/(info->var.pixclock);
2071 pixclock *= 1000;
2072 hfreq = pixclock/(info->var.xres + info->var.left_margin +
2073 info->var.hsync_len + info->var.right_margin);
2074 vfreq = hfreq/(info->var.yres + info->var.upper_margin +
2075 info->var.vsync_len + info->var.lower_margin);
2076
2077 printk("I810FB: fb%d : %s v%d.%d.%d%s\n"
2078 "I810FB: Video RAM : %dK\n"
2079 "I810FB: Monitor : H: %d-%d KHz V: %d-%d Hz\n"
2080 "I810FB: Mode : %dx%d-%dbpp@%dHz\n",
2081 info->node,
2082 i810_pci_list[entry->driver_data],
2083 VERSION_MAJOR, VERSION_MINOR, VERSION_TEENIE, BRANCH_VERSION,
2084 (int) par->fb.size>>10, info->monspecs.hfmin/1000,
2085 info->monspecs.hfmax/1000, info->monspecs.vfmin,
2086 info->monspecs.vfmax, info->var.xres,
2087 info->var.yres, info->var.bits_per_pixel, vfreq);
2088 return 0;
2089}
2090
2091/***************************************************************
2092 * De-initialization *
2093 ***************************************************************/
2094
2095static void i810fb_release_resource(struct fb_info *info,
2096 struct i810fb_par *par)
2097{
2098 struct gtt_data *gtt = &par->i810_gtt;
2099 unset_mtrr(par);
2100
2101 i810_delete_i2c_busses(par);
2102
2103 if (par->i810_gtt.i810_cursor_memory)
2104 agp_free_memory(gtt->i810_cursor_memory);
2105 if (par->i810_gtt.i810_fb_memory)
2106 agp_free_memory(gtt->i810_fb_memory);
2107
2108 if (par->mmio_start_virtual)
2109 iounmap(par->mmio_start_virtual);
2110 if (par->aperture.virtual)
2111 iounmap(par->aperture.virtual);
2112 kfree(par->edid);
2113 if (par->res_flags & FRAMEBUFFER_REQ)
2114 release_mem_region(par->aperture.physical,
2115 par->aperture.size);
2116 if (par->res_flags & MMIO_REQ)
2117 release_mem_region(par->mmio_start_phys, MMIO_SIZE);
2118
2119 framebuffer_release(info);
2120
2121}
2122
2123static void __exit i810fb_remove_pci(struct pci_dev *dev)
2124{
2125 struct fb_info *info = pci_get_drvdata(dev);
2126 struct i810fb_par *par = info->par;
2127
2128 unregister_framebuffer(info);
2129 i810fb_release_resource(info, par);
2130 printk("cleanup_module: unloaded i810 framebuffer device\n");
2131}
2132
2133#ifndef MODULE
2134static int i810fb_init(void)
2135{
2136 char *option = NULL;
2137
2138 if (fb_get_options("i810fb", &option))
2139 return -ENODEV;
2140 i810fb_setup(option);
2141
2142 return pci_register_driver(&i810fb_driver);
2143}
2144#endif
2145
2146/*********************************************************************
2147 * Modularization *
2148 *********************************************************************/
2149
2150#ifdef MODULE
2151
2152static int i810fb_init(void)
2153{
2154 hsync1 *= 1000;
2155 hsync2 *= 1000;
2156
2157 return pci_register_driver(&i810fb_driver);
2158}
2159
2160module_param(vram, int, 0);
2161MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB"
2162 " (default=4)");
2163module_param(voffset, int, 0);
2164MODULE_PARM_DESC(voffset, "at what offset to place start of framebuffer "
2165 "memory (0 to maximum aperture size), in MiB (default = 48)");
2166module_param(bpp, int, 0);
2167MODULE_PARM_DESC(bpp, "Color depth for display in bits per pixel"
2168 " (default = 8)");
2169module_param(xres, int, 0);
2170MODULE_PARM_DESC(xres, "Horizontal resolution in pixels (default = 640)");
2171module_param(yres, int, 0);
2172MODULE_PARM_DESC(yres, "Vertical resolution in scanlines (default = 480)");
2173module_param(vyres,int, 0);
2174MODULE_PARM_DESC(vyres, "Virtual vertical resolution in scanlines"
2175 " (default = 480)");
2176module_param(hsync1, int, 0);
2177MODULE_PARM_DESC(hsync1, "Minimum horizontal frequency of monitor in KHz"
2178 " (default = 29)");
2179module_param(hsync2, int, 0);
2180MODULE_PARM_DESC(hsync2, "Maximum horizontal frequency of monitor in KHz"
2181 " (default = 30)");
2182module_param(vsync1, int, 0);
2183MODULE_PARM_DESC(vsync1, "Minimum vertical frequency of monitor in Hz"
2184 " (default = 50)");
2185module_param(vsync2, int, 0);
2186MODULE_PARM_DESC(vsync2, "Maximum vertical frequency of monitor in Hz"
2187 " (default = 60)");
2188module_param(accel, bool, 0);
2189MODULE_PARM_DESC(accel, "Use Acceleration (BLIT) engine (default = 0)");
2190module_param(mtrr, bool, 0);
2191MODULE_PARM_DESC(mtrr, "Use MTRR (default = 0)");
2192module_param(extvga, bool, 0);
2193MODULE_PARM_DESC(extvga, "Enable external VGA connector (default = 0)");
2194module_param(sync, bool, 0);
2195MODULE_PARM_DESC(sync, "wait for accel engine to finish drawing"
2196 " (default = 0)");
2197module_param(dcolor, bool, 0);
2198MODULE_PARM_DESC(dcolor, "use DirectColor visuals"
2199 " (default = 0 = TrueColor)");
2200module_param(ddc3, bool, 0);
2201MODULE_PARM_DESC(ddc3, "Probe DDC bus 3 (default = 0 = no)");
2202module_param(mode_option, charp, 0);
2203MODULE_PARM_DESC(mode_option, "Specify initial video mode");
2204
2205MODULE_AUTHOR("Tony A. Daplas");
2206MODULE_DESCRIPTION("Framebuffer device for the Intel 810/815 and"
2207 " compatible cards");
2208MODULE_LICENSE("GPL");
2209
2210static void __exit i810fb_exit(void)
2211{
2212 pci_unregister_driver(&i810fb_driver);
2213}
2214module_exit(i810fb_exit);
2215
2216#endif /* MODULE */
2217
2218module_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 000000000000..a25afaa534ba
--- /dev/null
+++ b/drivers/video/fbdev/i810/i810_main.h
@@ -0,0 +1,95 @@
1/*-*- linux-c -*-
2 * linux/drivers/video/i810fb_main.h -- Intel 810 frame buffer device
3 * main header file
4 *
5 * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
6 * All Rights Reserved
7 *
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file COPYING in the main directory of this archive for
11 * more details.
12 */
13
14#ifndef __I810_MAIN_H__
15#define __I810_MAIN_H__
16
17/* Video Timings */
18extern void round_off_xres (u32 *xres);
19extern void round_off_yres (u32 *xres, u32 *yres);
20extern u32 i810_get_watermark (const struct fb_var_screeninfo *var,
21 struct i810fb_par *par);
22extern void i810fb_encode_registers(const struct fb_var_screeninfo *var,
23 struct i810fb_par *par, u32 xres, u32 yres);
24extern void i810fb_fill_var_timings(struct fb_var_screeninfo *var);
25
26/* Accelerated Functions */
27extern void i810fb_fillrect (struct fb_info *p,
28 const struct fb_fillrect *rect);
29extern void i810fb_copyarea (struct fb_info *p,
30 const struct fb_copyarea *region);
31extern void i810fb_imageblit(struct fb_info *p, const struct fb_image *image);
32extern int i810fb_sync (struct fb_info *p);
33
34extern void i810fb_init_ringbuffer(struct fb_info *info);
35extern void i810fb_load_front (u32 offset, struct fb_info *info);
36
37#ifdef CONFIG_FB_I810_I2C
38/* I2C */
39extern int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid,
40 int conn);
41extern void i810_create_i2c_busses(struct i810fb_par *par);
42extern void i810_delete_i2c_busses(struct i810fb_par *par);
43#else
44static inline int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid,
45 int conn)
46{
47 return 1;
48}
49static inline void i810_create_i2c_busses(struct i810fb_par *par) { }
50static inline void i810_delete_i2c_busses(struct i810fb_par *par) { }
51#endif
52
53/* Conditionals */
54#ifdef CONFIG_X86
55static inline void flush_cache(void)
56{
57 asm volatile ("wbinvd":::"memory");
58}
59#else
60#define flush_cache() do { } while(0)
61#endif
62
63#ifdef CONFIG_MTRR
64
65#include <asm/mtrr.h>
66
67static inline void set_mtrr(struct i810fb_par *par)
68{
69 par->mtrr_reg = mtrr_add((u32) par->aperture.physical,
70 par->aperture.size, MTRR_TYPE_WRCOMB, 1);
71 if (par->mtrr_reg < 0) {
72 printk(KERN_ERR "set_mtrr: unable to set MTRR\n");
73 return;
74 }
75 par->dev_flags |= HAS_MTRR;
76}
77static inline void unset_mtrr(struct i810fb_par *par)
78{
79 if (par->dev_flags & HAS_MTRR)
80 mtrr_del(par->mtrr_reg, (u32) par->aperture.physical,
81 par->aperture.size);
82}
83#else
84#define set_mtrr(x) printk("set_mtrr: MTRR is disabled in the kernel\n")
85
86#define unset_mtrr(x) do { } while (0)
87#endif /* CONFIG_MTRR */
88
89#ifdef CONFIG_FB_I810_GTF
90#define IS_DVT (0)
91#else
92#define IS_DVT (1)
93#endif
94
95#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 000000000000..91c6bd9d0d0d
--- /dev/null
+++ b/drivers/video/fbdev/i810/i810_regs.h
@@ -0,0 +1,275 @@
1/*-*- linux-c -*-
2 * linux/drivers/video/i810_regs.h -- Intel 810/815 Register List
3 *
4 * Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
5 * All Rights Reserved
6 *
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file COPYING in the main directory of this archive for
10 * more details.
11 */
12
13
14/*
15 * Intel 810 Chipset Family PRM 15 3.1
16 * GC Register Memory Address Map
17 *
18 * Based on:
19 * Intel (R) 810 Chipset Family
20 * Programmer s Reference Manual
21 * November 1999
22 * Revision 1.0
23 * Order Number: 298026-001 R
24 *
25 * All GC registers are memory-mapped. In addition, the VGA and extended VGA registers
26 * are I/O mapped.
27 */
28
29#ifndef __I810_REGS_H__
30#define __I810_REGS_H__
31
32/* Instruction and Interrupt Control Registers (01000h 02FFFh) */
33#define FENCE 0x02000
34#define PGTBL_CTL 0x02020
35#define PGTBL_ER 0x02024
36#define LRING 0x02030
37#define IRING 0x02040
38#define HWS_PGA 0x02080
39#define IPEIR 0x02088
40#define IPEHR 0x0208C
41#define INSTDONE 0x02090
42#define NOPID 0x02094
43#define HWSTAM 0x02098
44#define IER 0x020A0
45#define IIR 0x020A4
46#define IMR 0x020A8
47#define ISR 0x020AC
48#define EIR 0x020B0
49#define EMR 0x020B4
50#define ESR 0x020B8
51#define INSTPM 0x020C0
52#define INSTPS 0x020C4
53#define BBP_PTR 0x020C8
54#define ABB_SRT 0x020CC
55#define ABB_END 0x020D0
56#define DMA_FADD 0x020D4
57#define FW_BLC 0x020D8
58#define MEM_MODE 0x020DC
59
60/* Memory Control Registers (03000h 03FFFh) */
61#define DRT 0x03000
62#define DRAMCL 0x03001
63#define DRAMCH 0x03002
64
65
66/* Span Cursor Registers (04000h 04FFFh) */
67#define UI_SC_CTL 0x04008
68
69/* I/O Control Registers (05000h 05FFFh) */
70#define HVSYNC 0x05000
71#define GPIOA 0x05010
72#define GPIOB 0x05014
73#define GPIOC 0x0501C
74
75/* Clock Control and Power Management Registers (06000h 06FFFh) */
76#define DCLK_0D 0x06000
77#define DCLK_1D 0x06004
78#define DCLK_2D 0x06008
79#define LCD_CLKD 0x0600C
80#define DCLK_0DS 0x06010
81#define PWR_CLKC 0x06014
82
83/* Graphics Translation Table Range Definition (10000h 1FFFFh) */
84#define GTT 0x10000
85
86/* Overlay Registers (30000h 03FFFFh) */
87#define OVOADDR 0x30000
88#define DOVOSTA 0x30008
89#define GAMMA 0x30010
90#define OBUF_0Y 0x30100
91#define OBUF_1Y 0x30104
92#define OBUF_0U 0x30108
93#define OBUF_0V 0x3010C
94#define OBUF_1U 0x30110
95#define OBUF_1V 0x30114
96#define OVOSTRIDE 0x30118
97#define YRGB_VPH 0x3011C
98#define UV_VPH 0x30120
99#define HORZ_PH 0x30124
100#define INIT_PH 0x30128
101#define DWINPOS 0x3012C
102#define DWINSZ 0x30130
103#define SWID 0x30134
104#define SWIDQW 0x30138
105#define SHEIGHT 0x3013F
106#define YRGBSCALE 0x30140
107#define UVSCALE 0x30144
108#define OVOCLRCO 0x30148
109#define OVOCLRC1 0x3014C
110#define DCLRKV 0x30150
111#define DLCRKM 0x30154
112#define SCLRKVH 0x30158
113#define SCLRKVL 0x3015C
114#define SCLRKM 0x30160
115#define OVOCONF 0x30164
116#define OVOCMD 0x30168
117#define AWINPOS 0x30170
118#define AWINZ 0x30174
119
120/* BLT Engine Status (40000h 4FFFFh) (Software Debug) */
121#define BR00 0x40000
122#define BRO1 0x40004
123#define BR02 0x40008
124#define BR03 0x4000C
125#define BR04 0x40010
126#define BR05 0x40014
127#define BR06 0x40018
128#define BR07 0x4001C
129#define BR08 0x40020
130#define BR09 0x40024
131#define BR10 0x40028
132#define BR11 0x4002C
133#define BR12 0x40030
134#define BR13 0x40034
135#define BR14 0x40038
136#define BR15 0x4003C
137#define BR16 0x40040
138#define BR17 0x40044
139#define BR18 0x40048
140#define BR19 0x4004C
141#define SSLADD 0x40074
142#define DSLH 0x40078
143#define DSLRADD 0x4007C
144
145
146/* LCD/TV-Out and HW DVD Registers (60000h 6FFFFh) */
147/* LCD/TV-Out */
148#define HTOTAL 0x60000
149#define HBLANK 0x60004
150#define HSYNC 0x60008
151#define VTOTAL 0x6000C
152#define VBLANK 0x60010
153#define VSYNC 0x60014
154#define LCDTV_C 0x60018
155#define OVRACT 0x6001C
156#define BCLRPAT 0x60020
157
158/* Display and Cursor Control Registers (70000h 7FFFFh) */
159#define DISP_SL 0x70000
160#define DISP_SLC 0x70004
161#define PIXCONF 0x70008
162#define PIXCONF1 0x70009
163#define BLTCNTL 0x7000C
164#define SWF 0x70014
165#define DPLYBASE 0x70020
166#define DPLYSTAS 0x70024
167#define CURCNTR 0x70080
168#define CURBASE 0x70084
169#define CURPOS 0x70088
170
171
172/* VGA Registers */
173
174/* SMRAM Registers */
175#define SMRAM 0x10
176
177/* Graphics Control Registers */
178#define GR_INDEX 0x3CE
179#define GR_DATA 0x3CF
180
181#define GR10 0x10
182#define GR11 0x11
183
184/* CRT Controller Registers */
185#define CR_INDEX_MDA 0x3B4
186#define CR_INDEX_CGA 0x3D4
187#define CR_DATA_MDA 0x3B5
188#define CR_DATA_CGA 0x3D5
189
190#define CR30 0x30
191#define CR31 0x31
192#define CR32 0x32
193#define CR33 0x33
194#define CR35 0x35
195#define CR39 0x39
196#define CR40 0x40
197#define CR41 0x41
198#define CR42 0x42
199#define CR70 0x70
200#define CR80 0x80
201#define CR81 0x82
202
203/* Extended VGA Registers */
204
205/* General Control and Status Registers */
206#define ST00 0x3C2
207#define ST01_MDA 0x3BA
208#define ST01_CGA 0x3DA
209#define FRC_READ 0x3CA
210#define FRC_WRITE_MDA 0x3BA
211#define FRC_WRITE_CGA 0x3DA
212#define MSR_READ 0x3CC
213#define MSR_WRITE 0x3C2
214
215/* Sequencer Registers */
216#define SR_INDEX 0x3C4
217#define SR_DATA 0x3C5
218
219#define SR01 0x01
220#define SR02 0x02
221#define SR03 0x03
222#define SR04 0x04
223#define SR07 0x07
224
225/* Graphics Controller Registers */
226#define GR00 0x00
227#define GR01 0x01
228#define GR02 0x02
229#define GR03 0x03
230#define GR04 0x04
231#define GR05 0x05
232#define GR06 0x06
233#define GR07 0x07
234#define GR08 0x08
235
236/* Attribute Controller Registers */
237#define ATTR_WRITE 0x3C0
238#define ATTR_READ 0x3C1
239
240/* VGA Color Palette Registers */
241
242/* CLUT */
243#define CLUT_DATA 0x3C9 /* DACDATA */
244#define CLUT_INDEX_READ 0x3C7 /* DACRX */
245#define CLUT_INDEX_WRITE 0x3C8 /* DACWX */
246#define DACMASK 0x3C6
247
248/* CRT Controller Registers */
249#define CR00 0x00
250#define CR01 0x01
251#define CR02 0x02
252#define CR03 0x03
253#define CR04 0x04
254#define CR05 0x05
255#define CR06 0x06
256#define CR07 0x07
257#define CR08 0x08
258#define CR09 0x09
259#define CR0A 0x0A
260#define CR0B 0x0B
261#define CR0C 0x0C
262#define CR0D 0x0D
263#define CR0E 0x0E
264#define CR0F 0x0F
265#define CR10 0x10
266#define CR11 0x11
267#define CR12 0x12
268#define CR13 0x13
269#define CR14 0x14
270#define CR15 0x15
271#define CR16 0x16
272#define CR17 0x17
273#define CR18 0x18
274
275#endif /* __I810_REGS_H__ */