Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
0e2e212c
Commit
0e2e212c
authored
Dec 11, 2002
by
James Simmons
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Anothe rattempt at commting.
parent
864d65fb
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
6758 additions
and
73 deletions
+6758
-73
Documentation/fb/intel810.txt
Documentation/fb/intel810.txt
+272
-0
drivers/video/Kconfig
drivers/video/Kconfig
+38
-0
drivers/video/Makefile
drivers/video/Makefile
+4
-3
drivers/video/aty/atyfb_base.c
drivers/video/aty/atyfb_base.c
+1
-1
drivers/video/cfbimgblt.c
drivers/video/cfbimgblt.c
+6
-5
drivers/video/console/fbcon.c
drivers/video/console/fbcon.c
+3
-3
drivers/video/fbmem.c
drivers/video/fbmem.c
+5
-0
drivers/video/fbmon.c
drivers/video/fbmon.c
+265
-58
drivers/video/i810/i810.h
drivers/video/i810/i810.h
+300
-0
drivers/video/i810/i810_accel.c
drivers/video/i810/i810_accel.c
+513
-0
drivers/video/i810/i810_dvt.c
drivers/video/i810/i810_dvt.c
+308
-0
drivers/video/i810/i810_gtf.c
drivers/video/i810/i810_gtf.c
+275
-0
drivers/video/i810/i810_main.c
drivers/video/i810/i810_main.c
+2248
-0
drivers/video/i810/i810_main.h
drivers/video/i810/i810_main.h
+205
-0
drivers/video/i810/i810_regs.h
drivers/video/i810/i810_regs.h
+274
-0
drivers/video/offb.c
drivers/video/offb.c
+2
-3
drivers/video/riva/fbdev.c.new
drivers/video/riva/fbdev.c.new
+2036
-0
include/linux/fb.h
include/linux/fb.h
+3
-0
No files found.
Documentation/fb/intel810.txt
0 → 100644
View file @
0e2e212c
Intel 810/815 Framebuffer driver
Tony Daplas <adaplas@pol.net>
http://i810fb.sourceforge.net
March 17, 2002
First Released: July 2001
================================================================
A. Introduction
This is a framebuffer driver for various Intel 810/815 compatible
graphics devices. These would include:
Intel 810
Intel 810E
Intel 810-DC100
Intel 815 Internal graphics only, 100Mhz FSB
Intel 815 Internal graphics only
Intel 815 Internal graphics and AGP
B. Features
- Choice of using Discrete Video Timings, VESA Generalized Timing
Formula, or a framebuffer specific database to set the video mode
- Supports a variable range of horizontal and vertical resolution, and
vertical refresh rates if the VESA Generalized Timing Formula is
enabled.
- Supports color depths of 8, 16, 24 and 32 bits per pixel
- Supports pseudocolor, directcolor, or truecolor visuals
- Full and optimized hardware acceleration at 8, 16 and 24 bpp
- Robust video state save and restore
- MTRR support
- Utilizes user-entered monitor specifications to automatically
calculate required video mode parameters.
- Can concurrently run with xfree86 running with native i810 drivers
- Hardware Cursor Support
C. List of available options
a. "video=i810fb"
enables the i810 driver
Recommendation: required
b. "xres:<value>"
select horizontal resolution in pixels
Recommendation: user preference
(default = 640)
c. "yres:<value>"
select vertical resolution in scanlines. If Discrete Video Timings
is enabled, this will be ignored and computed as 3*xres/4.
Recommendation: user preference
(default = 480)
d. "vyres:<value>"
select virtual vertical resolution in scanlines. If (0) or none
is specified, this will be computed against maximum available memory.
Recommendation: do not set
(default = 480)
e. "vram:<value>"
select amount of system RAM in MB to allocate for the video memory
Recommendation: 1 - 4 MB.
(default = 4)
f. "bpp:<value>"
select desired pixel depth
Recommendation: 8
(default = 8)
g. "hsync1/hsync2:<value>"
select the minimum and maximum Horizontal Sync Frequency of the
monitor in KHz. If a using a fixed frequency monitor, hsync1 must
be equal to hsync2.
Recommendation: check monitor manual for correct values
default (29/30)
h. "vsync1/vsync2:<value>"
select the minimum and maximum Vertical Sync Frequency of the monitor
in Hz. You can also use this option to lock your monitor's refresh
rate.
Recommendation: check monitor manual for correct values
(default = 60/60)
IMPORTANT: If you need to clamp your timings, try to give some
leeway for computational errors (over/underflows). Example: if
using vsync1/vsync2 = 60/60, make sure hsync1/hsync2 has at least
a 1 unit difference, and vice versa.
i. "voffset:<value>"
select at what offset in MB of the logical memory to allocate the
framebuffer memory. The intent is to avoid the memory blocks
used by standard graphics applications (XFree86). The default
offset (16 MB for a 64MB aperture, 8 MB for a 32MB aperture) will
avoid XFree86's usage and allows up to 7MB/15MB of framebuffer
memory. Depending on your usage, adjust the value up or down,
(0 for maximum usage, 31/63 MB for the least amount). Note, an
arbitrary setting may conflict with XFree86.
Recommendation: do not set
(default = 8 or 16 MB)
j. "accel"
enable text acceleration. This can be enabled/reenabled anytime
by using 'fbset -accel true/false'.
Recommendation: enable
(default = not set)
k. "mtrr"
enable MTRR. This allows data transfers to the framebuffer memory
to occur in bursts which can significantly increase performance.
Not very helpful with the i810/i815 because of 'shared memory'.
Recommendation: do not set
(default = not set)
l. "extvga"
if specified, secondary/external VGA output will always be enabled.
Useful if the BIOS turns off the VGA port when no monitor is attached.
The external VGA monitor can then be attached without rebooting.
Recommendation: do not set
(default = not set)
m. "sync"
Forces the hardware engine to do a "sync" or wait for the hardware
to finish before starting another instruction. This will produce a
more stable setup, but will be slower.
Recommendation: do not set
(default = not set)
n. "dcolor"
Use directcolor visual instead of truecolor for pixel depths greater
than 8 bpp. Useful for color tuning, such as gamma control.
Recommendation: do not set
(default = not set)
D. Kernel booting
Separate each option/option-pair by commas (,) and the option from its value
with a colon (:) as in the following:
video=i810fb:option1,option2:value2
Sample Usage
------------
In /etc/lilo.conf, add the line:
append="video=i810fb:vram:2,xres:1024,yres:768,bpp:8,hsync1:30,hsync2:55, \
vsync1:50,vsync2:85,accel,mtrr"
This will initialize the framebuffer to 1024x768 at 8bpp. The framebuffer
will use 2 MB of System RAM. MTRR support will be enabled. The refresh rate
will be computed based on the hsync1/hsync2 and vsync1/vsync2 values.
IMPORTANT:
You must include hsync1, hsync2, vsync1 and vsync2 to enable video modes
better than 640x480 at 60Hz.
E. Module options
The module parameters are essentially similar to the kernel
parameters. The main difference is that you need to include a Boolean value
(1 for TRUE, and 0 for FALSE) for those options which don't need a value.
Example, to enable MTRR, include "mtrr=1".
Sample Usage
------------
Using the same setup as described above, load the module like this:
modprobe i810fb vram=2 xres=1024 bpp=8 hsync1=30 hsync2=55 vsync1=50 \
vsync2=85 accel=1 mtrr=1
Or just add the following to /etc/modules.conf
options i810fb vram=2 xres=1024 bpp=16 hsync1=30 hsync2=55 vsync1=50 \
vsync2=85 accel=1 mtrr=1
and just do a
modprobe i810fb
F. Setup
a. Do your usual method of configuring the kernel.
make menuconfig/xconfig/config
b. Under "Code Maturity Options", enable "Prompt for experimental/
incomplete code/drivers".
c. Enable agpgart support for the Intel 810/815 on-board graphics.
This is required. The option is under "Character Devices"
d. Under "Graphics Support", select "Intel 810/815" either statically
or as a module. Choose "use VESA GTF for video timings" if you
need to maximize the capability of your display. To be on the
safe side, you can leave this unselected.
e. If you want a framebuffer console, enable it under "Console
Drivers"
f. Compile your kernel.
g. Load the driver as described in section D and E.
Optional:
h. If you are going to run XFree86 with its native drivers, the
standard XFree86 4.1.0 and 4.2.0 drivers should work as is.
However, there's a bug in the XFree86 i810 drivers. It attempts
to use XAA even when switched to the console. This will crash
your server. I have a fix at this site:
http://i810fb.sourceforge.net.
You can either use the patch, or just replace
/usr/X11R6/lib/modules/drivers/i810_drv.o
with the one provided at the website.
i. Try the DirectFB (http://www.directfb.org) + the i810 gfxdriver
patch to see the chipset in action (or inaction :-).
G. Acknowledgment:
1. Geert Uytterhoeven - his excellent howto and the virtual
framebuffer driver code made this possible.
2. Jeff Hartmann for his agpgart code.
3. The X developers. Insights were provided just by reading the
XFree86 source code.
4. Intel(c). For this value-oriented chipset driver and for
providing documentation.
5. Matt Sottek. His inputs and ideas helped in making some
optimizations possible.
H. Home Page:
A more complete, and probably updated information is provided at
http://i810fb.sourceforge.net.
###########################
Tony
drivers/video/Kconfig
View file @
0e2e212c
...
...
@@ -471,6 +471,44 @@ config FB_RIVA
module will be called rivafb.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
config FB_I810
tristate "Intel 810/815 support (EXPERIMENTAL)"
depends on FB && AGP && AGP_INTEL && EXPERIMENTAL && PCI
help
This driver supports the on-board graphics built in to the Intel 810
and 815 chipsets. Say Y if you have and plan to use such a board.
The driver is also available as a module ( = code which can be
inserted and removed from the running kernel whenever you want).
The module will be called i810fb.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
For more information, please read
<file:Documentation/fb/intel810.txt>
config FB_I810_GTF
bool "use VESA Generalized Timing Formula"
depends on FB_I810
help
If you say Y, then the VESA standard, Generalized Timing Formula
or GTF, will be used to calculate the required video timing values
per video mode. Since the GTF allows nondiscrete timings
(nondiscrete being a range of values as opposed to discrete being a
set of values), you'll be able to use any combination of horizontal
and vertical resolutions, and vertical refresh rates without having
to specify your own timing parameters. This is especially useful
to maximize the performance of an aging display, or if you just
have a display with nonstandard dimensions. A VESA compliant
monitor is recommended, but can still work with non-compliant ones.
If you need or want this, then select this option. The timings may
not be compliant with Intel's recommended values. Use at your own
risk.
If you say N, the driver will revert to discrete video timings
using a set recommended by Intel in their documentation.
If unsure, say N.
config FB_MATROX
tristate "Matrox acceleration"
depends on FB && PCI
...
...
drivers/video/Makefile
View file @
0e2e212c
...
...
@@ -12,8 +12,7 @@ export-objs := fbmem.o fbcmap.o fbmon.o modedb.o softcursor.o cfbfillrect.o
obj-$(CONFIG_VT)
+=
console/
# Add fbmon.o back into obj-$(CONFIG_FB) in 2.5.x
obj-$(CONFIG_FB)
+=
fbmem.o fbcmap.o modedb.o softcursor.o
obj-$(CONFIG_FB)
+=
fbmem.o fbmon.o fbcmap.o modedb.o softcursor.o
# Only include macmodes.o if we have FB support and are PPC
ifeq
($(CONFIG_FB),y)
obj-$(CONFIG_PPC)
+=
macmodes.o
...
...
@@ -42,7 +41,7 @@ obj-$(CONFIG_FB_SGIVW) += sgivwfb.o cfbfillrect.o cfbcopyarea.o cfbim
obj-$(CONFIG_FB_3DFX)
+=
tdfxfb.o
obj-$(CONFIG_FB_MAC)
+=
macfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_HP300)
+=
hpfb.o cfbfillrect.o cfbimgblt.o
obj-$(CONFIG_FB_OF)
+=
offb.o cfbfillrect.o cfbimgbl
i
t.o cfbcopyarea.o
obj-$(CONFIG_FB_OF)
+=
offb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o
obj-$(CONFIG_FB_IMSTT)
+=
imsttfb.o
obj-$(CONFIG_FB_RETINAZ3)
+=
retz3fb.o
obj-$(CONFIG_FB_CLGEN)
+=
clgenfb.o
...
...
@@ -74,6 +73,8 @@ obj-$(CONFIG_FB_RIVA) += riva/ cfbfillrect.o cfbcopyarea.o \
cfbimgblt.o vgastate.o
obj-$(CONFIG_FB_SIS)
+=
sis/
obj-$(CONFIG_FB_ATY)
+=
aty/ cfbimgblt.o
obj-$(CONFIG_FB_I810)
+=
i810/ cfbfillrect.o cfbcopyarea.o
\
cfbimgblt.o vgastate.o
obj-$(CONFIG_FB_SUN3)
+=
sun3fb.o
obj-$(CONFIG_FB_BWTWO)
+=
bwtwofb.o
...
...
drivers/video/aty/atyfb_base.c
View file @
0e2e212c
...
...
@@ -976,7 +976,7 @@ static int atyfb_release(struct fb_info *info, int user)
var
.
yres_virtual
=
var
.
yres
;
}
gen
_set_var
(
&
var
,
-
1
,
info
);
fb
_set_var
(
&
var
,
-
1
,
info
);
}
}
}
...
...
drivers/video/cfbimgblt.c
View file @
0e2e212c
...
...
@@ -103,10 +103,10 @@ static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8
{
/* Draw the penguin */
int
i
,
n
;
unsigned
long
bitmask
=
SHIFT_LOW
(
~
0UL
,
BITS_PER_LONG
-
p
->
var
.
bits_per_pixel
)
;
int
bpp
=
p
->
var
.
bits_per_pixel
;
unsigned
long
*
palette
=
(
unsigned
long
*
)
p
->
pseudo_palette
;
unsigned
long
*
dst
,
*
dst2
,
color
=
0
,
val
,
shift
;
unsigned
long
null_bits
=
BITS_PER_LONG
-
p
->
var
.
bits_per_pixel
;
unsigned
long
null_bits
=
BITS_PER_LONG
-
bpp
;
u8
*
src
=
image
->
data
;
dst2
=
(
unsigned
long
*
)
dst1
;
...
...
@@ -125,9 +125,10 @@ static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8
while
(
n
--
)
{
if
(
p
->
fix
.
visual
==
FB_VISUAL_TRUECOLOR
||
p
->
fix
.
visual
==
FB_VISUAL_DIRECTCOLOR
)
color
=
palette
[
*
src
]
&
bitmask
;
color
=
palette
[
*
src
];
else
color
=
*
src
&
bitmask
;
color
=
*
src
;
color
<<=
LEFT_POS
(
bpp
);
val
|=
SHIFT_HIGH
(
color
,
shift
);
if
(
shift
>=
null_bits
)
{
FB_WRITEL
(
val
,
dst
++
);
...
...
@@ -136,7 +137,7 @@ static inline void color_imageblit(struct fb_image *image, struct fb_info *p, u8
else
val
=
SHIFT_LOW
(
color
,
BITS_PER_LONG
-
shift
);
}
shift
+=
p
->
var
.
bits_per_pixel
;
shift
+=
bpp
;
shift
&=
(
BITS_PER_LONG
-
1
);
src
++
;
}
...
...
drivers/video/console/fbcon.c
View file @
0e2e212c
...
...
@@ -929,11 +929,11 @@ static void fbcon_set_display(int con, int init, int logo)
struct
display
*
q
=
&
fb_display
[
i
];
struct
vc_data
*
tmp
=
vc_cons
[
i
].
d
;
if
(
fontwidthvalid
(
p
,
vc
->
vc_font
.
width
))
{
if
(
!
fontwidthvalid
(
p
,
vc
->
vc_font
.
width
))
{
/* If we are not the first console on this
fb, copy the font from that console */
tmp
->
vc_font
.
width
=
vc
->
vc_font
.
width
;
tmp
->
vc_font
.
height
=
vc
->
vc_font
.
height
;
vc
->
vc_font
.
width
=
tmp
->
vc_font
.
width
;
vc
->
vc_font
.
height
=
tmp
->
vc_font
.
height
;
p
->
fontdata
=
q
->
fontdata
;
p
->
userfont
=
q
->
userfont
;
if
(
p
->
userfont
)
{
...
...
drivers/video/fbmem.c
View file @
0e2e212c
...
...
@@ -141,6 +141,8 @@ extern int pvr2fb_init(void);
extern
int
pvr2fb_setup
(
char
*
);
extern
int
sstfb_init
(
void
);
extern
int
sstfb_setup
(
char
*
);
extern
int
i810fb_init
(
void
);
extern
int
i810fb_setup
(
char
*
);
static
struct
{
const
char
*
name
;
...
...
@@ -235,6 +237,9 @@ static struct {
#ifdef CONFIG_FB_TRIDENT
{
"trident"
,
tridentfb_init
,
tridentfb_setup
},
#endif
#ifdef CONFIG_FB_I810
{
"i810fb"
,
i810fb_init
,
i810fb_setup
},
#endif
/*
* Generic drivers that are used as fallbacks
...
...
drivers/video/fbmon.c
View file @
0e2e212c
/*
* linux/drivers/video/fbmon.c
*
* Copyright (C)
1999 James Simmons
* Copyright (C)
2002 James Simmons <jsimmons@users.sf.net>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*
* Notes:
* This code handles the different types of monitors that are out their.
* Most video cards for example can support a mode like 800x600 but fix
* frequency monitors can't. So the code here checks if the monitor can
* support the mode as well as the card can. Fbmonospecs takes on
* different meaning with different types of monitors. For multifrequency
* monitors fbmonospecs represents the range of frequencies the monitor
* can support. Only one fbmonospec needs to be allocated. The fbmonospecs
* pointer in fb_info points to this one. If you specific a mode that has
* timing greater than the allowed range then setting the video mode will
* fail. With multifrequency monitors you can set any mode you like as long
* as you have a programmable clock on the video card.
* With fixed frequency monitors you have only a SET of very narrow
* allowed frequency ranges. So for a fixed fequency monitor you have a
* array of fbmonospecs. The fbmonospecs in fb_info represents the
* monitor frequency for the CURRENT mode. If you change the mode and ask
* for fbmonospecs you will NOT get the same values as before. Note this
* is not true for multifrequency monitors where you do get the same
* fbmonospecs each time. Also the values in each fbmonospecs represent the
* very narrow frequency band for range. Well you can't have exactly the
* same frequencies from fixed monitor. So some tolerance is excepted.
* By DEFAULT all monitors are assumed fixed frequency since they are so
* easy to fry or screw up a mode with. Just try setting a 800x600 mode on
* one. After you boot you can run a simple program the tells what kind of
* monitor you have. If you have a multifrequency monitor then you can set
* any mode size you like as long as your video card has a programmable clock.
* By default also besides assuming you have a fixed frequency monitor it
* assumes the monitor only supports lower modes. This way for example you
* can't set a 1280x1024 mode on a fixed frequency monitor that can only
* support up to 1024x768.
*
*/
#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/module.h>
int
fbmon_valid_timings
(
u_int
pixclock
,
u_int
htotal
,
u_int
vtotal
,
const
struct
fb_info
*
fb_info
)
/*
* EDID parser
*
* portions of this file were based on the EDID parser by
* John Fremlin <vii@users.sourceforge.net> and Ani Joshi <ajoshi@unixbox.com>
*/
#define EDID_LENGTH 0x80
#define EDID_HEADER 0x00
#define EDID_HEADER_END 0x07
#define ID_MANUFACTURER_NAME 0x08
#define ID_MANUFACTURER_NAME_END 0x09
#define ID_MODEL 0x0a
#define ID_SERIAL_NUMBER 0x0c
#define MANUFACTURE_WEEK 0x10
#define MANUFACTURE_YEAR 0x11
#define EDID_STRUCT_VERSION 0x12
#define EDID_STRUCT_REVISION 0x13
#define DPMS_FLAGS 0x18
#define ESTABLISHED_TIMING_1 0x23
#define ESTABLISHED_TIMING_2 0x24
#define MANUFACTURERS_TIMINGS 0x25
#define DETAILED_TIMING_DESCRIPTIONS_START 0x36
#define DETAILED_TIMING_DESCRIPTION_SIZE 18
#define NO_DETAILED_TIMING_DESCRIPTIONS 4
#define DETAILED_TIMING_DESCRIPTION_1 0x36
#define DETAILED_TIMING_DESCRIPTION_2 0x48
#define DETAILED_TIMING_DESCRIPTION_3 0x5a
#define DETAILED_TIMING_DESCRIPTION_4 0x6c
#define DESCRIPTOR_DATA 5
#define UPPER_NIBBLE( x ) \
(((128|64|32|16) & (x)) >> 4)
#define LOWER_NIBBLE( x ) \
((1|2|4|8) & (x))
#define COMBINE_HI_8LO( hi, lo ) \
( (((unsigned)hi) << 8) | (unsigned)lo )
#define COMBINE_HI_4LO( hi, lo ) \
( (((unsigned)hi) << 4) | (unsigned)lo )
#define PIXEL_CLOCK_LO (unsigned)block[ 0 ]
#define PIXEL_CLOCK_HI (unsigned)block[ 1 ]
#define PIXEL_CLOCK (COMBINE_HI_8LO( PIXEL_CLOCK_HI,PIXEL_CLOCK_LO )*1000
#define H_ACTIVE_LO (unsigned)block[ 2 ]
#define H_BLANKING_LO (unsigned)block[ 3 ]
#define H_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 4 ] )
#define H_ACTIVE COMBINE_HI_8LO( H_ACTIVE_HI, H_ACTIVE_LO )
#define H_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 4 ] )
#define H_BLANKING COMBINE_HI_8LO( H_BLANKING_HI, H_BLANKING_LO )
#define V_ACTIVE_LO (unsigned)block[ 5 ]
#define V_BLANKING_LO (unsigned)block[ 6 ]
#define V_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 7 ] )
#define V_ACTIVE COMBINE_HI_8LO( V_ACTIVE_HI, V_ACTIVE_LO )
#define V_BLANKING_HI LOWER_NIBBLE( (unsigned)block[ 7 ] )
#define V_BLANKING COMBINE_HI_8LO( V_BLANKING_HI, V_BLANKING_LO )
#define H_SYNC_OFFSET_LO (unsigned)block[ 8 ]
#define H_SYNC_WIDTH_LO (unsigned)block[ 9 ]
#define V_SYNC_OFFSET_LO UPPER_NIBBLE( (unsigned)block[ 10 ] )
#define V_SYNC_WIDTH_LO LOWER_NIBBLE( (unsigned)block[ 10 ] )
#define V_SYNC_WIDTH_HI ((unsigned)block[ 11 ] & (1|2))
#define V_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (4|8)) >> 2)
#define H_SYNC_WIDTH_HI (((unsigned)block[ 11 ] & (16|32)) >> 4)
#define H_SYNC_OFFSET_HI (((unsigned)block[ 11 ] & (64|128)) >> 6)
#define V_SYNC_WIDTH COMBINE_HI_4LO( V_SYNC_WIDTH_HI, V_SYNC_WIDTH_LO )
#define V_SYNC_OFFSET COMBINE_HI_4LO( V_SYNC_OFFSET_HI, V_SYNC_OFFSET_LO )
#define H_SYNC_WIDTH COMBINE_HI_4LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO )
#define H_SYNC_OFFSET COMBINE_HI_4LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO )
#define H_SIZE_LO (unsigned)block[ 12 ]
#define V_SIZE_LO (unsigned)block[ 13 ]
#define H_SIZE_HI UPPER_NIBBLE( (unsigned)block[ 14 ] )
#define V_SIZE_HI LOWER_NIBBLE( (unsigned)block[ 14 ] )
#define H_SIZE COMBINE_HI_8LO( H_SIZE_HI, H_SIZE_LO )
#define V_SIZE COMBINE_HI_8LO( V_SIZE_HI, V_SIZE_LO )
#define H_BORDER (unsigned)block[ 15 ]
#define V_BORDER (unsigned)block[ 16 ]
#define FLAGS (unsigned)block[ 17 ]
#define INTERLACED (FLAGS&128)
#define SYNC_TYPE (FLAGS&3<<3)
/* bits 4,3 */
#define SYNC_SEPARATE (3<<3)
#define HSYNC_POSITIVE (FLAGS & 4)
#define VSYNC_POSITIVE (FLAGS & 2)
const
unsigned
char
edid_v1_header
[]
=
{
0x00
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0xff
,
0x00
};
const
unsigned
char
edid_v1_descriptor_flag
[]
=
{
0x00
,
0x00
};
static
int
edid_checksum
(
unsigned
char
*
edid
)
{
#if 0
/*
* long long divisions .... $#%%#$
*/
unsigned long long hpicos, vpicos;
const unsigned long long _1e12 = 1000000000000ULL;
const struct fb_monspecs *monspecs = &fb_info->monspecs;
hpicos = (unsigned long long)htotal*(unsigned long long)pixclock;
vpicos = (unsigned long long)vtotal*(unsigned long long)hpicos;
if (!vpicos)
return 0;
if (monspecs->hfmin == 0)
return 1;
if (hpicos*monspecs->hfmin > _1e12 || hpicos*monspecs->hfmax < _1e12 ||
vpicos*monspecs->vfmin > _1e12 || vpicos*monspecs->vfmax < _1e12)
return 0;
#endif
return
1
;
unsigned
char
i
,
csum
=
0
;
for
(
i
=
0
;
i
<
EDID_LENGTH
;
i
++
)
csum
+=
edid
[
i
];
if
(
csum
==
0x00
)
{
/* checksum passed, everything's good */
return
1
;
}
else
{
printk
(
"EDID checksum failed, aborting
\n
"
);
return
0
;
}
}
int
fbmon_dpms
(
const
struct
fb_info
*
fb_info
)
static
int
edid_check_header
(
unsigned
char
*
edid
)
{
return
fb_info
->
monspecs
.
dpms
;
if
((
edid
[
0
]
!=
0x00
)
||
(
edid
[
1
]
!=
0xff
)
||
(
edid
[
2
]
!=
0xff
)
||
(
edid
[
3
]
!=
0xff
)
||
(
edid
[
4
]
!=
0xff
)
||
(
edid
[
5
]
!=
0xff
)
||
(
edid
[
6
]
!=
0xff
))
{
printk
(
"EDID header doesn't match EDID v1 header, aborting
\n
"
);
return
0
;
}
return
1
;
}
EXPORT_SYMBOL
(
fbmon_valid_timings
);
static
char
*
edid_get_vendor
(
unsigned
char
*
block
)
{
static
char
sign
[
4
];
unsigned
short
h
;
h
=
COMBINE_HI_8LO
(
block
[
0
],
block
[
1
]);
sign
[
0
]
=
((
h
>>
10
)
&
0x1f
)
+
'A'
-
1
;
sign
[
1
]
=
((
h
>>
5
)
&
0x1f
)
+
'A'
-
1
;
sign
[
2
]
=
(
h
&
0x1f
)
+
'A'
-
1
;
sign
[
3
]
=
0
;
return
sign
;
}
static
char
*
edid_get_monitor
(
unsigned
char
*
block
)
{
static
char
name
[
13
];
unsigned
i
;
const
unsigned
char
*
ptr
=
block
+
DESCRIPTOR_DATA
;
for
(
i
=
0
;
i
<
13
;
i
++
,
ptr
++
)
{
if
(
*
ptr
==
0xa
)
{
name
[
i
]
=
0x00
;
return
name
;
}
name
[
i
]
=
*
ptr
;
}
return
name
;
}
static
int
edid_is_timing_block
(
unsigned
char
*
block
)
{
if
((
block
[
0
]
==
0x00
)
&&
(
block
[
1
]
==
0x00
))
return
0
;
else
return
1
;
}
static
int
edid_is_monitor_block
(
unsigned
char
*
block
)
{
if
((
block
[
0
]
==
0x00
)
&&
(
block
[
1
]
==
0x00
)
&&
(
block
[
3
]
==
0xfc
))
return
1
;
else
return
0
;
}
static
void
parse_timing_block
(
unsigned
char
*
block
,
struct
fb_var_screeninfo
*
var
)
{
var
->
xres
=
var
->
xres_virtual
=
H_ACTIVE
;
var
->
yres
=
var
->
yres_virtual
=
V_ACTIVE
;
var
->
height
=
var
->
width
=
-
1
;
var
->
right_margin
=
H_SYNC_OFFSET
;
var
->
left_margin
=
(
H_ACTIVE
+
H_BLANKING
)
-
(
H_ACTIVE
+
H_SYNC_OFFSET
+
H_SYNC_WIDTH
);
var
->
upper_margin
=
V_BLANKING
-
V_SYNC_OFFSET
-
V_SYNC_WIDTH
;
var
->
lower_margin
=
V_SYNC_OFFSET
;
var
->
hsync_len
=
H_SYNC_WIDTH
;
var
->
vsync_len
=
V_SYNC_WIDTH
;
var
->
pixclock
=
PIXEL_CLOCK
;
var
->
pixclock
/=
1000
;
var
->
pixclock
=
KHZ2PICOS
(
var
->
pixclock
);
if
(
HSYNC_POSITIVE
)
var
->
sync
|=
FB_SYNC_HOR_HIGH_ACT
;
if
(
VSYNC_POSITIVE
)
var
->
sync
|=
FB_SYNC_VERT_HIGH_ACT
;
}
int
parse_edid
(
unsigned
char
*
edid
,
struct
fb_var_screeninfo
*
var
)
{
int
i
;
unsigned
char
*
block
,
*
vendor
,
*
monitor
;
if
(
!
(
edid_checksum
(
edid
)))
return
0
;
if
(
!
(
edid_check_header
(
edid
)))
return
0
;
printk
(
"EDID ver %d rev %d
\n
"
,
(
int
)
edid
[
EDID_STRUCT_VERSION
],
(
int
)
edid
[
EDID_STRUCT_REVISION
]);
vendor
=
edid_get_vendor
(
edid
+
ID_MANUFACTURER_NAME
);
block
=
edid
+
DETAILED_TIMING_DESCRIPTIONS_START
;
for
(
i
=
0
;
i
<
4
;
i
++
,
block
+=
DETAILED_TIMING_DESCRIPTION_SIZE
)
{
if
(
edid_is_monitor_block
(
block
))
{
monitor
=
edid_get_monitor
(
block
);
}
}
printk
(
"EDID: detected %s %s
\n
"
,
vendor
,
monitor
);
block
=
edid
+
DETAILED_TIMING_DESCRIPTIONS_START
;
for
(
i
=
0
;
i
<
4
;
i
++
,
block
+=
DETAILED_TIMING_DESCRIPTION_SIZE
)
{
if
(
edid_is_timing_block
(
block
))
{
parse_timing_block
(
block
,
var
);
}
}
return
1
;
}
char
*
get_EDID
(
struct
pci_dev
*
pdev
)
{
#ifdef CONFIG_ALL_PPC
static
char
*
propnames
[]
=
{
"DFP,EDID"
,
"LCD,EDID"
,
"EDID"
,
"EDID1"
,
NULL
};
unsigned
char
*
pedid
=
NULL
;
struct
device_node
*
dp
;
int
i
;
dp
=
pci_device_to_OF_node
(
pdev
);
while
(
dp
!=
NULL
)
{
for
(
i
=
0
;
propnames
[
i
]
!=
NULL
;
++
i
)
{
pedid
=
(
unsigned
char
*
)
get_property
(
dp
,
propnames
[
i
],
NULL
);
if
(
pedid
!=
NULL
)
return
pedid
;
}
dp
=
dp
->
child
;
}
return
pedid
;
#else
return
NULL
;
#endif
}
EXPORT_SYMBOL
(
parse_edid
);
EXPORT_SYMBOL
(
get_EDID
);
drivers/video/i810/i810.h
0 → 100644
View file @
0e2e212c
/*-*- linux-c -*-
* linux/drivers/video/i810.h -- Intel 810 General Definitions/Declarations
*
* Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
* All Rights Reserved
*
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
#ifndef __I810_H__
#define __I810_H__
#include <linux/list.h>
#include <linux/agp_backend.h>
#include <linux/fb.h>
#include <video/vga.h>
/* Fence */
#define TILEWALK_X (0 << 12)
#define TILEWALK_Y (1 << 12)
/* Raster ops */
#define COLOR_COPY_ROP 0xF0
#define PAT_COPY_ROP 0xCC
#define CLEAR_ROP 0x00
#define WHITE_ROP 0xFF
#define INVERT_ROP 0x55
#define XOR_ROP 0x5A
/* 2D Engine definitions */
#define SOLIDPATTERN 0x80000000
#define NONSOLID 0x00000000
#define BPP8 (0 << 24)
#define BPP16 (1 << 24)
#define BPP24 (2 << 24)
#define PIXCONF8 (2 << 16)
#define PIXCONF15 (4 << 16)
#define PIXCONF16 (5 << 16)
#define PIXCONF24 (6 << 16)
#define PIXCONF32 (7 << 16)
#define DYN_COLOR_EN (1 << 26)
#define DYN_COLOR_DIS (0 << 26)
#define INCREMENT 0x00000000
#define DECREMENT (0x01 << 30)
#define ARB_ON 0x00000001
#define ARB_OFF 0x00000000
#define SYNC_FLIP 0x00000000
#define ASYNC_FLIP 0x00000040
#define OPTYPE_MASK 0xE0000000
#define PARSER_MASK 0x001F8000
#define D2_MASK 0x001FC000
/* 2D mask */
/* Instruction type */
/* There are more but pertains to 3D */
#define PARSER 0x00000000
#define BLIT (0x02 << 29)
#define RENDER (0x03 << 29)
/* Parser */
#define NOP 0x00
/* No operation, padding */
#define BP_INT (0x01 << 23)
/* Breakpoint interrupt */
#define USR_INT (0x02 << 23)
/* User interrupt */
#define WAIT_FOR_EVNT (0x03 << 23)
/* Wait for event */
#define FLUSH (0x04 << 23)
#define CONTEXT_SEL (0x05 << 23)
#define REPORT_HEAD (0x07 << 23)
#define ARB_ON_OFF (0x08 << 23)
#define OVERLAY_FLIP (0x11 << 23)
#define LOAD_SCAN_INC (0x12 << 23)
#define LOAD_SCAN_EX (0x13 << 23)
#define FRONT_BUFFER (0x14 << 23)
#define DEST_BUFFER (0x15 << 23)
#define Z_BUFFER (0x16 << 23)
#define STORE_DWORD_IMM (0x20 << 23)
#define STORE_DWORD_IDX (0x21 << 23)
#define BATCH_BUFFER (0x30 << 23)
/* Blit */
#define SETUP_BLIT 0x00
#define SETUP_MONO_PATTERN_SL_BLT (0x10 << 22)
#define PIXEL_BLT (0x20 << 22)
#define SCANLINE_BLT (0x21 << 22)
#define TEXT_BLT (0x22 << 22)
#define TEXT_IMM_BLT (0x30 << 22)
#define COLOR_BLT (0x40 << 22)
#define MONO_PAT_BLIT (0x42 << 22)
#define SOURCE_COPY_BLIT (0x43 << 22)
#define MONO_SOURCE_COPY_BLIT (0x44 << 22)
#define SOURCE_COPY_IMMEDIATE (0x60 << 22)
#define MONO_SOURCE_COPY_IMMEDIATE (0x61 << 22)
#define VERSION_MAJOR 0
#define VERSION_MINOR 9
#define VERSION_TEENIE 0
#define BRANCH_VERSION ""
/* mvo: intel i815 */
#ifndef PCI_DEVICE_ID_INTEL_82815_100
#define PCI_DEVICE_ID_INTEL_82815_100 0x1102
#endif
#ifndef PCI_DEVICE_ID_INTEL_82815_NOAGP
#define PCI_DEVICE_ID_INTEL_82815_NOAGP 0x1112
#endif
#ifndef PCI_DEVICE_ID_INTEL_82815_FULL_CTRL
#define PCI_DEVICE_ID_INTEL_82815_FULL_CTRL 0x1130
#endif
/* General Defines */
#define I810_PAGESIZE 4096
#define MAX_DMA_SIZE (1024 * 4096)
#define SAREA_SIZE 4096
#define PCI_I810_MISCC 0x72
#define MMIO_SIZE (512*1024)
#define GTT_SIZE (16*1024)
#define RINGBUFFER_SIZE (64*1024)
#define PIXMAP_SIZE (4 * 4096)
#define CURSOR_SIZE 4096
#define OFF 0
#define ON 1
#define MAX_KEY 256
#define WAIT_COUNT 10000000
#define IRING_PAD 8
#define FONTDATAMAX 8192
/* Masks (AND ops) and OR's */
#define FB_START_MASK (0x3f << (32 - 6))
#define MMIO_ADDR_MASK (0x1FFF << (32 - 13))
#define FREQ_MASK 0x1EF
#define SCR_OFF 0x20
#define DRAM_ON 0x08
#define DRAM_OFF 0xE7
#define PG_ENABLE_MASK 0x01
#define RING_SIZE_MASK (RINGBUFFER_SIZE - 1);
/* defines for restoring registers partially */
#define ADDR_MAP_MASK (0x07 << 5)
#define DISP_CTRL ~0
#define PIXCONF_0 (0x64 << 8)
#define PIXCONF_2 (0xF3 << 24)
#define PIXCONF_1 (0xF0 << 16)
#define MN_MASK 0x3FF03FF
#define P_OR (0x7 << 4)
#define DAC_BIT (1 << 16)
#define INTERLACE_BIT (1 << 7)
#define IER_MASK (3 << 13)
#define IMR_MASK (3 << 13)
/* Power Management */
#define DPMS_MASK 0xF0000
#define POWERON 0x00000
#define STANDBY 0x20000
#define SUSPEND 0x80000
#define POWERDOWN 0xA0000
#define EMR_MASK ~0x3F
#define FW_BLC_MASK ~(0x3F|(7 << 8)|(0x3F << 12)|(7 << 20))
/* Ringbuffer */
#define RBUFFER_START_MASK 0xFFFFF000
#define RBUFFER_SIZE_MASK 0x001FF000
#define RBUFFER_HEAD_MASK 0x001FFFFC
#define RBUFFER_TAIL_MASK 0x001FFFF8
/* Video Timings */
#define REF_FREQ 24000000
#define TARGET_N_MAX 30
#define FLYBACK 550
#define V_FRONTPORCH 1
#define H_OFFSET 40
#define H_SCALEFACTOR 20
#define H_BLANKSCALE 128
#define H_GRADIENT 600
#define MAX_PIXELCLOCK 230000000
#define MIN_PIXELCLOCK 15000000
#define VFMAX 60
#define VFMIN 60
#define HFMAX 30000
#define HFMIN 29000
/* Cursor */
#define CURSOR_ENABLE_MASK 0x1000
#define CURSOR_MODE_64_TRANS 4
#define CURSOR_MODE_64_XOR 5
#define CURSOR_MODE_64_3C 6
#define COORD_INACTIVE 0
#define COORD_ACTIVE (1 << 4)
#define EXTENDED_PALETTE 1
/* AGP Memory Types*/
#define AGP_NORMAL_MEMORY 0
#define AGP_DCACHE_MEMORY 1
#define AGP_PHYSICAL_MEMORY 2
/* Allocated resource Flags */
#define FRAMEBUFFER_REQ 1
#define MMIO_REQ 2
#define PCI_DEVICE_ENABLED 4
#define HAS_FONTCACHE 8
/* driver flags */
#define HAS_MTRR 1
#define HAS_ACCELERATION 2
#define ALWAYS_SYNC 4
#define LOCKUP 8
struct
gtt_data
{
agp_memory
*
i810_fb_memory
;
agp_memory
*
i810_iring_memory
;
agp_memory
*
i810_cursor_memory
;
agp_memory
*
i810_pixmap_memory
;
};
struct
mode_registers
{
u32
pixclock
,
M
,
N
,
P
;
u8
cr00
,
cr01
,
cr02
,
cr03
;
u8
cr04
,
cr05
,
cr06
,
cr07
;
u8
cr09
,
cr10
,
cr11
,
cr12
;
u8
cr13
,
cr15
,
cr16
,
cr30
;
u8
cr31
,
cr32
,
cr33
,
cr35
,
cr39
;
u32
bpp8_100
,
bpp16_100
;
u32
bpp24_100
,
bpp8_133
;
u32
bpp16_133
,
bpp24_133
;
u8
msr
;
};
struct
heap_data
{
unsigned
long
physical
;
__u8
*
virtual
;
u32
offset
;
u32
size
;
};
struct
state_registers
{
u32
dclk_1d
,
dclk_2d
,
dclk_0ds
;
u32
pixconf
,
fw_blc
,
pgtbl_ctl
;
u32
fence0
,
hws_pga
,
dplystas
;
u16
bltcntl
,
hwstam
,
ier
,
iir
,
imr
;
u8
cr00
,
cr01
,
cr02
,
cr03
,
cr04
;
u8
cr05
,
cr06
,
cr07
,
cr08
,
cr09
;
u8
cr10
,
cr11
,
cr12
,
cr13
,
cr14
;
u8
cr15
,
cr16
,
cr17
,
cr80
,
gr10
;
u8
cr30
,
cr31
,
cr32
,
cr33
,
cr35
;
u8
cr39
,
cr41
,
cr70
,
sr01
,
msr
;
};
struct
i810fb_par
{
struct
mode_registers
regs
;
struct
state_registers
hw_state
;
struct
gtt_data
i810_gtt
;
struct
fb_ops
i810fb_ops
;
struct
pci_dev
*
dev
;
struct
heap_data
aperture
;
struct
heap_data
fb
;
struct
heap_data
iring
;
struct
heap_data
cursor_heap
;
struct
heap_data
pixmap
;
struct
vgastate
state
;
drm_agp_t
*
drm_agp
;
atomic_t
use_count
;
u32
pseudo_palette
[
17
];
unsigned
long
mmio_start_phys
;
u8
*
mmio_start_virtual
;
u32
cursor_reset
;
u8
red
[
64
];
u8
green
[
64
];
u8
blue
[
64
];
u32
pixmap_offset
;
u32
pitch
;
u32
pixconf
;
u32
watermark
;
u32
mem_freq
;
u32
res_flags
;
u32
dev_flags
;
u32
cur_tail
;
u32
depth
;
u32
blit_bpp
;
u32
ovract
;
int
mtrr_reg
;
u16
bltcntl
;
u8
interlace
;
};
/*
* Register I/O
*/
#define i810_readb(where, mmio) readb(mmio + where)
#define i810_readw(where, mmio) readw(mmio + where)
#define i810_readl(where, mmio) readl(mmio + where)
#define i810_writeb(where, mmio, val) writeb(val, mmio + where)
#define i810_writew(where, mmio, val) writew(val, mmio + where)
#define i810_writel(where, mmio, val) writel(val, mmio + where)
#endif
/* __I810_H__ */
drivers/video/i810/i810_accel.c
0 → 100644
View file @
0e2e212c
/*-*- linux-c -*-
* linux/drivers/video/i810_accel.c -- Hardware Acceleration
*
* Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
* All Rights Reserved
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
#include <linux/kernel.h>
#include <linux/fb.h>
#include "i810_regs.h"
#include "i810.h"
static
u32
i810fb_rop
[]
=
{
COLOR_COPY_ROP
,
/* ROP_COPY */
XOR_ROP
/* ROP_XOR */
};
/* Macros */
#define PUT_RING(n) { \
i810_writel(par->cur_tail, par->iring.virtual, n); \
par->cur_tail += 4; \
par->cur_tail &= RING_SIZE_MASK; \
}
extern
inline
void
flush_cache
(
void
);
extern
int
reinit_agp
(
struct
fb_info
*
info
);
/************************************************************/
/* BLT Engine Routines */
static
inline
void
i810_report_error
(
u8
*
mmio
)
{
printk
(
"IIR : 0x%04x
\n
"
"EIR : 0x%04x
\n
"
"PGTBL_ER: 0x%04x
\n
"
"IPEIR : 0x%04x
\n
"
"IPEHR : 0x%04x
\n
"
,
i810_readw
(
IIR
,
mmio
),
i810_readb
(
EIR
,
mmio
),
i810_readl
(
PGTBL_ER
,
mmio
),
i810_readl
(
IPEIR
,
mmio
),
i810_readl
(
IPEHR
,
mmio
));
}
/**
* wait_for_space - check ring buffer free space
* @space: amount of ringbuffer space needed in bytes
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* The function waits until a free space from the ringbuffer
* is available
*/
static
inline
int
wait_for_space
(
struct
i810fb_par
*
par
,
u32
space
)
{
u32
head
,
count
=
WAIT_COUNT
,
tail
;
u8
*
mmio
=
par
->
mmio_start_virtual
;
tail
=
par
->
cur_tail
;
while
(
count
--
)
{
head
=
i810_readl
(
IRING
+
4
,
mmio
)
&
RBUFFER_HEAD_MASK
;
if
((
tail
==
head
)
||
(
tail
>
head
&&
(
par
->
iring
.
size
-
tail
+
head
)
>=
space
)
||
(
tail
<
head
&&
(
head
-
tail
)
>=
space
))
{
return
0
;
}
}
printk
(
"ringbuffer lockup!!!
\n
"
);
i810_report_error
(
mmio
);
par
->
dev_flags
|=
LOCKUP
;
return
1
;
}
/**
* wait_for_engine_idle - waits for all hardware engines to finish
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* This waits for lring(0), iring(1), and batch(3), etc to finish and
* waits until ringbuffer is empty.
*/
static
inline
int
wait_for_engine_idle
(
struct
i810fb_par
*
par
)
{
u8
*
mmio
=
par
->
mmio_start_virtual
;
int
count
=
WAIT_COUNT
;
while
((
i810_readw
(
INSTDONE
,
mmio
)
&
0x7B
)
!=
0x7B
&&
--
count
);
if
(
count
)
return
0
;
printk
(
"accel engine lockup!!!
\n
"
);
printk
(
"INSTDONE: 0x%04x
\n
"
,
i810_readl
(
INSTDONE
,
mmio
));
i810_report_error
(
mmio
);
par
->
dev_flags
|=
LOCKUP
;
return
1
;
}
/* begin_iring - prepares the ringbuffer
* @space: length of sequence in dwords
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* Checks/waits for sufficent space in ringbuffer of size
* space. Returns the tail of the buffer
*/
static
inline
u32
begin_iring
(
struct
i810fb_par
*
par
,
u32
space
)
{
if
(
par
->
dev_flags
&
ALWAYS_SYNC
)
wait_for_engine_idle
(
par
);
return
wait_for_space
(
par
,
space
);
}
/**
* end_iring - advances the buffer
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* This advances the tail of the ringbuffer, effectively
* beginning the execution of the graphics instruction sequence.
*/
static
inline
void
end_iring
(
struct
i810fb_par
*
par
)
{
u8
*
mmio
=
par
->
mmio_start_virtual
;
i810_writel
(
IRING
,
mmio
,
par
->
cur_tail
);
}
/**
* source_copy_blit - BLIT transfer operation
* @dwidth: width of rectangular graphics data
* @dheight: height of rectangular graphics data
* @dpitch: bytes per line of destination buffer
* @xdir: direction of copy (left to right or right to left)
* @src: address of first pixel to read from
* @dest: address of first pixel to write to
* @from: source address
* @where: destination address
* @rop: raster operation
* @blit_bpp: pixel format which can be different from the
* framebuffer's pixelformat
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* This is a BLIT operation typically used when doing
* a 'Copy and Paste'
*/
static
inline
void
source_copy_blit
(
int
dwidth
,
int
dheight
,
int
dpitch
,
int
xdir
,
int
src
,
int
dest
,
int
rop
,
int
blit_bpp
,
struct
i810fb_par
*
par
)
{
if
(
begin_iring
(
par
,
24
+
IRING_PAD
))
return
;
PUT_RING
(
BLIT
|
SOURCE_COPY_BLIT
|
4
);
PUT_RING
(
xdir
|
rop
<<
16
|
dpitch
|
DYN_COLOR_EN
|
blit_bpp
);
PUT_RING
(
dheight
<<
16
|
dwidth
);
PUT_RING
(
dest
);
PUT_RING
(
dpitch
);
PUT_RING
(
src
);
end_iring
(
par
);
}
/**
* color_blit - solid color BLIT operation
* @width: width of destination
* @height: height of destination
* @pitch: pixels per line of the buffer
* @dest: address of first pixel to write to
* @where: destination
* @rop: raster operation
* @what: color to transfer
* @blit_bpp: pixel format which can be different from the
* framebuffer's pixelformat
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* A BLIT operation which can be used for color fill/rectangular fill
*/
static
inline
void
color_blit
(
int
width
,
int
height
,
int
pitch
,
int
dest
,
int
rop
,
int
what
,
int
blit_bpp
,
struct
i810fb_par
*
par
)
{
if
(
begin_iring
(
par
,
24
+
IRING_PAD
))
return
;
PUT_RING
(
BLIT
|
COLOR_BLT
|
3
);
PUT_RING
(
rop
<<
16
|
pitch
|
SOLIDPATTERN
|
DYN_COLOR_EN
|
blit_bpp
);
PUT_RING
(
height
<<
16
|
width
);
PUT_RING
(
dest
);
PUT_RING
(
what
);
PUT_RING
(
NOP
);
end_iring
(
par
);
}
/**
* mono_src_copy_imm_blit - color expand from system memory to framebuffer
* @dwidth: width of destination
* @dheight: height of destination
* @dpitch: pixels per line of the buffer
* @dsize: size of bitmap in double words
* @dest: address of first byte of pixel;
* @rop: raster operation
* @blit_bpp: pixelformat to use which can be different from the
* framebuffer's pixelformat
* @src: address of image data
* @bg: backgound color
* @fg: forground color
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* A color expand operation where the source data is placed in the
* ringbuffer itself. Useful for drawing text.
*
* REQUIREMENT:
* The end of a scanline must be padded to the next word.
*/
static
inline
void
mono_src_copy_imm_blit
(
int
dwidth
,
int
dheight
,
int
dpitch
,
int
dsize
,
int
blit_bpp
,
int
rop
,
int
dest
,
const
u32
*
src
,
int
bg
,
int
fg
,
struct
i810fb_par
*
par
)
{
u32
i
,
*
s
=
(
u32
*
)
src
;
if
(
begin_iring
(
par
,
24
+
(
dsize
<<
2
)
+
IRING_PAD
))
return
;
PUT_RING
(
BLIT
|
MONO_SOURCE_COPY_IMMEDIATE
|
(
4
+
dsize
));
PUT_RING
(
DYN_COLOR_EN
|
blit_bpp
|
rop
<<
16
|
dpitch
);
PUT_RING
(
dheight
<<
16
|
dwidth
);
PUT_RING
(
dest
);
PUT_RING
(
bg
);
PUT_RING
(
fg
);
for
(
i
=
dsize
;
i
--
;
)
PUT_RING
(
*
s
++
);
end_iring
(
par
);
}
/**
* mono_src_copy_blit - color expand from video memory to framebuffer
* @dwidth: width of destination
* @dheight: height of destination
* @dpitch: pixels per line of the buffer
* @qsize: size of bitmap in quad words
* @dest: address of first byte of pixel;
* @rop: raster operation
* @blit_bpp: pixelformat to use which can be different from the
* framebuffer's pixelformat
* @src: address of image data
* @bg: backgound color
* @fg: forground color
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* A color expand operation where the source data is in video memory.
* Useful for drawing text.
*
* REQUIREMENT:
* The end of a scanline must be padded to the next word.
*/
static
inline
void
mono_src_copy_blit
(
int
dwidth
,
int
dheight
,
int
dpitch
,
int
qsize
,
int
blit_bpp
,
int
rop
,
int
dest
,
int
src
,
int
bg
,
int
fg
,
struct
i810fb_par
*
par
)
{
if
(
begin_iring
(
par
,
32
+
IRING_PAD
))
return
;
PUT_RING
(
BLIT
|
MONO_SOURCE_COPY_BLIT
|
6
);
PUT_RING
(
DYN_COLOR_EN
|
blit_bpp
|
rop
<<
16
|
dpitch
|
1
<<
27
);
PUT_RING
(
dheight
<<
16
|
dwidth
);
PUT_RING
(
dest
);
PUT_RING
(
qsize
-
1
);
PUT_RING
(
src
);
PUT_RING
(
bg
);
PUT_RING
(
fg
);
end_iring
(
par
);
}
static
u32
get_buffer_offset
(
u32
size
,
struct
i810fb_par
*
par
)
{
u32
offset
;
if
(
par
->
pixmap_offset
+
size
>
par
->
pixmap
.
size
)
{
wait_for_engine_idle
(
par
);
par
->
pixmap_offset
=
0
;
}
offset
=
par
->
pixmap_offset
;
par
->
pixmap_offset
+=
size
;
return
offset
;
}
/**
* i810fb_iring_enable - enables/disables the ringbuffer
* @mode: enable or disable
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* Enables or disables the ringbuffer, effectively enabling or
* disabling the instruction/acceleration engine.
*/
static
inline
void
i810fb_iring_enable
(
struct
i810fb_par
*
par
,
u32
mode
)
{
u32
tmp
;
u8
*
mmio
=
par
->
mmio_start_virtual
;
tmp
=
i810_readl
(
IRING
+
12
,
mmio
);
if
(
mode
==
OFF
)
tmp
&=
~
1
;
else
tmp
|=
1
;
flush_cache
();
i810_writel
(
IRING
+
12
,
mmio
,
tmp
);
}
void
i810fb_fillrect
(
struct
fb_info
*
p
,
struct
fb_fillrect
*
rect
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
p
->
par
;
u32
dx
,
dy
,
width
,
height
,
dest
,
rop
=
0
,
color
=
0
;
if
(
!
p
->
var
.
accel_flags
||
par
->
dev_flags
&
LOCKUP
)
{
cfb_fillrect
(
p
,
rect
);
return
;
}
if
(
par
->
depth
==
4
)
{
wait_for_engine_idle
(
par
);
cfb_fillrect
(
p
,
rect
);
return
;
}
if
(
par
->
depth
==
1
)
color
=
rect
->
color
;
else
color
=
((
u32
*
)
(
p
->
pseudo_palette
))[
rect
->
color
];
rop
=
i810fb_rop
[
rect
->
rop
];
dx
=
rect
->
dx
*
par
->
depth
;
width
=
rect
->
width
*
par
->
depth
;
dy
=
rect
->
dy
;
height
=
rect
->
height
;
dest
=
p
->
fix
.
smem_start
+
(
dy
*
p
->
fix
.
line_length
)
+
dx
;
color_blit
(
width
,
height
,
p
->
fix
.
line_length
,
dest
,
rop
,
color
,
par
->
blit_bpp
,
par
);
}
void
i810fb_copyarea
(
struct
fb_info
*
p
,
struct
fb_copyarea
*
region
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
p
->
par
;
u32
sx
,
sy
,
dx
,
dy
,
pitch
,
width
,
height
,
src
,
dest
,
xdir
;
if
(
!
p
->
var
.
accel_flags
||
par
->
dev_flags
&
LOCKUP
)
{
cfb_copyarea
(
p
,
region
);
return
;
}
if
(
par
->
depth
==
4
)
{
wait_for_engine_idle
(
par
);
cfb_copyarea
(
p
,
region
);
return
;
}
dx
=
region
->
dx
*
par
->
depth
;
sx
=
region
->
sx
*
par
->
depth
;
width
=
region
->
width
*
par
->
depth
;
sy
=
region
->
sy
;
dy
=
region
->
dy
;
height
=
region
->
height
;
if
(
dx
<=
sx
)
{
xdir
=
INCREMENT
;
}
else
{
xdir
=
DECREMENT
;
sx
+=
width
-
1
;
dx
+=
width
-
1
;
}
if
(
dy
<=
sy
)
{
pitch
=
p
->
fix
.
line_length
;
}
else
{
pitch
=
(
-
(
p
->
fix
.
line_length
))
&
0xFFFF
;
sy
+=
height
-
1
;
dy
+=
height
-
1
;
}
src
=
p
->
fix
.
smem_start
+
(
sy
*
p
->
fix
.
line_length
)
+
sx
;
dest
=
p
->
fix
.
smem_start
+
(
dy
*
p
->
fix
.
line_length
)
+
dx
;
source_copy_blit
(
width
,
height
,
pitch
,
xdir
,
src
,
dest
,
PAT_COPY_ROP
,
par
->
blit_bpp
,
par
);
}
/*
* Blitting is done at 8x8 pixel-array at a time. If map is not
* monochrome or not a multiple of 8x8 pixels, cfb_imageblit will
* be called instead.
*/
void
i810fb_imageblit
(
struct
fb_info
*
p
,
struct
fb_image
*
image
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
p
->
par
;
u32
fg
=
0
,
bg
=
0
,
s_pitch
,
d_pitch
,
size
,
offset
,
dst
,
i
,
j
;
u8
*
s_addr
,
*
d_addr
;
if
(
!
p
->
var
.
accel_flags
||
par
->
dev_flags
&
LOCKUP
)
{
cfb_imageblit
(
p
,
image
);
return
;
}
if
(
par
->
depth
==
4
||
image
->
depth
!=
1
)
{
wait_for_engine_idle
(
par
);
cfb_imageblit
(
p
,
image
);
return
;
}
switch
(
p
->
var
.
bits_per_pixel
)
{
case
8
:
fg
=
image
->
fg_color
;
bg
=
image
->
bg_color
;
break
;
case
16
:
fg
=
((
u32
*
)(
p
->
pseudo_palette
))[
image
->
fg_color
];
bg
=
((
u32
*
)(
p
->
pseudo_palette
))[
image
->
bg_color
];
break
;
case
24
:
fg
=
((
u32
*
)(
p
->
pseudo_palette
))[
image
->
fg_color
];
bg
=
((
u32
*
)(
p
->
pseudo_palette
))[
image
->
bg_color
];
break
;
}
dst
=
p
->
fix
.
smem_start
+
(
image
->
dy
*
p
->
fix
.
line_length
)
+
(
image
->
dx
*
par
->
depth
);
s_pitch
=
image
->
width
/
8
;
d_pitch
=
(
s_pitch
+
1
)
&
~
1
;
size
=
d_pitch
*
image
->
height
;
if
(
image
->
width
&
15
)
{
offset
=
get_buffer_offset
(
size
,
par
);
d_addr
=
par
->
pixmap
.
virtual
+
offset
;
s_addr
=
image
->
data
;
for
(
i
=
image
->
height
;
i
--
;
)
{
for
(
j
=
0
;
j
<
s_pitch
;
j
++
)
i810_writeb
(
j
,
d_addr
,
s_addr
[
j
]);
s_addr
+=
s_pitch
;
d_addr
+=
d_pitch
;
}
mono_src_copy_blit
(
image
->
width
*
par
->
depth
,
image
->
height
,
p
->
fix
.
line_length
,
size
/
8
,
par
->
blit_bpp
,
PAT_COPY_ROP
,
dst
,
par
->
pixmap
.
physical
+
offset
,
bg
,
fg
,
par
);
}
/*
* immediate blit if width is a multiple of 16 (hardware requirement)
*/
else
{
mono_src_copy_imm_blit
(
image
->
width
*
par
->
depth
,
image
->
height
,
p
->
fix
.
line_length
,
size
/
4
,
par
->
blit_bpp
,
PAT_COPY_ROP
,
dst
,
(
u32
*
)
image
->
data
,
bg
,
fg
,
par
);
}
}
int
i810fb_sync
(
struct
fb_info
*
p
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
p
->
par
;
if
(
!
p
->
var
.
accel_flags
)
return
0
;
return
wait_for_engine_idle
(
par
);
}
/**
* i810fb_init_ringbuffer - initialize the ringbuffer
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* Initializes the ringbuffer by telling the device the
* size and location of the ringbuffer. It also sets
* the head and tail pointers = 0
*/
void
i810fb_init_ringbuffer
(
struct
i810fb_par
*
par
)
{
u32
tmp1
,
tmp2
;
u8
*
mmio
=
par
->
mmio_start_virtual
;
wait_for_engine_idle
(
par
);
i810fb_iring_enable
(
par
,
OFF
);
i810_writel
(
IRING
,
mmio
,
0
);
i810_writel
(
IRING
+
4
,
mmio
,
0
);
par
->
cur_tail
=
0
;
tmp2
=
i810_readl
(
IRING
+
8
,
mmio
)
&
~
RBUFFER_START_MASK
;
tmp1
=
par
->
iring
.
physical
;
i810_writel
(
IRING
+
8
,
mmio
,
tmp2
|
tmp1
);
tmp1
=
i810_readl
(
IRING
+
12
,
mmio
);
tmp1
&=
~
RBUFFER_SIZE_MASK
;
tmp2
=
(
par
->
iring
.
size
-
I810_PAGESIZE
)
&
RBUFFER_SIZE_MASK
;
i810_writel
(
IRING
+
12
,
mmio
,
tmp1
|
tmp2
);
i810fb_iring_enable
(
par
,
ON
);
}
drivers/video/i810/i810_dvt.c
0 → 100644
View file @
0e2e212c
/*-*- linux-c -*-
* linux/drivers/video/i810_dvt.c -- Intel 810 Discrete Video Timings (Intel)
*
* Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
* All Rights Reserved
*
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
#include <linux/kernel.h>
#include "i810_regs.h"
#include "i810.h"
struct
mode_registers
std_modes
[]
=
{
/* 640x480 @ 60Hz */
{
25000
,
0x0013
,
0x0003
,
0x40
,
0x5F
,
0x4F
,
0x50
,
0x82
,
0x51
,
0x9D
,
0x0B
,
0x10
,
0x40
,
0xE9
,
0x0B
,
0xDF
,
0x50
,
0xE7
,
0x04
,
0x02
,
0x01
,
0x01
,
0x01
,
0x00
,
0x01
,
0x22002000
,
0x22004000
,
0x22006000
,
0x22002000
,
0x22004000
,
0x22006000
,
0xC0
},
/* 640x480 @ 70Hz */
{
28000
,
0x0053
,
0x0010
,
0x40
,
0x61
,
0x4F
,
0x4F
,
0x85
,
0x52
,
0x9A
,
0xF2
,
0x10
,
0x40
,
0xE0
,
0x03
,
0xDF
,
0x50
,
0xDF
,
0xF3
,
0x01
,
0x01
,
0x01
,
0x01
,
0x00
,
0x01
,
0x22002000
,
0x22004000
,
0x22005000
,
0x22002000
,
0x22004000
,
0x22005000
,
0xC0
},
/* 640x480 @ 72Hz */
{
31000
,
0x0013
,
0x0002
,
0x40
,
0x63
,
0x4F
,
0x4F
,
0x87
,
0x52
,
0x97
,
0x06
,
0x0F
,
0x40
,
0xE8
,
0x0B
,
0xDF
,
0x50
,
0xDF
,
0x07
,
0x02
,
0x01
,
0x01
,
0x01
,
0x00
,
0x01
,
0x22003000
,
0x22005000
,
0x22007000
,
0x22003000
,
0x22005000
,
0x22007000
,
0xC0
},
/* 640x480 @ 75Hz */
{
31000
,
0x0013
,
0x0002
,
0x40
,
0x64
,
0x4F
,
0x4F
,
0x88
,
0x51
,
0x99
,
0xF2
,
0x10
,
0x40
,
0xE0
,
0x03
,
0xDF
,
0x50
,
0xDF
,
0xF3
,
0x01
,
0x01
,
0x01
,
0x01
,
0x00
,
0x01
,
0x22003000
,
0x22005000
,
0x22007000
,
0x22003000
,
0x22005000
,
0x22007000
,
0xC0
},
/* 640x480 @ 85Hz */
{
36000
,
0x0010
,
0x0001
,
0x40
,
0x63
,
0x4F
,
0x4F
,
0x87
,
0x56
,
0x9D
,
0xFB
,
0x10
,
0x40
,
0xE0
,
0x03
,
0xDF
,
0x50
,
0xDF
,
0xFC
,
0x01
,
0x01
,
0x01
,
0x01
,
0x00
,
0x01
,
0x22003000
,
0x22005000
,
0x22107000
,
0x22003000
,
0x22005000
,
0x22107000
,
0xC0
},
/* 800x600 @ 56Hz */
{
36000
,
0x0010
,
0x0001
,
0x40
,
0x7B
,
0x63
,
0x63
,
0x9F
,
0x66
,
0x8F
,
0x6F
,
0x10
,
0x40
,
0x58
,
0x0A
,
0x57
,
0xC8
,
0x57
,
0x70
,
0x02
,
0x02
,
0x02
,
0x02
,
0x00
,
0x01
,
0x22003000
,
0x22005000
,
0x22107000
,
0x22003000
,
0x22005000
,
0x22107000
,
0x00
},
/* 800x600 @ 60Hz */
{
40000
,
0x0008
,
0x0001
,
0x30
,
0x7F
,
0x63
,
0x63
,
0x83
,
0x68
,
0x18
,
0x72
,
0x10
,
0x40
,
0x58
,
0x0C
,
0x57
,
0xC8
,
0x57
,
0x73
,
0x02
,
0x02
,
0x02
,
0x02
,
0x00
,
0x00
,
0x22003000
,
0x22006000
,
0x22108000
,
0x22003000
,
0x22006000
,
0x22108000
,
0x00
},
/* 800x600 @ 70Hz */
{
45000
,
0x0054
,
0x0015
,
0x30
,
0x7D
,
0x63
,
0x63
,
0x81
,
0x68
,
0x12
,
0x6f
,
0x10
,
0x40
,
0x58
,
0x0b
,
0x57
,
0x64
,
0x57
,
0x70
,
0x02
,
0x02
,
0x02
,
0x02
,
0x00
,
0x00
,
0x22004000
,
0x22007000
,
0x2210A000
,
0x22004000
,
0x22007000
,
0x2210A000
,
0x00
},
/* 800x600 @ 72Hz */
{
50000
,
0x0017
,
0x0004
,
0x30
,
0x7D
,
0x63
,
0x63
,
0x81
,
0x6A
,
0x19
,
0x98
,
0x10
,
0x40
,
0x7C
,
0x02
,
0x57
,
0xC8
,
0x57
,
0x99
,
0x02
,
0x02
,
0x02
,
0x02
,
0x00
,
0x00
,
0x22004000
,
0x22007000
,
0x2210A000
,
0x22004000
,
0x22007000
,
0x2210A000
,
0x00
},
/* 800x600 @ 75Hz */
{
49000
,
0x001F
,
0x0006
,
0x30
,
0x7F
,
0x63
,
0x63
,
0x83
,
0x65
,
0x0F
,
0x6F
,
0x10
,
0x40
,
0x58
,
0x0B
,
0x57
,
0xC8
,
0x57
,
0x70
,
0x02
,
0x02
,
0x02
,
0x02
,
0x00
,
0x00
,
0x22004000
,
0x22007000
,
0x2210B000
,
0x22004000
,
0x22007000
,
0x2210B000
,
0x00
},
/* 800x600 @ 85Hz */
{
56000
,
0x0049
,
0x000E
,
0x30
,
0x7E
,
0x63
,
0x63
,
0x82
,
0x67
,
0x0F
,
0x75
,
0x10
,
0x40
,
0x58
,
0x0B
,
0x57
,
0xC8
,
0x57
,
0x76
,
0x02
,
0x02
,
0x02
,
0x02
,
0x00
,
0x00
,
0x22004000
,
0x22108000
,
0x2210b000
,
0x22004000
,
0x22108000
,
0x2210b000
,
0x00
},
/* 1024x768 @ 60Hz */
{
65000
,
0x003F
,
0x000A
,
0x30
,
0xA3
,
0x7F
,
0x7F
,
0x87
,
0x83
,
0x94
,
0x24
,
0x10
,
0x40
,
0x02
,
0x08
,
0xFF
,
0x80
,
0xFF
,
0x25
,
0x03
,
0x02
,
0x03
,
0x02
,
0x00
,
0x00
,
0x22005000
,
0x22109000
,
0x2220D000
,
0x22005000
,
0x22109000
,
0x2220D000
,
0xC0
},
/* 1024x768 @ 70Hz */
{
75000
,
0x0017
,
0x0002
,
0x30
,
0xA1
,
0x7F
,
0x7F
,
0x85
,
0x82
,
0x93
,
0x24
,
0x10
,
0x40
,
0x02
,
0x08
,
0xFF
,
0x80
,
0xFF
,
0x25
,
0x03
,
0x02
,
0x03
,
0x02
,
0x00
,
0x00
,
0x22005000
,
0x2210A000
,
0x2220F000
,
0x22005000
,
0x2210A000
,
0x2220F000
,
0xC0
},
/* 1024x768 @ 75Hz */
{
78000
,
0x0050
,
0x0017
,
0x20
,
0x9F
,
0x7F
,
0x7F
,
0x83
,
0x81
,
0x8D
,
0x1E
,
0x10
,
0x40
,
0x00
,
0x03
,
0xFF
,
0x80
,
0xFF
,
0x1F
,
0x03
,
0x02
,
0x03
,
0x02
,
0x00
,
0x00
,
0x22006000
,
0x2210B000
,
0x22210000
,
0x22006000
,
0x2210B000
,
0x22210000
,
0x00
},
/* 1024x768 @ 85Hz */
{
94000
,
0x003D
,
0x000E
,
0x20
,
0xA7
,
0x7F
,
0x7F
,
0x8B
,
0x85
,
0x91
,
0x26
,
0x10
,
0x40
,
0x00
,
0x03
,
0xFF
,
0x80
,
0xFF
,
0x27
,
0x03
,
0x02
,
0x03
,
0x02
,
0x00
,
0x00
,
0x22007000
,
0x2220E000
,
0x22212000
,
0x22007000
,
0x2220E000
,
0x22212000
,
0x00
},
/* 1152x864 @ 60Hz */
{
80000
,
0x0008
,
0x0001
,
0x20
,
0xB3
,
0x8F
,
0x8F
,
0x97
,
0x93
,
0x9f
,
0x87
,
0x10
,
0x40
,
0x60
,
0x03
,
0x5F
,
0x90
,
0x5f
,
0x88
,
0x03
,
0x03
,
0x03
,
0x03
,
0x00
,
0x00
,
0x2220C000
,
0x22210000
,
0x22415000
,
0x2220C000
,
0x22210000
,
0x22415000
,
0x00
},
/* 1152x864 @ 70Hz */
{
96000
,
0x000a
,
0x0001
,
0x20
,
0xbb
,
0x8F
,
0x8F
,
0x9f
,
0x98
,
0x87
,
0x82
,
0x10
,
0x40
,
0x60
,
0x03
,
0x5F
,
0x90
,
0x5F
,
0x83
,
0x03
,
0x03
,
0x03
,
0x03
,
0x00
,
0x00
,
0x22107000
,
0x22210000
,
0x22415000
,
0x22107000
,
0x22210000
,
0x22415000
,
0x00
},
/* 1152x864 @ 72Hz */
{
99000
,
0x001f
,
0x0006
,
0x20
,
0xbb
,
0x8F
,
0x8F
,
0x9f
,
0x98
,
0x87
,
0x83
,
0x10
,
0x40
,
0x60
,
0x03
,
0x5F
,
0x90
,
0x5F
,
0x84
,
0x03
,
0x03
,
0x03
,
0x03
,
0x00
,
0x00
,
0x22107000
,
0x22210000
,
0x22415000
,
0x22107000
,
0x22210000
,
0x22415000
,
0x00
},
/* 1152x864 @ 75Hz */
{
108000
,
0x0010
,
0x0002
,
0x20
,
0xC3
,
0x8F
,
0x8F
,
0x87
,
0x97
,
0x07
,
0x82
,
0x10
,
0x40
,
0x60
,
0x03
,
0x5F
,
0x90
,
0x5F
,
0x83
,
0x03
,
0x03
,
0x03
,
0x03
,
0x00
,
0x01
,
0x22107000
,
0x22210000
,
0x22415000
,
0x22107000
,
0x22210000
,
0x22415000
,
0x00
},
/* 1152x864 @ 85Hz */
{
121000
,
0x006D
,
0x0014
,
0x20
,
0xc0
,
0x8F
,
0x8F
,
0x84
,
0x97
,
0x07
,
0x93
,
0x10
,
0x40
,
0x60
,
0x03
,
0x5F
,
0x90
,
0x5F
,
0x94
,
0x03
,
0x03
,
0x03
,
0x03
,
0x00
,
0x01
,
0x2220C000
,
0x22210000
,
0x22415000
,
0x2220C000
,
0x22210000
,
0x22415000
,
0x0
},
/* 1280x960 @ 60Hz */
{
108000
,
0x0010
,
0x0002
,
0x20
,
0xDC
,
0x9F
,
0x9F
,
0x80
,
0xAB
,
0x99
,
0xE6
,
0x10
,
0x40
,
0xC0
,
0x03
,
0xBF
,
0xA0
,
0xBF
,
0xE7
,
0x03
,
0x03
,
0x03
,
0x03
,
0x00
,
0x01
,
0x2210A000
,
0x22210000
,
0x22415000
,
0x2210A000
,
0x22210000
,
0x22415000
,
0x00
},
/* 1280x960 @ 75Hz */
{
129000
,
0x0029
,
0x0006
,
0x20
,
0xD3
,
0x9F
,
0x9F
,
0x97
,
0xaa
,
0x1b
,
0xE8
,
0x10
,
0x40
,
0xC0
,
0x03
,
0xBF
,
0xA0
,
0xBF
,
0xE9
,
0x03
,
0x03
,
0x03
,
0x03
,
0x00
,
0x01
,
0x2210A000
,
0x22210000
,
0x2241B000
,
0x2210A000
,
0x22210000
,
0x2241B000
,
0x00
},
/* 1280x960 @ 85Hz */
{
148000
,
0x0042
,
0x0009
,
0x20
,
0xD3
,
0x9F
,
0x9F
,
0x97
,
0xA7
,
0x1B
,
0xF1
,
0x10
,
0x40
,
0xC0
,
0x03
,
0xBF
,
0xA0
,
0xBF
,
0xF2
,
0x03
,
0x03
,
0x03
,
0x03
,
0x00
,
0x01
,
0x2210A000
,
0x22220000
,
0x2241D000
,
0x2210A000
,
0x22220000
,
0x2241D000
,
0x00
},
/* 1600x1200 @ 60Hz */
{
162000
,
0x0019
,
0x0006
,
0x10
,
0x09
,
0xC7
,
0xC7
,
0x8D
,
0xcf
,
0x07
,
0xE0
,
0x10
,
0x40
,
0xB0
,
0x03
,
0xAF
,
0xC8
,
0xAF
,
0xE1
,
0x04
,
0x04
,
0x04
,
0x04
,
0x01
,
0x00
,
0x2210b000
,
0x22416000
,
0x44419000
,
0x2210b000
,
0x22416000
,
0x44419000
,
0x00
},
/* 1600x1200 @ 65 Hz */
{
175000
,
0x005d
,
0x0018
,
0x10
,
0x09
,
0xC7
,
0xC7
,
0x8D
,
0xcf
,
0x07
,
0xE0
,
0x10
,
0x40
,
0xB0
,
0x03
,
0xAF
,
0xC8
,
0xAF
,
0xE1
,
0x04
,
0x04
,
0x04
,
0x04
,
0x01
,
0x00
,
0x2210c000
,
0x22416000
,
0x44419000
,
0x2210c000
,
0x22416000
,
0x44419000
,
0x00
},
/* 1600x1200 @ 70 Hz */
{
189000
,
0x003D
,
0x000e
,
0x10
,
0x09
,
0xC7
,
0xC7
,
0x8d
,
0xcf
,
0x07
,
0xE0
,
0x10
,
0x40
,
0xb0
,
0x03
,
0xAF
,
0xC8
,
0xaf
,
0xE1
,
0x04
,
0x04
,
0x04
,
0x04
,
0x01
,
0x00
,
0x2220e000
,
0x22416000
,
0x44419000
,
0x2220e000
,
0x22416000
,
0x44419000
,
0x00
},
/* 1600x1200 @ 72 Hz */
{
195000
,
0x003f
,
0x000e
,
0x10
,
0x0b
,
0xC7
,
0xC7
,
0x8f
,
0xd5
,
0x0b
,
0xE1
,
0x10
,
0x40
,
0xb0
,
0x03
,
0xAF
,
0xC8
,
0xaf
,
0xe2
,
0x04
,
0x04
,
0x04
,
0x04
,
0x01
,
0x00
,
0x2220e000
,
0x22416000
,
0x44419000
,
0x2220e000
,
0x22416000
,
0x44419000
,
0x00
},
/* 1600x1200 @ 75 Hz */
{
202000
,
0x0024
,
0x0007
,
0x10
,
0x09
,
0xC7
,
0xC7
,
0x8d
,
0xcf
,
0x07
,
0xE0
,
0x10
,
0x40
,
0xb0
,
0x03
,
0xAF
,
0xC8
,
0xaf
,
0xE1
,
0x04
,
0x04
,
0x04
,
0x04
,
0x01
,
0x00
,
0x2220e000
,
0x22416000
,
0x44419000
,
0x2220e000
,
0x22416000
,
0x44419000
,
0x00
},
/* 1600x1200 @ 85 Hz */
{
229000
,
0x0029
,
0x0007
,
0x10
,
0x09
,
0xC7
,
0xC7
,
0x8d
,
0xcf
,
0x07
,
0xE0
,
0x10
,
0x40
,
0xb0
,
0x03
,
0xAF
,
0xC8
,
0xaf
,
0xE1
,
0x04
,
0x04
,
0x04
,
0x04
,
0x01
,
0x00
,
0x22210000
,
0x22416000
,
0x0
,
0x22210000
,
0x22416000
,
0x0
,
0x00
},
};
void
round_off_xres
(
u32
*
xres
)
{
if
(
*
xres
<
800
)
*
xres
=
640
;
if
(
*
xres
<
1024
&&
*
xres
>=
800
)
*
xres
=
800
;
if
(
*
xres
<
1152
&&
*
xres
>=
1024
)
*
xres
=
1024
;
if
(
*
xres
<
1280
&&
*
xres
>=
1152
)
*
xres
=
1152
;
if
(
*
xres
<
1600
&&
*
xres
>=
1280
)
*
xres
=
1280
;
if
(
*
xres
>=
1600
)
*
xres
=
1600
;
}
inline
void
round_off_yres
(
u32
*
xres
,
u32
*
yres
)
{
*
yres
=
(
*
xres
*
3
)
>>
2
;
}
void
i810fb_encode_registers
(
const
struct
fb_var_screeninfo
*
var
,
struct
i810fb_par
*
par
,
u32
xres
,
u32
yres
)
{
u32
diff
=
0
,
diff_best
=
0xFFFFFFFF
,
i
=
0
,
i_best
=
0
;
u8
hfl
;
hfl
=
(
u8
)
((
xres
>>
3
)
-
1
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
std_modes
);
i
++
)
{
if
(
std_modes
[
i
].
cr01
==
hfl
)
{
if
(
std_modes
[
i
].
pixclock
<=
par
->
regs
.
pixclock
)
diff
=
par
->
regs
.
pixclock
-
std_modes
[
i
].
pixclock
;
if
(
diff
<
diff_best
)
{
i_best
=
i
;
diff_best
=
diff
;
}
}
}
par
->
regs
=
std_modes
[
i_best
];
/* overlay */
par
->
ovract
=
((
xres
+
var
->
right_margin
+
var
->
hsync_len
+
var
->
left_margin
-
32
)
|
((
xres
-
32
)
<<
16
));
}
void
i810fb_fill_var_timings
(
struct
fb_var_screeninfo
*
var
)
{
struct
i810fb_par
par
;
u32
total
,
xres
,
yres
;
xres
=
var
->
xres
;
yres
=
var
->
yres
;
par
.
regs
.
pixclock
=
1000000000
/
var
->
pixclock
;
i810fb_encode_registers
(
var
,
&
par
,
xres
,
yres
);
total
=
((
par
.
regs
.
cr00
|
(
par
.
regs
.
cr35
&
1
)
<<
8
)
+
3
)
<<
3
;
var
->
pixclock
=
1000000000
/
par
.
regs
.
pixclock
;
var
->
right_margin
=
(
par
.
regs
.
cr04
<<
3
)
-
xres
;
var
->
hsync_len
=
((
par
.
regs
.
cr05
&
0x1F
)
-
(
par
.
regs
.
cr04
&
0x1F
))
<<
3
;
var
->
left_margin
=
(
total
-
(
xres
+
var
->
right_margin
+
var
->
hsync_len
));
var
->
sync
=
FB_SYNC_ON_GREEN
;
if
(
~
(
par
.
regs
.
msr
&
(
1
<<
6
)))
var
->
sync
|=
FB_SYNC_HOR_HIGH_ACT
;
if
(
~
(
par
.
regs
.
msr
&
(
1
<<
7
)))
var
->
sync
|=
FB_SYNC_VERT_HIGH_ACT
;
total
=
((
par
.
regs
.
cr06
|
(
par
.
regs
.
cr30
&
0x0F
)
<<
8
))
+
2
;
var
->
lower_margin
=
(
par
.
regs
.
cr10
|
(
par
.
regs
.
cr32
&
0x0F
)
<<
8
)
-
yres
;
var
->
vsync_len
=
(
par
.
regs
.
cr11
&
0x0F
)
-
(
var
->
lower_margin
&
0x0F
);
var
->
upper_margin
=
total
-
(
yres
+
var
->
lower_margin
+
var
->
vsync_len
);
}
u32
i810_get_watermark
(
struct
fb_var_screeninfo
*
var
,
struct
i810fb_par
*
par
)
{
struct
mode_registers
*
params
=
&
par
->
regs
;
u32
wmark
=
0
;
if
(
par
->
mem_freq
==
100
)
{
switch
(
var
->
bits_per_pixel
)
{
case
8
:
wmark
=
params
->
bpp8_100
;
break
;
case
16
:
wmark
=
params
->
bpp16_100
;
break
;
case
24
:
case
32
:
wmark
=
params
->
bpp24_100
;
}
}
else
{
switch
(
var
->
bits_per_pixel
)
{
case
8
:
wmark
=
params
->
bpp8_133
;
break
;
case
16
:
wmark
=
params
->
bpp16_133
;
break
;
case
24
:
case
32
:
wmark
=
params
->
bpp24_133
;
}
}
return
wmark
;
}
drivers/video/i810/i810_gtf.c
0 → 100644
View file @
0e2e212c
/*-*- linux-c -*-
* linux/drivers/video/i810_main.h -- Intel 810 Nondiscrete Video Timings
* (VESA GTF)
*
* Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
* All Rights Reserved
*
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
#include <linux/kernel.h>
#include "i810_regs.h"
#include "i810.h"
/*
* FIFO and Watermark tables - based almost wholly on i810_wmark.c in
* XFree86 v4.03 by Precision Insight. Slightly modified for integer
* operation, instead of float
*/
struct
wm_info
{
u32
freq
;
u32
wm
;
};
struct
wm_info
i810_wm_8_100
[]
=
{
{
15
,
0x0070c000
},
{
19
,
0x0070c000
},
{
25
,
0x22003000
},
{
28
,
0x22003000
},
{
31
,
0x22003000
},
{
36
,
0x22007000
},
{
40
,
0x22007000
},
{
45
,
0x22007000
},
{
49
,
0x22008000
},
{
50
,
0x22008000
},
{
56
,
0x22008000
},
{
65
,
0x22008000
},
{
75
,
0x22008000
},
{
78
,
0x22008000
},
{
80
,
0x22008000
},
{
94
,
0x22008000
},
{
96
,
0x22107000
},
{
99
,
0x22107000
},
{
108
,
0x22107000
},
{
121
,
0x22107000
},
{
128
,
0x22107000
},
{
132
,
0x22109000
},
{
135
,
0x22109000
},
{
157
,
0x2210b000
},
{
162
,
0x2210b000
},
{
175
,
0x2210b000
},
{
189
,
0x2220e000
},
{
195
,
0x2220e000
},
{
202
,
0x2220e000
},
{
204
,
0x2220e000
},
{
218
,
0x2220f000
},
{
229
,
0x22210000
},
{
234
,
0x22210000
},
};
struct
wm_info
i810_wm_16_100
[]
=
{
{
15
,
0x0070c000
},
{
19
,
0x0020c000
},
{
25
,
0x22006000
},
{
28
,
0x22006000
},
{
31
,
0x22007000
},
{
36
,
0x22007000
},
{
40
,
0x22007000
},
{
45
,
0x22007000
},
{
49
,
0x22009000
},
{
50
,
0x22009000
},
{
56
,
0x22108000
},
{
65
,
0x2210e000
},
{
75
,
0x2210e000
},
{
78
,
0x2210e000
},
{
80
,
0x22210000
},
{
94
,
0x22210000
},
{
96
,
0x22210000
},
{
99
,
0x22210000
},
{
108
,
0x22210000
},
{
121
,
0x22210000
},
{
128
,
0x22210000
},
{
132
,
0x22314000
},
{
135
,
0x22314000
},
{
157
,
0x22415000
},
{
162
,
0x22416000
},
{
175
,
0x22416000
},
{
189
,
0x22416000
},
{
195
,
0x22416000
},
{
202
,
0x22416000
},
{
204
,
0x22416000
},
{
218
,
0x22416000
},
{
229
,
0x22416000
},
};
struct
wm_info
i810_wm_24_100
[]
=
{
{
15
,
0x0020c000
},
{
19
,
0x0040c000
},
{
25
,
0x22009000
},
{
28
,
0x22009000
},
{
31
,
0x2200a000
},
{
36
,
0x2210c000
},
{
40
,
0x2210c000
},
{
45
,
0x2210c000
},
{
49
,
0x22111000
},
{
50
,
0x22111000
},
{
56
,
0x22111000
},
{
65
,
0x22214000
},
{
75
,
0x22214000
},
{
78
,
0x22215000
},
{
80
,
0x22216000
},
{
94
,
0x22218000
},
{
96
,
0x22418000
},
{
99
,
0x22418000
},
{
108
,
0x22418000
},
{
121
,
0x22418000
},
{
128
,
0x22419000
},
{
132
,
0x22519000
},
{
135
,
0x4441d000
},
{
157
,
0x44419000
},
{
162
,
0x44419000
},
{
175
,
0x44419000
},
{
189
,
0x44419000
},
{
195
,
0x44419000
},
{
202
,
0x44419000
},
{
204
,
0x44419000
},
};
struct
wm_info
i810_wm_8_133
[]
=
{
{
15
,
0x0070c000
},
{
19
,
0x0070c000
},
{
25
,
0x22003000
},
{
28
,
0x22003000
},
{
31
,
0x22003000
},
{
36
,
0x22007000
},
{
40
,
0x22007000
},
{
45
,
0x22007000
},
{
49
,
0x22008000
},
{
50
,
0x22008000
},
{
56
,
0x22008000
},
{
65
,
0x22008000
},
{
75
,
0x22008000
},
{
78
,
0x22008000
},
{
80
,
0x22008000
},
{
94
,
0x22008000
},
{
96
,
0x22107000
},
{
99
,
0x22107000
},
{
108
,
0x22107000
},
{
121
,
0x22107000
},
{
128
,
0x22107000
},
{
132
,
0x22109000
},
{
135
,
0x22109000
},
{
157
,
0x2210b000
},
{
162
,
0x2210b000
},
{
175
,
0x2210b000
},
{
189
,
0x2220e000
},
{
195
,
0x2220e000
},
{
202
,
0x2220e000
},
{
204
,
0x2220e000
},
{
218
,
0x2220f000
},
{
229
,
0x22210000
},
{
234
,
0x22210000
},
};
struct
wm_info
i810_wm_16_133
[]
=
{
{
15
,
0x0020c000
},
{
19
,
0x0020c000
},
{
25
,
0x22006000
},
{
28
,
0x22006000
},
{
31
,
0x22007000
},
{
36
,
0x22007000
},
{
40
,
0x22007000
},
{
45
,
0x22007000
},
{
49
,
0x22009000
},
{
50
,
0x22009000
},
{
56
,
0x22108000
},
{
65
,
0x2210e000
},
{
75
,
0x2210e000
},
{
78
,
0x2210e000
},
{
80
,
0x22210000
},
{
94
,
0x22210000
},
{
96
,
0x22210000
},
{
99
,
0x22210000
},
{
108
,
0x22210000
},
{
121
,
0x22210000
},
{
128
,
0x22210000
},
{
132
,
0x22314000
},
{
135
,
0x22314000
},
{
157
,
0x22415000
},
{
162
,
0x22416000
},
{
175
,
0x22416000
},
{
189
,
0x22416000
},
{
195
,
0x22416000
},
{
202
,
0x22416000
},
{
204
,
0x22416000
},
{
218
,
0x22416000
},
{
229
,
0x22416000
},
};
struct
wm_info
i810_wm_24_133
[]
=
{
{
15
,
0x0020c000
},
{
19
,
0x00408000
},
{
25
,
0x22009000
},
{
28
,
0x22009000
},
{
31
,
0x2200a000
},
{
36
,
0x2210c000
},
{
40
,
0x2210c000
},
{
45
,
0x2210c000
},
{
49
,
0x22111000
},
{
50
,
0x22111000
},
{
56
,
0x22111000
},
{
65
,
0x22214000
},
{
75
,
0x22214000
},
{
78
,
0x22215000
},
{
80
,
0x22216000
},
{
94
,
0x22218000
},
{
96
,
0x22418000
},
{
99
,
0x22418000
},
{
108
,
0x22418000
},
{
121
,
0x22418000
},
{
128
,
0x22419000
},
{
132
,
0x22519000
},
{
135
,
0x4441d000
},
{
157
,
0x44419000
},
{
162
,
0x44419000
},
{
175
,
0x44419000
},
{
189
,
0x44419000
},
{
195
,
0x44419000
},
{
202
,
0x44419000
},
{
204
,
0x44419000
},
};
void
round_off_xres
(
u32
*
xres
)
{
}
void
round_off_yres
(
u32
*
xres
,
u32
*
yres
)
{
}
/**
* i810fb_encode_registers - encode @var to hardware register values
* @var: pointer to var structure
* @par: pointer to hardware par structure
*
* DESCRIPTION:
* Timing values in @var will be converted to appropriate
* register values of @par.
*/
void
i810fb_encode_registers
(
const
struct
fb_var_screeninfo
*
var
,
struct
i810fb_par
*
par
,
u32
xres
,
u32
yres
)
{
int
n
,
blank_s
,
blank_e
;
u8
*
mmio
=
par
->
mmio_start_virtual
,
msr
=
0
;
/* Horizontal */
/* htotal */
n
=
((
xres
+
var
->
right_margin
+
var
->
hsync_len
+
var
->
left_margin
)
>>
3
)
-
5
;
par
->
regs
.
cr00
=
(
u8
)
n
;
par
->
regs
.
cr35
=
(
u8
)
((
n
>>
8
)
&
1
);
/* xres */
par
->
regs
.
cr01
=
(
u8
)
((
xres
>>
3
)
-
1
);
/* hblank */
blank_e
=
(
xres
+
var
->
right_margin
+
var
->
hsync_len
+
var
->
left_margin
)
>>
3
;
blank_e
--
;
blank_s
=
blank_e
-
127
;
if
(
blank_s
<
(
xres
>>
3
))
blank_s
=
xres
>>
3
;
par
->
regs
.
cr02
=
(
u8
)
blank_s
;
par
->
regs
.
cr03
=
(
u8
)
(
blank_e
&
0x1F
);
par
->
regs
.
cr05
=
(
u8
)
((
blank_e
&
(
1
<<
5
))
<<
2
);
par
->
regs
.
cr39
=
(
u8
)
((
blank_e
>>
6
)
&
1
);
/* hsync */
par
->
regs
.
cr04
=
(
u8
)
((
xres
+
var
->
right_margin
)
>>
3
);
par
->
regs
.
cr05
|=
(
u8
)
(((
xres
+
var
->
right_margin
+
var
->
hsync_len
)
>>
3
)
&
0x1F
);
/* Vertical */
/* vtotal */
n
=
yres
+
var
->
lower_margin
+
var
->
vsync_len
+
var
->
upper_margin
-
2
;
par
->
regs
.
cr06
=
(
u8
)
(
n
&
0xFF
);
par
->
regs
.
cr30
=
(
u8
)
((
n
>>
8
)
&
0x0F
);
/* vsync */
n
=
yres
+
var
->
lower_margin
;
par
->
regs
.
cr10
=
(
u8
)
(
n
&
0xFF
);
par
->
regs
.
cr32
=
(
u8
)
((
n
>>
8
)
&
0x0F
);
par
->
regs
.
cr11
=
i810_readb
(
CR11
,
mmio
)
&
~
0x0F
;
par
->
regs
.
cr11
|=
(
u8
)
((
yres
+
var
->
lower_margin
+
var
->
vsync_len
)
&
0x0F
);
/* yres */
n
=
yres
-
1
;
par
->
regs
.
cr12
=
(
u8
)
(
n
&
0xFF
);
par
->
regs
.
cr31
=
(
u8
)
((
n
>>
8
)
&
0x0F
);
/* vblank */
blank_e
=
yres
+
var
->
lower_margin
+
var
->
vsync_len
+
var
->
upper_margin
;
blank_e
--
;
blank_s
=
blank_e
-
127
;
if
(
blank_s
<
yres
)
blank_s
=
yres
;
par
->
regs
.
cr15
=
(
u8
)
(
blank_s
&
0xFF
);
par
->
regs
.
cr33
=
(
u8
)
((
blank_s
>>
8
)
&
0x0F
);
par
->
regs
.
cr16
=
(
u8
)
(
blank_e
&
0xFF
);
par
->
regs
.
cr09
=
0
;
/* sync polarity */
if
(
!
(
var
->
sync
&
FB_SYNC_HOR_HIGH_ACT
))
msr
|=
1
<<
6
;
if
(
!
(
var
->
sync
&
FB_SYNC_VERT_HIGH_ACT
))
msr
|=
1
<<
7
;
par
->
regs
.
msr
=
msr
;
/* interlace */
if
(
var
->
vmode
&
FB_VMODE_INTERLACED
)
par
->
interlace
=
(
1
<<
7
)
|
((
u8
)
(
var
->
yres
>>
4
));
else
par
->
interlace
=
0
;
if
(
var
->
vmode
&
FB_VMODE_DOUBLE
)
par
->
regs
.
cr09
|=
1
<<
7
;
/* overlay */
par
->
ovract
=
((
var
->
xres
+
var
->
right_margin
+
var
->
hsync_len
+
var
->
left_margin
-
32
)
|
((
var
->
xres
-
32
)
<<
16
));
}
void
i810fb_fill_var_timings
(
struct
fb_var_screeninfo
*
var
)
{
}
/**
* i810_get_watermark - gets watermark
* @var: pointer to fb_var_screeninfo
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* Get's the required watermark based on
* pixelclock and RAMBUS frequency.
*
* RETURNS:
* watermark
*/
u32
i810_get_watermark
(
const
struct
fb_var_screeninfo
*
var
,
struct
i810fb_par
*
par
)
{
struct
wm_info
*
wmark
=
0
;
u32
i
,
size
=
0
,
pixclock
,
wm_best
=
0
,
min
,
diff
;
if
(
par
->
mem_freq
==
100
)
{
switch
(
var
->
bits_per_pixel
)
{
case
8
:
wmark
=
i810_wm_8_100
;
size
=
ARRAY_SIZE
(
i810_wm_8_100
);
break
;
case
16
:
wmark
=
i810_wm_16_100
;
size
=
ARRAY_SIZE
(
i810_wm_16_100
);
break
;
case
24
:
case
32
:
wmark
=
i810_wm_24_100
;
size
=
ARRAY_SIZE
(
i810_wm_24_100
);
}
}
else
{
switch
(
var
->
bits_per_pixel
)
{
case
8
:
wmark
=
i810_wm_8_133
;
size
=
ARRAY_SIZE
(
i810_wm_8_133
);
break
;
case
16
:
wmark
=
i810_wm_16_133
;
size
=
ARRAY_SIZE
(
i810_wm_16_133
);
break
;
case
24
:
case
32
:
wmark
=
i810_wm_24_133
;
size
=
ARRAY_SIZE
(
i810_wm_24_133
);
}
}
pixclock
=
1000000
/
var
->
pixclock
;
min
=
~
0
;
for
(
i
=
0
;
i
<
size
;
i
++
)
{
if
(
pixclock
<=
wmark
[
i
].
freq
)
diff
=
wmark
[
i
].
freq
-
pixclock
;
else
diff
=
pixclock
-
wmark
[
i
].
freq
;
if
(
diff
<
min
)
{
wm_best
=
wmark
[
i
].
wm
;
min
=
diff
;
}
}
return
wm_best
;
}
drivers/video/i810/i810_main.c
0 → 100644
View file @
0e2e212c
/*-*- linux-c -*-
* linux/drivers/video/i810_main.c -- Intel 810 frame buffer device
*
* Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
* All Rights Reserved
*
* Contributors:
* Michael Vogt <mvogt@acm.org> - added support for Intel 815 chipsets
* and enabling the power-on state of
* external VGA connectors for
* secondary displays
*
* Fredrik Andersson <krueger@shell.linux.se> - alpha testing of
* the VESA GTF
*
* Brad Corrion <bcorrion@web-co.com> - alpha testing of customized
* timings support
*
* The code framework is a modification of vfb.c by Geert Uytterhoeven.
* DotClock and PLL calculations are partly based on i810_driver.c
* in xfree86 v4.0.3 by Precision Insight.
* Watermark calculation and tables are based on i810_wmark.c
* in xfre86 v4.0.3 by Precision Insight. Slight modifications
* only to allow for integer operations instead of floating point.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/resource.h>
#include <linux/selection.h>
#include <linux/console.h>
#include <linux/vt_kern.h>
#include <linux/unistd.h>
#include <asm/io.h>
#include <asm/div64.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
#include <asm/page.h>
#include "i810_regs.h"
#include "i810.h"
#include "i810_main.h"
/*------------------------------------------------------------*/
/**************************************************************
* Hardware Low Level Routines *
**************************************************************/
/**
* i810_screen_off - turns off/on display
* @mmio: address of register space
* @mode: on or off
*
* DESCRIPTION:
* Blanks/unblanks the display
*/
static
void
i810_screen_off
(
u8
*
mmio
,
u8
mode
)
{
u32
count
=
WAIT_COUNT
;
u8
val
;
i810_writeb
(
SR_INDEX
,
mmio
,
SR01
);
val
=
i810_readb
(
SR_DATA
,
mmio
);
val
=
(
mode
==
OFF
)
?
val
|
SCR_OFF
:
val
&
~
SCR_OFF
;
while
((
i810_readw
(
DISP_SL
,
mmio
)
&
0xFFF
)
&&
count
--
);
i810_writeb
(
SR_INDEX
,
mmio
,
SR01
);
i810_writeb
(
SR_DATA
,
mmio
,
val
);
}
/**
* i810_dram_off - turns off/on dram refresh
* @mmio: address of register space
* @mode: on or off
*
* DESCRIPTION:
* Turns off DRAM refresh. Must be off for only 2 vsyncs
* before data becomes corrupt
*/
static
void
i810_dram_off
(
u8
*
mmio
,
u8
mode
)
{
u8
val
;
val
=
i810_readb
(
DRAMCH
,
mmio
);
val
&=
DRAM_OFF
;
val
=
(
mode
==
OFF
)
?
val
:
val
|
DRAM_ON
;
i810_writeb
(
DRAMCH
,
mmio
,
val
);
}
/**
* i810_protect_regs - allows rw/ro mode of certain VGA registers
* @mmio: address of register space
* @mode: protect/unprotect
*
* DESCRIPTION:
* The IBM VGA standard allows protection of certain VGA registers.
* This will protect or unprotect them.
*/
static
void
i810_protect_regs
(
u8
*
mmio
,
int
mode
)
{
u8
reg
;
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR11
);
reg
=
i810_readb
(
CR_DATA_CGA
,
mmio
);
reg
=
(
mode
==
OFF
)
?
reg
&
~
0x80
:
reg
|
0x80
;
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR11
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
reg
);
}
/**
* i810_load_pll - loads values for the hardware PLL clock
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* Loads the P, M, and N registers.
*/
static
void
i810_load_pll
(
struct
i810fb_par
*
par
)
{
u32
tmp1
,
tmp2
;
u8
*
mmio
=
par
->
mmio_start_virtual
;
tmp1
=
par
->
regs
.
M
|
par
->
regs
.
N
<<
16
;
tmp2
=
i810_readl
(
DCLK_2D
,
mmio
);
tmp2
&=
~
MN_MASK
;
i810_writel
(
DCLK_2D
,
mmio
,
tmp1
|
tmp2
);
tmp1
=
par
->
regs
.
P
;
tmp2
=
i810_readl
(
DCLK_0DS
,
mmio
);
tmp2
&=
~
(
P_OR
<<
16
);
i810_writel
(
DCLK_0DS
,
mmio
,
(
tmp1
<<
16
)
|
tmp2
);
i810_writeb
(
MSR_WRITE
,
mmio
,
par
->
regs
.
msr
|
0xC8
|
1
);
}
/**
* i810_load_vga - load standard VGA registers
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* Load values to VGA registers
*/
static
void
i810_load_vga
(
struct
i810fb_par
*
par
)
{
u8
*
mmio
=
par
->
mmio_start_virtual
;
/* interlace */
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR70
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
interlace
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR00
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr00
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR01
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr01
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR02
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr02
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR03
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr03
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR04
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr04
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR05
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr05
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR06
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr06
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR09
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr09
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR10
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr10
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR11
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr11
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR12
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr12
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR15
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr15
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR16
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr16
);
}
/**
* i810_load_vgax - load extended VGA registers
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* Load values to extended VGA registers
*/
static
void
i810_load_vgax
(
struct
i810fb_par
*
par
)
{
u8
*
mmio
=
par
->
mmio_start_virtual
;
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR30
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr30
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR31
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr31
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR32
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr32
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR33
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr33
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR35
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr35
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR39
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
regs
.
cr39
);
}
/**
* i810_load_2d - load grahics registers
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* Load values to graphics registers
*/
static
void
i810_load_2d
(
struct
i810fb_par
*
par
)
{
u32
tmp
;
u8
tmp8
,
*
mmio
=
par
->
mmio_start_virtual
;;
i810_writel
(
FW_BLC
,
mmio
,
par
->
watermark
);
tmp
=
i810_readl
(
PIXCONF
,
mmio
);
tmp
|=
1
|
1
<<
20
;
i810_writel
(
PIXCONF
,
mmio
,
tmp
);
i810_writel
(
OVRACT
,
mmio
,
par
->
ovract
);
i810_writeb
(
GR_INDEX
,
mmio
,
GR10
);
tmp8
=
i810_readb
(
GR_DATA
,
mmio
);
tmp8
|=
2
;
i810_writeb
(
GR_INDEX
,
mmio
,
GR10
);
i810_writeb
(
GR_DATA
,
mmio
,
tmp8
);
}
/**
* i810_hires - enables high resolution mode
* @mmio: address of register space
*/
static
void
i810_hires
(
u8
*
mmio
)
{
u8
val
;
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR80
);
val
=
i810_readb
(
CR_DATA_CGA
,
mmio
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR80
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
val
|
1
);
}
/**
* i810_load_pitch - loads the characters per line of the display
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* Loads the characters per line
*/
static
void
i810_load_pitch
(
struct
i810fb_par
*
par
)
{
u32
tmp
,
pitch
;
u8
val
,
*
mmio
=
par
->
mmio_start_virtual
;
pitch
=
par
->
pitch
>>
3
;
i810_writeb
(
SR_INDEX
,
mmio
,
SR01
);
val
=
i810_readb
(
SR_DATA
,
mmio
);
val
&=
0xE0
;
val
|=
1
|
1
<<
2
;
i810_writeb
(
SR_INDEX
,
mmio
,
SR01
);
i810_writeb
(
SR_DATA
,
mmio
,
val
);
tmp
=
pitch
&
0xFF
;
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR13
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
(
u8
)
tmp
);
tmp
=
pitch
>>
8
;
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR41
);
val
=
i810_readb
(
CR_DATA_CGA
,
mmio
)
&
~
0x0F
;
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR41
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
(
u8
)
tmp
|
val
);
}
/**
* i810_load_color - loads the color depth of the display
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* Loads the color depth of the display and the graphics engine
*/
static
void
i810_load_color
(
struct
i810fb_par
*
par
)
{
u8
*
mmio
=
par
->
mmio_start_virtual
;
u32
reg1
;
u16
reg2
;
reg1
=
i810_readl
(
PIXCONF
,
mmio
)
&
~
(
0xF0000
|
1
<<
27
);
reg2
=
i810_readw
(
BLTCNTL
,
mmio
)
&
~
0x30
;
reg1
|=
0x8000
|
par
->
pixconf
;
reg2
|=
par
->
bltcntl
;
i810_writel
(
PIXCONF
,
mmio
,
reg1
);
i810_writew
(
BLTCNTL
,
mmio
,
reg2
);
}
/**
* i810_load_regs - loads all registers for the mode
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* Loads registers
*/
static
void
i810_load_regs
(
struct
i810fb_par
*
par
)
{
u8
*
mmio
=
par
->
mmio_start_virtual
;
i810_screen_off
(
mmio
,
OFF
);
i810_protect_regs
(
mmio
,
OFF
);
i810_dram_off
(
mmio
,
OFF
);
i810_load_pll
(
par
);
i810_load_vga
(
par
);
i810_load_vgax
(
par
);
i810_dram_off
(
mmio
,
ON
);
i810_load_2d
(
par
);
i810_hires
(
mmio
);
i810_screen_off
(
mmio
,
ON
);
i810_protect_regs
(
mmio
,
ON
);
i810_load_color
(
par
);
i810_load_pitch
(
par
);
}
static
void
i810_write_dac
(
u8
regno
,
u8
red
,
u8
green
,
u8
blue
,
u8
*
mmio
)
{
i810_writeb
(
CLUT_INDEX_WRITE
,
mmio
,
regno
);
i810_writeb
(
CLUT_DATA
,
mmio
,
red
);
i810_writeb
(
CLUT_DATA
,
mmio
,
green
);
i810_writeb
(
CLUT_DATA
,
mmio
,
blue
);
}
static
void
i810_read_dac
(
u8
regno
,
u8
*
red
,
u8
*
green
,
u8
*
blue
,
u8
*
mmio
)
{
i810_writeb
(
CLUT_INDEX_READ
,
mmio
,
regno
);
*
red
=
i810_readb
(
CLUT_DATA
,
mmio
);
*
green
=
i810_readb
(
CLUT_DATA
,
mmio
);
*
blue
=
i810_readb
(
CLUT_DATA
,
mmio
);
}
/************************************************************
* VGA State Restore *
************************************************************/
static
void
i810_restore_pll
(
struct
i810fb_par
*
par
)
{
u32
tmp1
,
tmp2
;
u8
*
mmio
=
par
->
mmio_start_virtual
;
tmp1
=
par
->
hw_state
.
dclk_2d
;
tmp2
=
i810_readl
(
DCLK_2D
,
mmio
);
tmp1
&=
~
MN_MASK
;
tmp2
&=
MN_MASK
;
i810_writel
(
DCLK_2D
,
mmio
,
tmp1
|
tmp2
);
tmp1
=
par
->
hw_state
.
dclk_1d
;
tmp2
=
i810_readl
(
DCLK_1D
,
mmio
);
tmp1
&=
~
MN_MASK
;
tmp2
&=
MN_MASK
;
i810_writel
(
DCLK_1D
,
mmio
,
tmp1
|
tmp2
);
i810_writel
(
DCLK_0DS
,
mmio
,
par
->
hw_state
.
dclk_0ds
);
}
static
void
i810_restore_dac
(
struct
i810fb_par
*
par
)
{
u32
tmp1
,
tmp2
;
u8
*
mmio
=
par
->
mmio_start_virtual
;
tmp1
=
par
->
hw_state
.
pixconf
;
tmp2
=
i810_readl
(
PIXCONF
,
mmio
);
tmp1
&=
DAC_BIT
;
tmp2
&=
~
DAC_BIT
;
i810_writel
(
PIXCONF
,
mmio
,
tmp1
|
tmp2
);
}
static
void
i810_restore_vgax
(
struct
i810fb_par
*
par
)
{
u8
i
,
j
,
*
mmio
=
par
->
mmio_start_virtual
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR30
+
i
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
*
(
&
(
par
->
hw_state
.
cr30
)
+
i
));
}
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR35
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
hw_state
.
cr35
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR39
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
hw_state
.
cr39
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR41
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
hw_state
.
cr39
);
/*restore interlace*/
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR70
);
i
=
par
->
hw_state
.
cr70
;
i
&=
INTERLACE_BIT
;
j
=
i810_readb
(
CR_DATA_CGA
,
mmio
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR70
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
j
|
i
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR80
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
par
->
hw_state
.
cr80
);
i810_writeb
(
MSR_WRITE
,
mmio
,
par
->
hw_state
.
msr
);
i810_writeb
(
SR_INDEX
,
mmio
,
SR01
);
i
=
(
par
->
hw_state
.
sr01
)
&
~
0xE0
;
j
=
i810_readb
(
SR_DATA
,
mmio
)
&
0xE0
;
i810_writeb
(
SR_INDEX
,
mmio
,
SR01
);
i810_writeb
(
SR_DATA
,
mmio
,
i
|
j
);
}
static
void
i810_restore_vga
(
struct
i810fb_par
*
par
)
{
u8
i
,
*
mmio
=
par
->
mmio_start_virtual
;
for
(
i
=
0
;
i
<
10
;
i
++
)
{
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR00
+
i
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
*
((
&
par
->
hw_state
.
cr00
)
+
i
));
}
for
(
i
=
0
;
i
<
8
;
i
++
)
{
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR10
+
i
);
i810_writeb
(
CR_DATA_CGA
,
mmio
,
*
((
&
par
->
hw_state
.
cr10
)
+
i
));
}
}
static
void
i810_restore_addr_map
(
struct
i810fb_par
*
par
)
{
u8
tmp
,
*
mmio
=
par
->
mmio_start_virtual
;
i810_writeb
(
GR_INDEX
,
mmio
,
GR10
);
tmp
=
i810_readb
(
GR_DATA
,
mmio
);
tmp
&=
ADDR_MAP_MASK
;
tmp
|=
par
->
hw_state
.
gr10
;
i810_writeb
(
GR_INDEX
,
mmio
,
GR10
);
i810_writeb
(
GR_DATA
,
mmio
,
tmp
);
}
static
void
i810_restore_2d
(
struct
i810fb_par
*
par
)
{
u32
tmp_long
;
u16
tmp_word
;
u8
*
mmio
=
par
->
mmio_start_virtual
;
tmp_word
=
i810_readw
(
BLTCNTL
,
mmio
);
tmp_word
&=
~
(
3
<<
4
);
tmp_word
|=
par
->
hw_state
.
bltcntl
;
i810_writew
(
BLTCNTL
,
mmio
,
tmp_word
);
i810_dram_off
(
mmio
,
OFF
);
i810_writel
(
PIXCONF
,
mmio
,
par
->
hw_state
.
pixconf
);
i810_dram_off
(
mmio
,
ON
);
tmp_word
=
i810_readw
(
HWSTAM
,
mmio
);
tmp_word
&=
3
<<
13
;
tmp_word
|=
par
->
hw_state
.
hwstam
;
i810_writew
(
HWSTAM
,
mmio
,
tmp_word
);
tmp_long
=
i810_readl
(
FW_BLC
,
mmio
);
tmp_long
&=
FW_BLC_MASK
;
tmp_long
|=
par
->
hw_state
.
fw_blc
;
i810_writel
(
FW_BLC
,
mmio
,
tmp_long
);
i810_writel
(
HWS_PGA
,
mmio
,
par
->
hw_state
.
hws_pga
);
i810_writew
(
IER
,
mmio
,
par
->
hw_state
.
ier
);
i810_writew
(
IMR
,
mmio
,
par
->
hw_state
.
imr
);
i810_writel
(
DPLYSTAS
,
mmio
,
par
->
hw_state
.
dplystas
);
}
static
void
i810_restore_vga_state
(
struct
i810fb_par
*
par
)
{
u8
*
mmio
=
par
->
mmio_start_virtual
;
i810_screen_off
(
mmio
,
OFF
);
i810_protect_regs
(
mmio
,
OFF
);
i810_dram_off
(
mmio
,
OFF
);
i810_restore_pll
(
par
);
i810_restore_dac
(
par
);
i810_restore_vga
(
par
);
i810_restore_vgax
(
par
);
i810_restore_addr_map
(
par
);
i810_dram_off
(
mmio
,
ON
);
i810_restore_2d
(
par
);
i810_screen_off
(
mmio
,
ON
);
i810_protect_regs
(
mmio
,
ON
);
}
/***********************************************************************
* VGA State Save *
***********************************************************************/
static
void
i810_save_vgax
(
struct
i810fb_par
*
par
)
{
u8
i
,
*
mmio
=
par
->
mmio_start_virtual
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR30
+
i
);
*
(
&
(
par
->
hw_state
.
cr30
)
+
i
)
=
i810_readb
(
CR_DATA_CGA
,
mmio
);
}
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR35
);
par
->
hw_state
.
cr35
=
i810_readb
(
CR_DATA_CGA
,
mmio
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR39
);
par
->
hw_state
.
cr39
=
i810_readb
(
CR_DATA_CGA
,
mmio
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR41
);
par
->
hw_state
.
cr41
=
i810_readb
(
CR_DATA_CGA
,
mmio
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR70
);
par
->
hw_state
.
cr70
=
i810_readb
(
CR_DATA_CGA
,
mmio
);
par
->
hw_state
.
msr
=
i810_readb
(
MSR_READ
,
mmio
);
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR80
);
par
->
hw_state
.
cr80
=
i810_readb
(
CR_DATA_CGA
,
mmio
);
i810_writeb
(
SR_INDEX
,
mmio
,
SR01
);
par
->
hw_state
.
sr01
=
i810_readb
(
SR_DATA
,
mmio
);
}
static
void
i810_save_vga
(
struct
i810fb_par
*
par
)
{
u8
i
,
*
mmio
=
par
->
mmio_start_virtual
;
for
(
i
=
0
;
i
<
10
;
i
++
)
{
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR00
+
i
);
*
((
&
par
->
hw_state
.
cr00
)
+
i
)
=
i810_readb
(
CR_DATA_CGA
,
mmio
);
}
for
(
i
=
0
;
i
<
8
;
i
++
)
{
i810_writeb
(
CR_INDEX_CGA
,
mmio
,
CR10
+
i
);
*
((
&
par
->
hw_state
.
cr10
)
+
i
)
=
i810_readb
(
CR_DATA_CGA
,
mmio
);
}
}
static
void
i810_save_2d
(
struct
i810fb_par
*
par
)
{
u8
*
mmio
=
par
->
mmio_start_virtual
;
par
->
hw_state
.
dclk_2d
=
i810_readl
(
DCLK_2D
,
mmio
);
par
->
hw_state
.
dclk_1d
=
i810_readl
(
DCLK_1D
,
mmio
);
par
->
hw_state
.
dclk_0ds
=
i810_readl
(
DCLK_0DS
,
mmio
);
par
->
hw_state
.
pixconf
=
i810_readl
(
PIXCONF
,
mmio
);
par
->
hw_state
.
fw_blc
=
i810_readl
(
FW_BLC
,
mmio
);
par
->
hw_state
.
bltcntl
=
i810_readw
(
BLTCNTL
,
mmio
);
par
->
hw_state
.
hwstam
=
i810_readw
(
HWSTAM
,
mmio
);
par
->
hw_state
.
hws_pga
=
i810_readl
(
HWS_PGA
,
mmio
);
par
->
hw_state
.
ier
=
i810_readw
(
IER
,
mmio
);
par
->
hw_state
.
imr
=
i810_readw
(
IMR
,
mmio
);
par
->
hw_state
.
dplystas
=
i810_readl
(
DPLYSTAS
,
mmio
);
}
static
void
i810_save_vga_state
(
struct
i810fb_par
*
par
)
{
i810_save_vga
(
par
);
i810_save_vgax
(
par
);
i810_save_2d
(
par
);
}
/************************************************************
* Helpers *
************************************************************/
/**
* get_line_length - calculates buffer pitch in bytes
* @par: pointer to i810fb_par structure
* @xres_virtual: virtual resolution of the frame
* @bpp: bits per pixel
*
* DESCRIPTION:
* Calculates buffer pitch in bytes.
*/
u32
get_line_length
(
struct
i810fb_par
*
par
,
int
xres_virtual
,
int
bpp
)
{
u32
length
;
length
=
xres_virtual
*
bpp
;
length
=
(
length
+
31
)
&-
32
;
length
>>=
3
;
return
length
;
}
/**
* i810_calc_dclk - calculates the P, M, and N values of a pixelclock value
* @freq: target pixelclock in picoseconds
* @m: where to write M register
* @n: where to write N register
* @p: where to write P register
*
* DESCRIPTION:
* Based on the formula Freq_actual = (4*M*Freq_ref)/(N^P)
* Repeatedly computes the Freq until the actual Freq is equal to
* the target Freq or until the loop count is zero. In the latter
* case, the actual frequency nearest the target will be used.
*/
static
void
i810_calc_dclk
(
u32
freq
,
u32
*
m
,
u32
*
n
,
u32
*
p
)
{
u32
m_reg
,
n_reg
,
p_divisor
,
n_target_max
;
u32
m_target
,
n_target
,
p_target
,
n_best
,
m_best
,
mod
;
u32
f_out
,
target_freq
,
diff
=
0
,
mod_min
,
diff_min
;
diff_min
=
mod_min
=
0xFFFFFFFF
;
n_best
=
m_best
=
m_target
=
f_out
=
0
;
target_freq
=
freq
;
n_target_max
=
30
;
/*
* find P such that target freq is 16x reference freq (Hz).
*/
p_divisor
=
1
;
p_target
=
0
;
while
(
!
((
1000000
*
p_divisor
)
/
(
16
*
24
*
target_freq
))
&&
p_divisor
<=
32
)
{
p_divisor
<<=
1
;
p_target
++
;
}
n_reg
=
m_reg
=
n_target
=
3
;
while
((
diff_min
||
mod_min
)
&&
(
n_target
<
n_target_max
))
{
f_out
=
(
p_divisor
*
n_reg
*
1000000
)
/
(
4
*
24
*
m_reg
);
mod
=
(
p_divisor
*
n_reg
*
1000000
)
%
(
4
*
24
*
m_reg
);
m_target
=
m_reg
;
n_target
=
n_reg
;
if
(
f_out
<=
target_freq
)
{
n_reg
++
;
diff
=
target_freq
-
f_out
;
}
else
{
m_reg
++
;
diff
=
f_out
-
target_freq
;
}
if
(
diff_min
>
diff
)
{
diff_min
=
diff
;
n_best
=
n_target
;
m_best
=
m_target
;
}
if
(
!
diff
&&
mod_min
>
mod
)
{
mod_min
=
mod
;
n_best
=
n_target
;
m_best
=
m_target
;
}
}
if
(
m
)
*
m
=
(
m_best
-
2
)
&
0x3FF
;
if
(
n
)
*
n
=
(
n_best
-
2
)
&
0x3FF
;
if
(
p
)
*
p
=
(
p_target
<<
4
);
}
/**
* i810_get_vblank - get vertical blank time
* @hfreq: horizontal freq
*
* DESCRIPTION:
* vblank = right_margin + vsync_len + left_margin
* given: right_margin = 1 (V_FRONTPORCH)
* vsync_len = 3
* flyback = 550
*
* flyback * hfreq
* left_margin = --------------- - vsync_len
* 1000000
* and flyback is set to 550
*/
static
u32
i810_get_vblank
(
u32
hfreq
)
{
u32
vblank
;
vblank
=
(
hfreq
*
FLYBACK
)
/
1000
;
vblank
=
(
vblank
+
500
)
/
1000
;
return
(
vblank
+
V_FRONTPORCH
);
}
/**
* i810_get_hblank - get horizontal blank time
* @hfreq: horizontal freq
* @xres: horizontal resolution in pixels
*
* DESCRIPTION:
* duty cycle is the percent of htotal assigned to inactive display
* duty cycle = C - (M/Hfreq)
* where: C = ((offset - scale factor) * blank_scale)
* -------------------------------------- + scale factor
* 256
* M = blank_scale * gradient
*
* xres * duty_cycle
* hblank = ------------------
* 100 - duty_cycle
*/
static
u32
i810_get_hblank
(
u32
hfreq
,
u32
xres
)
{
u32
c_val
,
m_val
,
duty_cycle
,
hblank
;
c_val
=
(((
H_OFFSET
-
H_SCALEFACTOR
)
*
H_BLANKSCALE
)
/
256
+
H_SCALEFACTOR
)
*
1000
;
m_val
=
(
H_BLANKSCALE
*
H_GRADIENT
)
/
256
;
m_val
=
(
m_val
*
1000000
)
/
hfreq
;
duty_cycle
=
c_val
-
m_val
;
hblank
=
(
xres
*
duty_cycle
)
/
(
100000
-
duty_cycle
);
hblank
=
(
hblank
+
4
)
&
~
7
;
return
(
hblank
);
}
/**
* i810_estimate_hfreq - estimate hsync
* @vfreq: vertical refresh rate
* @yres: vertical resolution
*
* DESCRIPTION:
* Based on:
*
* (yres + front_port) * vfreq * 1000000
* hfreq = -------------------------------------
* (1000000 - (vfreq * FLYBACK)
*
*/
static
u32
i810_estimate_hfreq
(
u32
vfreq
,
u32
yres
)
{
u64
hfreq
;
u32
divisor
;
divisor
=
1000000
-
(
vfreq
*
FLYBACK
);
hfreq
=
(
u64
)
(
yres
+
V_FRONTPORCH
)
*
(
u64
)
(
vfreq
)
*
1000000
;
do_div
(
hfreq
,
divisor
);
return
((
u32
)
hfreq
);
}
/**
* i810_calculate_timings - calculate video timings
* @info: pointer to fb_info structure
* @var: pointer to current var
*
* DESCRIPTION:
* htotal: calculated using GTF
* vtotal: calculated using GTF
* hsync pulse: 8% of htotal
* vsync pulse: 3
* left margin : (htotal - xres)/2 - hsync
* right margin: sync + left margin
* upper margin: 1
* lower margin: vtotal - (yres + vsync + upper margin)
*
* Calculates necessary timing information based on
* monitor specifications. This will use the
* VESA generalized timing formula. New values are
* written to @var.
*/
static
int
i810_calculate_timings
(
struct
fb_info
*
info
,
struct
fb_var_screeninfo
*
var
,
u32
xres
,
u32
yres
)
{
u64
num
=
1000000000000
;
u32
htotal
=
0
,
vtotal
,
hfreq
,
vfreq
,
hblank
,
vblank
;
u32
dclk
,
interlace
=
0
,
dscan
=
0
;
u32
max_pixclock
=
0
;
switch
(
var
->
bits_per_pixel
)
{
case
8
:
max_pixclock
=
234000000
;
break
;
case
16
:
max_pixclock
=
229000000
;
break
;
case
24
:
case
32
:
max_pixclock
=
204000000
;
break
;
default:
max_pixclock
=
0
;
}
if
(
var
->
vmode
&
FB_VMODE_INTERLACED
)
{
yres
>>=
1
;
interlace
=
1
;
}
if
(
var
->
vmode
&
FB_VMODE_DOUBLE
)
{
yres
<<=
1
;
dscan
=
1
;
}
hfreq
=
info
->
monspecs
.
hfmax
;
vblank
=
i810_get_vblank
(
hfreq
);
vtotal
=
yres
+
vblank
;
vfreq
=
hfreq
/
vtotal
;
if
(
vfreq
>
info
->
monspecs
.
vfmax
)
{
vfreq
=
info
->
monspecs
.
vfmax
;
hfreq
=
i810_estimate_hfreq
(
vfreq
,
yres
);
vblank
=
i810_get_vblank
(
hfreq
);
vtotal
=
yres
+
vblank
;
}
hblank
=
i810_get_hblank
(
hfreq
,
xres
);
htotal
=
xres
+
hblank
;
dclk
=
htotal
*
hfreq
;
while
(
dclk
>
max_pixclock
&&
hfreq
>
info
->
monspecs
.
hfmin
&&
vfreq
>
info
->
monspecs
.
vfmin
)
{
hfreq
-=
1000
;
vblank
=
i810_get_vblank
(
hfreq
);
vtotal
=
yres
+
vblank
;
vfreq
=
hfreq
/
vtotal
;
hblank
=
i810_get_hblank
(
hfreq
,
xres
);
htotal
=
xres
+
hblank
;
dclk
=
hfreq
*
htotal
;
}
if
(
vfreq
<
info
->
monspecs
.
vfmin
)
{
printk
(
"i810fb: required vertical refresh, %dHz, "
"for %dx%d is out of range
\n
"
,
vfreq
,
xres
,
yres
);
return
-
1
;
}
if
(
hfreq
<
info
->
monspecs
.
hfmin
)
{
printk
(
"i810fb: required horizontal sync frequency, %dKHz, "
"for %dx%d is out of range
\n
"
,
hfreq
/
1000
,
xres
,
yres
);
return
-
1
;
}
if
(
dclk
<
MIN_PIXELCLOCK
)
{
printk
(
"i810fb: required pixelclock, %dMHz, for %dx%d"
" is out of range
\n
"
,
dclk
/
1000000
,
xres
,
yres
);
return
-
1
;
}
do_div
(
num
,
dclk
);
var
->
pixclock
=
(
u32
)
num
;
var
->
hsync_len
=
((
htotal
*
8
)
/
100
+
4
)
&
~
7
;
var
->
right_margin
=
((
hblank
>>
1
)
-
var
->
hsync_len
+
4
)
&
~
7
;
var
->
left_margin
=
(
hblank
-
var
->
right_margin
-
var
->
hsync_len
+
4
)
&
~
7
;
var
->
vsync_len
=
(
3
<<
interlace
)
>>
dscan
;
var
->
lower_margin
=
(
1
<<
interlace
)
>>
dscan
;
var
->
upper_margin
=
((
vblank
<<
interlace
)
>>
dscan
)
-
(
var
->
vsync_len
+
var
->
lower_margin
);
if
(
yres
>
480
||
(
yres
==
200
&&
vfreq
==
60
&&
hfreq
/
100
==
157
))
var
->
sync
|=
FB_SYNC_VERT_HIGH_ACT
|
FB_SYNC_HOR_HIGH_ACT
;
else
{
if
(
yres
==
400
&&
vfreq
==
70
&&
hfreq
/
100
==
315
)
var
->
sync
|=
FB_SYNC_VERT_HIGH_ACT
;
if
(
yres
==
350
&&
vfreq
==
60
&&
hfreq
/
100
==
218
)
var
->
sync
|=
FB_SYNC_HOR_HIGH_ACT
;
}
return
0
;
}
/**
* i810_check_custom_timings - validates user entered timings
* @info: pointer to fb_info
* @var: pointer to current fb_var_screeninfo
*
* DESCRIPTION:
* Validates user entered timings in @var.
*/
static
int
i810_check_custom_timings
(
struct
fb_info
*
info
,
struct
fb_var_screeninfo
*
var
,
u32
xres
,
u32
yres
)
{
u64
num
=
1000000000000
;
u32
hfreq
,
vfreq
,
htotal
,
vtotal
,
pixclock
;
u32
max_pixclock
=
0
;
if
(
!
var
->
pixclock
)
return
-
EINVAL
;
do_div
(
num
,
var
->
pixclock
);
pixclock
=
(
u32
)
num
;
htotal
=
xres
+
var
->
right_margin
+
var
->
hsync_len
+
var
->
left_margin
;
vtotal
=
yres
+
var
->
lower_margin
+
var
->
vsync_len
+
var
->
upper_margin
;
if
(
var
->
vmode
&
FB_VMODE_INTERLACED
)
vtotal
>>=
1
;
if
(
var
->
vmode
&
FB_VMODE_DOUBLE
)
vtotal
<<=
1
;
hfreq
=
pixclock
/
htotal
;
vfreq
=
hfreq
/
vtotal
;
switch
(
var
->
bits_per_pixel
)
{
case
8
:
max_pixclock
=
234000000
;
break
;
case
16
:
max_pixclock
=
229000000
;
break
;
case
24
:
case
32
:
max_pixclock
=
204000000
;
break
;
default:
max_pixclock
=
0
;
}
if
(
pixclock
<
MIN_PIXELCLOCK
||
pixclock
>
max_pixclock
||
hfreq
<
info
->
monspecs
.
hfmin
||
hfreq
>
info
->
monspecs
.
hfmax
||
vfreq
<
info
->
monspecs
.
vfmin
||
vfreq
>
info
->
monspecs
.
vfmax
)
return
-
EINVAL
;
return
0
;
}
/*************************************************************
* Hardware Cursor Routines *
*************************************************************/
/**
* i810_enable_cursor - show or hide the hardware cursor
* @mmio: address of register space
* @mode: show (1) or hide (0)
*
* Description:
* Shows or hides the hardware cursor
*/
void
i810_enable_cursor
(
u8
*
mmio
,
int
mode
)
{
u32
temp
;
temp
=
i810_readl
(
PIXCONF
,
mmio
);
temp
=
(
mode
==
ON
)
?
temp
|
CURSOR_ENABLE_MASK
:
temp
&
~
CURSOR_ENABLE_MASK
;
i810_writel
(
PIXCONF
,
mmio
,
temp
);
}
static
void
i810_reset_cursor_image
(
struct
i810fb_par
*
par
)
{
u8
*
addr
=
par
->
cursor_heap
.
virtual
;
int
i
,
j
;
for
(
i
=
64
;
i
--
;
)
{
for
(
j
=
0
;
j
<
8
;
j
++
)
{
i810_writeb
(
j
,
addr
,
0xff
);
i810_writeb
(
j
+
8
,
addr
,
0x00
);
}
addr
+=
16
;
}
}
static
void
i810_load_cursor_image
(
int
width
,
int
height
,
u8
*
data
,
struct
i810fb_par
*
par
)
{
u8
*
addr
=
par
->
cursor_heap
.
virtual
;
int
i
,
j
,
w
=
(
width
+
7
)
/
8
;
for
(
i
=
height
;
i
--
;
)
{
for
(
j
=
0
;
j
<
w
;
j
++
)
{
i810_writeb
(
j
+
0
,
addr
,
0x00
);
i810_writeb
(
j
+
8
,
addr
,
*
data
++
);
}
addr
+=
16
;
}
}
static
void
i810_load_cursor_colors
(
int
fg
,
int
bg
,
struct
fb_info
*
info
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
info
->
par
;
u8
*
mmio
=
par
->
mmio_start_virtual
,
temp
;
u8
red
,
green
,
blue
,
trans
;
i810fb_getcolreg
(
bg
,
&
red
,
&
green
,
&
blue
,
&
trans
,
info
);
temp
=
i810_readb
(
PIXCONF1
,
mmio
);
i810_writeb
(
PIXCONF1
,
mmio
,
temp
|
EXTENDED_PALETTE
);
i810_write_dac
(
4
,
red
,
green
,
blue
,
mmio
);
i810_writeb
(
PIXCONF1
,
mmio
,
temp
);
i810fb_getcolreg
(
fg
,
&
red
,
&
green
,
&
blue
,
&
trans
,
info
);
temp
=
i810_readb
(
PIXCONF1
,
mmio
);
i810_writeb
(
PIXCONF1
,
mmio
,
temp
|
EXTENDED_PALETTE
);
i810_write_dac
(
5
,
red
,
green
,
blue
,
mmio
);
i810_writeb
(
PIXCONF1
,
mmio
,
temp
);
}
/**
* i810_init_cursor - initializes the cursor
* @par: pointer to i810fb_par structure
*
* DESCRIPTION:
* Initializes the cursor registers
*/
static
void
i810_init_cursor
(
struct
i810fb_par
*
par
)
{
u8
*
mmio
=
par
->
mmio_start_virtual
;
i810_enable_cursor
(
mmio
,
OFF
);
i810_writel
(
CURBASE
,
mmio
,
par
->
cursor_heap
.
physical
);
i810_writew
(
CURCNTR
,
mmio
,
COORD_ACTIVE
|
CURSOR_MODE_64_XOR
);
}
/*********************************************************************
* Framebuffer hook helpers *
*********************************************************************/
/**
* i810_round_off - Round off values to capability of hardware
* @var: pointer to fb_var_screeninfo structure
*
* DESCRIPTION:
* @var contains user-defined information for the mode to be set.
* This will try modify those values to ones nearest the
* capability of the hardware
*/
static
void
i810_round_off
(
struct
fb_var_screeninfo
*
var
)
{
u32
xres
,
yres
,
vxres
,
vyres
;
/*
* Presently supports only these configurations
*/
xres
=
var
->
xres
;
yres
=
var
->
yres
;
vxres
=
var
->
xres_virtual
;
vyres
=
var
->
yres_virtual
;
var
->
bits_per_pixel
+=
7
;
var
->
bits_per_pixel
&=
~
7
;
if
(
var
->
bits_per_pixel
<
8
)
var
->
bits_per_pixel
=
8
;
if
(
var
->
bits_per_pixel
>
32
)
var
->
bits_per_pixel
=
32
;
round_off_xres
(
&
xres
);
if
(
xres
<
40
)
xres
=
40
;
if
(
xres
>
2048
)
xres
=
2048
;
xres
=
(
xres
+
7
)
&
~
7
;
if
(
vxres
<
xres
)
vxres
=
xres
;
round_off_yres
(
&
xres
,
&
yres
);
if
(
yres
<
1
)
yres
=
1
;
if
(
yres
>=
2048
)
yres
=
2048
;
if
(
vyres
<
yres
)
vyres
=
yres
;
if
(
var
->
bits_per_pixel
==
32
)
var
->
accel_flags
=
0
;
/* round of horizontal timings to nearest 8 pixels */
var
->
left_margin
=
(
var
->
left_margin
+
4
)
&
~
7
;
var
->
right_margin
=
(
var
->
right_margin
+
4
)
&
~
7
;
var
->
hsync_len
=
(
var
->
hsync_len
+
4
)
&
~
7
;
if
(
var
->
vmode
&
FB_VMODE_INTERLACED
)
{
if
(
!
((
yres
+
var
->
upper_margin
+
var
->
vsync_len
+
var
->
lower_margin
)
&
1
))
var
->
upper_margin
++
;
}
var
->
xres
=
xres
;
var
->
yres
=
yres
;
var
->
xres_virtual
=
vxres
;
var
->
yres_virtual
=
vyres
;
}
/**
* set_color_bitfields - sets rgba fields
* @var: pointer to fb_var_screeninfo
*
* DESCRIPTION:
* The length, offset and ordering for each color field
* (red, green, blue) will be set as specified
* by the hardware
*/
static
void
set_color_bitfields
(
struct
fb_var_screeninfo
*
var
)
{
switch
(
var
->
bits_per_pixel
)
{
case
8
:
var
->
red
.
offset
=
0
;
var
->
red
.
length
=
8
;
var
->
green
.
offset
=
0
;
var
->
green
.
length
=
8
;
var
->
blue
.
offset
=
0
;
var
->
blue
.
length
=
8
;
var
->
transp
.
offset
=
0
;
var
->
transp
.
length
=
0
;
break
;
case
16
:
if
(
var
->
green
.
length
==
5
)
{
/* RGB 555 */
var
->
red
.
offset
=
10
;
var
->
red
.
length
=
5
;
var
->
green
.
offset
=
5
;
var
->
green
.
length
=
5
;
var
->
blue
.
offset
=
0
;
var
->
blue
.
length
=
5
;
var
->
transp
.
offset
=
15
;
var
->
transp
.
length
=
1
;
}
else
{
/* RGB 565 */
var
->
red
.
offset
=
11
;
var
->
red
.
length
=
5
;
var
->
green
.
offset
=
5
;
var
->
green
.
length
=
6
;
var
->
blue
.
offset
=
0
;
var
->
blue
.
length
=
5
;
var
->
transp
.
offset
=
0
;
var
->
transp
.
length
=
0
;
}
break
;
case
24
:
/* RGB 888 */
case
32
:
/* RGBA 8888 */
var
->
red
.
offset
=
16
;
var
->
red
.
length
=
8
;
var
->
green
.
offset
=
8
;
var
->
green
.
length
=
8
;
var
->
blue
.
offset
=
0
;
var
->
blue
.
length
=
8
;
if
(
var
->
bits_per_pixel
==
24
)
{
var
->
transp
.
offset
=
0
;
var
->
transp
.
length
=
0
;
}
else
{
var
->
transp
.
offset
=
24
;
var
->
transp
.
length
=
8
;
break
;
}
}
var
->
red
.
msb_right
=
0
;
var
->
green
.
msb_right
=
0
;
var
->
blue
.
msb_right
=
0
;
var
->
transp
.
msb_right
=
0
;
}
/**
* i810_check_params - check if contents in var are valid
* @var: pointer to fb_var_screeninfo
* @info: pointer to fb_info
*
* DESCRIPTION:
* This will check if the framebuffer size is sufficient
* for the current mode and if the user's monitor has the
* required specifications to display the current mode.
*/
static
int
i810_check_params
(
struct
fb_var_screeninfo
*
var
,
struct
fb_info
*
info
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
info
->
par
;
int
line_length
,
vidmem
;
u32
xres
,
yres
,
vxres
,
vyres
;
xres
=
var
->
xres
;
yres
=
var
->
yres
;
vxres
=
var
->
xres_virtual
;
vyres
=
var
->
yres_virtual
;
/*
* Memory limit
*/
line_length
=
get_line_length
(
par
,
vxres
,
var
->
bits_per_pixel
);
vidmem
=
line_length
*
vyres
;
if
(
vidmem
>
par
->
fb
.
size
)
{
vyres
=
par
->
fb
.
size
/
line_length
;
if
(
vyres
<
yres
)
{
vyres
=
yres
;
vxres
=
par
->
fb
.
size
/
vyres
;
vxres
/=
var
->
bits_per_pixel
>>
3
;
line_length
=
get_line_length
(
par
,
vxres
,
var
->
bits_per_pixel
);
vidmem
=
line_length
*
yres
;
if
(
vxres
<
xres
)
{
printk
(
"i810fb: required video memory, "
"%d bytes, for %dx%d-%d (virtual) "
"is out of range
\n
"
,
vidmem
,
vxres
,
vyres
,
var
->
bits_per_pixel
);
return
-
ENOMEM
;
}
}
}
/*
* Monitor limit
*/
if
(
i810_check_custom_timings
(
info
,
var
,
xres
,
yres
))
{
if
(
i810_calculate_timings
(
info
,
var
,
xres
,
yres
))
{
return
-
EINVAL
;
}
}
var
->
xres
=
xres
;
var
->
yres
=
yres
;
var
->
xres_virtual
=
vxres
;
var
->
yres_virtual
=
vyres
;
return
0
;
}
/**
* encode_fix - fill up fb_fix_screeninfo structure
* @fix: pointer to fb_fix_screeninfo
* @info: pointer to fb_info
*
* DESCRIPTION:
* This will set up parameters that are unmodifiable by the user.
*/
static
int
encode_fix
(
struct
fb_fix_screeninfo
*
fix
,
struct
fb_info
*
info
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
info
->
par
;
memset
(
fix
,
0
,
sizeof
(
struct
fb_fix_screeninfo
));
strcpy
(
fix
->
id
,
i810fb_name
);
fix
->
smem_start
=
par
->
fb
.
physical
;
fix
->
smem_len
=
par
->
fb
.
size
;
fix
->
type
=
FB_TYPE_PACKED_PIXELS
;
fix
->
type_aux
=
0
;
fix
->
xpanstep
=
8
;
fix
->
ypanstep
=
1
;
switch
(
info
->
var
.
bits_per_pixel
)
{
case
8
:
fix
->
visual
=
FB_VISUAL_PSEUDOCOLOR
;
break
;
case
16
:
case
24
:
case
32
:
if
(
info
->
var
.
nonstd
)
fix
->
visual
=
FB_VISUAL_DIRECTCOLOR
;
else
fix
->
visual
=
FB_VISUAL_TRUECOLOR
;
break
;
default:
return
-
EINVAL
;
}
fix
->
ywrapstep
=
0
;
fix
->
line_length
=
get_line_length
(
par
,
info
->
var
.
xres_virtual
,
info
->
var
.
bits_per_pixel
);
fix
->
mmio_start
=
par
->
mmio_start_phys
;
fix
->
mmio_len
=
MMIO_SIZE
;
fix
->
accel
=
FB_ACCEL_I810
;
return
0
;
}
/**
* decode_var - modify par according to contents of var
* @var: pointer to fb_var_screeninfo
* @par: pointer to i810fb_par
* @info: pointer to fb_info
*
* DESCRIPTION:
* Based on the contents of @var, @par will be dynamically filled up.
* @par contains all information necessary to modify the hardware.
*/
static
void
decode_var
(
const
struct
fb_var_screeninfo
*
var
,
struct
i810fb_par
*
par
,
struct
fb_info
*
info
)
{
u32
xres
,
yres
,
vxres
,
vyres
;
xres
=
var
->
xres
;
yres
=
var
->
yres
;
vxres
=
var
->
xres_virtual
;
vyres
=
var
->
yres_virtual
;
switch
(
var
->
bits_per_pixel
)
{
case
8
:
par
->
pixconf
=
PIXCONF8
;
par
->
bltcntl
=
0
;
par
->
depth
=
1
;
par
->
blit_bpp
=
BPP8
;
break
;
case
16
:
if
(
var
->
green
.
length
==
5
)
par
->
pixconf
=
PIXCONF15
;
else
par
->
pixconf
=
PIXCONF16
;
par
->
bltcntl
=
16
;
par
->
depth
=
2
;
par
->
blit_bpp
=
BPP16
;
break
;
case
24
:
par
->
pixconf
=
PIXCONF24
;
par
->
bltcntl
=
32
;
par
->
depth
=
3
;
par
->
blit_bpp
=
BPP24
;
break
;
case
32
:
par
->
pixconf
=
PIXCONF32
;
par
->
bltcntl
=
0
;
par
->
depth
=
4
;
par
->
blit_bpp
=
3
<<
24
;
break
;
}
if
(
var
->
nonstd
&&
var
->
bits_per_pixel
!=
8
)
par
->
pixconf
|=
1
<<
27
;
i810_calc_dclk
(
var
->
pixclock
,
&
par
->
regs
.
M
,
&
par
->
regs
.
N
,
&
par
->
regs
.
P
);
i810fb_encode_registers
(
var
,
par
,
xres
,
yres
);
par
->
watermark
=
i810_get_watermark
(
var
,
par
);
par
->
pitch
=
get_line_length
(
par
,
vxres
,
var
->
bits_per_pixel
);
}
/**
* i810fb_getcolreg - gets red, green and blue values of the hardware DAC
* @regno: DAC index
* @red: red
* @green: green
* @blue: blue
* @transp: transparency (alpha)
* @info: pointer to fb_info
*
* DESCRIPTION:
* Gets the red, green and blue values of the hardware DAC as pointed by @regno
* and writes them to @red, @green and @blue respectively
*/
static
int
i810fb_getcolreg
(
u8
regno
,
u8
*
red
,
u8
*
green
,
u8
*
blue
,
u8
*
transp
,
struct
fb_info
*
info
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
info
->
par
;
u8
*
mmio
=
par
->
mmio_start_virtual
,
temp
;
if
(
regno
>
255
)
return
1
;
if
(
info
->
fix
.
visual
==
FB_VISUAL_DIRECTCOLOR
)
{
if
((
info
->
var
.
green
.
length
==
5
&&
regno
>
31
)
||
(
info
->
var
.
green
.
length
==
6
&&
regno
>
63
))
return
1
;
}
temp
=
i810_readb
(
PIXCONF1
,
mmio
);
i810_writeb
(
PIXCONF1
,
mmio
,
temp
&
~
EXTENDED_PALETTE
);
if
(
info
->
fix
.
visual
==
FB_VISUAL_DIRECTCOLOR
&&
info
->
var
.
green
.
length
==
5
)
i810_read_dac
(
regno
*
8
,
red
,
green
,
blue
,
mmio
);
else
if
(
info
->
fix
.
visual
==
FB_VISUAL_DIRECTCOLOR
&&
info
->
var
.
green
.
length
==
6
)
{
u8
tmp
;
i810_read_dac
(
regno
*
8
,
red
,
&
tmp
,
blue
,
mmio
);
i810_read_dac
(
regno
*
4
,
&
tmp
,
green
,
&
tmp
,
mmio
);
}
else
i810_read_dac
(
regno
,
red
,
green
,
blue
,
mmio
);
*
transp
=
0
;
i810_writeb
(
PIXCONF1
,
mmio
,
temp
);
return
0
;
}
/******************************************************************
* Framebuffer device-specific hooks *
******************************************************************/
static
int
i810fb_open
(
struct
fb_info
*
info
,
int
user
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
info
->
par
;
u32
count
=
atomic_read
(
&
par
->
use_count
);
if
(
count
==
0
)
{
memset
(
&
par
->
state
,
0
,
sizeof
(
struct
vgastate
));
par
->
state
.
flags
=
VGA_SAVE_CMAP
;
par
->
state
.
vgabase
=
(
caddr_t
)
par
->
mmio_start_virtual
;
save_vga
(
&
par
->
state
);
i810_save_vga_state
(
par
);
}
atomic_inc
(
&
par
->
use_count
);
return
0
;
}
static
int
i810fb_release
(
struct
fb_info
*
info
,
int
user
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
info
->
par
;
u32
count
;
count
=
atomic_read
(
&
par
->
use_count
);
if
(
count
==
0
)
return
-
EINVAL
;
if
(
count
==
1
)
{
i810_restore_vga_state
(
par
);
restore_vga
(
&
par
->
state
);
}
atomic_dec
(
&
par
->
use_count
);
return
0
;
}
static
int
i810fb_setcolreg
(
unsigned
regno
,
unsigned
red
,
unsigned
green
,
unsigned
blue
,
unsigned
transp
,
struct
fb_info
*
info
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
info
->
par
;
u8
*
mmio
=
par
->
mmio_start_virtual
,
temp
;
int
i
;
if
(
regno
>
255
)
return
1
;
if
(
info
->
fix
.
visual
==
FB_VISUAL_DIRECTCOLOR
)
{
if
((
info
->
var
.
green
.
length
==
5
&&
regno
>
31
)
||
(
info
->
var
.
green
.
length
==
6
&&
regno
>
63
))
return
1
;
}
if
(
info
->
var
.
grayscale
)
red
=
green
=
blue
=
(
19595
*
red
+
38470
*
green
+
7471
*
blue
)
>>
16
;
temp
=
i810_readb
(
PIXCONF1
,
mmio
);
i810_writeb
(
PIXCONF1
,
mmio
,
temp
&
~
EXTENDED_PALETTE
);
if
(
info
->
fix
.
visual
==
FB_VISUAL_DIRECTCOLOR
&&
info
->
var
.
green
.
length
==
5
)
{
for
(
i
=
0
;
i
<
8
;
i
++
)
i810_write_dac
((
u8
)
(
regno
*
8
)
+
i
,
(
u8
)
red
,
(
u8
)
green
,
(
u8
)
blue
,
mmio
);
}
else
if
(
info
->
fix
.
visual
==
FB_VISUAL_DIRECTCOLOR
&&
info
->
var
.
green
.
length
==
6
)
{
if
(
!
regno
)
{
memset
(
par
->
red
,
0
,
64
);
memset
(
par
->
green
,
0
,
64
);
memset
(
par
->
blue
,
0
,
64
);
}
par
->
red
[
regno
]
=
(
u8
)
red
;
par
->
green
[
regno
]
=
(
u8
)
green
;
par
->
blue
[
regno
]
=
(
u8
)
blue
;
if
(
regno
<
32
)
{
for
(
i
=
0
;
i
<
8
;
i
++
)
i810_write_dac
((
u8
)
(
regno
*
8
)
+
i
,
(
u8
)
red
,
par
->
green
[
regno
*
2
],
(
u8
)
blue
,
mmio
);
}
for
(
i
=
0
;
i
<
4
;
i
++
)
i810_write_dac
((
u8
)
(
regno
*
4
)
+
i
,
par
->
red
[
regno
/
2
],
(
u8
)
green
,
par
->
blue
[
regno
/
2
],
mmio
);
}
else
{
i810_write_dac
((
u8
)
regno
,
(
u8
)
red
,
(
u8
)
green
,
(
u8
)
blue
,
mmio
);
}
i810_writeb
(
PIXCONF1
,
mmio
,
temp
);
if
(
regno
<
16
)
{
switch
(
info
->
var
.
bits_per_pixel
)
{
case
16
:
if
(
info
->
fix
.
visual
==
FB_VISUAL_DIRECTCOLOR
)
{
if
(
info
->
var
.
green
.
length
==
5
)
((
u32
*
)
info
->
pseudo_palette
)[
regno
]
=
(
regno
<<
10
)
|
(
regno
<<
5
)
|
regno
;
else
((
u32
*
)
info
->
pseudo_palette
)[
regno
]
=
(
regno
<<
11
)
|
(
regno
<<
5
)
|
regno
;
}
else
{
if
(
info
->
var
.
green
.
length
==
5
)
{
/* RGB 555 */
((
u32
*
)
info
->
pseudo_palette
)[
regno
]
=
((
red
&
0xf800
)
>>
1
)
|
((
green
&
0xf800
)
>>
6
)
|
((
blue
&
0xf800
)
>>
11
);
}
else
{
/* RGB 565 */
((
u32
*
)
info
->
pseudo_palette
)[
regno
]
=
(
red
&
0xf800
)
|
((
green
&
0xf800
)
>>
5
)
|
((
blue
&
0xf800
)
>>
11
);
}
}
break
;
case
24
:
/* RGB 888 */
case
32
:
/* RGBA 8888 */
if
(
info
->
fix
.
visual
==
FB_VISUAL_DIRECTCOLOR
)
((
u32
*
)
info
->
pseudo_palette
)[
regno
]
=
(
regno
<<
16
)
|
(
regno
<<
8
)
|
regno
;
else
((
u32
*
)
info
->
pseudo_palette
)[
regno
]
=
((
red
&
0xff00
)
<<
8
)
|
(
green
&
0xff00
)
|
((
blue
&
0xff00
)
>>
8
);
break
;
}
}
return
0
;
}
static
int
i810fb_pan_display
(
struct
fb_var_screeninfo
*
var
,
struct
fb_info
*
info
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
info
->
par
;
u32
total
;
u8
*
mmio
=
par
->
mmio_start_virtual
;
int
xoffset
=
var
->
xoffset
,
yoffset
=
var
->
yoffset
;
if
(
xoffset
<
0
||
xoffset
+
var
->
xres
>
var
->
xres_virtual
||
yoffset
<
0
||
yoffset
+
var
->
yres
>
var
->
yres_virtual
)
return
-
EINVAL
;
total
=
xoffset
*
par
->
depth
+
yoffset
*
info
->
fix
.
line_length
;
i810_writel
(
DPLYBASE
,
mmio
,
par
->
fb
.
physical
+
total
);
return
0
;
}
static
int
i810fb_blank
(
int
blank_mode
,
struct
fb_info
*
info
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
info
->
par
;
u8
*
mmio
=
par
->
mmio_start_virtual
;
int
mode
=
0
,
pwr
,
scr_off
=
0
;
pwr
=
i810_readl
(
PWR_CLKC
,
mmio
);
switch
(
blank_mode
)
{
case
VESA_NO_BLANKING
:
mode
=
POWERON
;
pwr
|=
1
;
scr_off
=
ON
;
break
;
case
VESA_VSYNC_SUSPEND
:
mode
=
STANDBY
;
pwr
|=
1
;
scr_off
=
OFF
;
break
;
case
VESA_HSYNC_SUSPEND
:
mode
=
SUSPEND
;
pwr
|=
1
;
scr_off
=
OFF
;
break
;
case
VESA_POWERDOWN
:
mode
=
POWERDOWN
;
pwr
&=
~
1
;
scr_off
=
OFF
;
break
;
default:
return
-
EINVAL
;
}
i810_screen_off
(
mmio
,
scr_off
);
i810_writel
(
HVSYNC
,
mmio
,
mode
);
i810_writel
(
PWR_CLKC
,
mmio
,
pwr
);
return
0
;
}
static
int
i810fb_set_par
(
struct
fb_info
*
info
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
info
->
par
;
i810_load_regs
(
par
);
i810_init_cursor
(
par
);
par
->
cursor_reset
=
1
;
encode_fix
(
&
info
->
fix
,
info
);
return
0
;
}
static
int
i810fb_check_var
(
struct
fb_var_screeninfo
*
var
,
struct
fb_info
*
info
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
info
->
par
;
int
err
;
if
(
IS_DVT
)
{
var
->
vmode
&=
~
FB_VMODE_MASK
;
var
->
vmode
|=
FB_VMODE_NONINTERLACED
;
}
if
(
var
->
vmode
&
FB_VMODE_DOUBLE
)
{
var
->
vmode
&=
~
FB_VMODE_MASK
;
var
->
vmode
|=
FB_VMODE_NONINTERLACED
;
}
i810_round_off
(
var
);
if
((
err
=
i810_check_params
(
var
,
info
)))
return
err
;
i810fb_fill_var_timings
(
var
);
set_color_bitfields
(
var
);
decode_var
(
&
info
->
var
,
par
,
info
);
return
0
;
}
static
int
i810fb_cursor
(
struct
fb_info
*
info
,
struct
fb_cursor
*
cursor
)
{
static
u8
data
[
64
*
8
];
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
info
->
par
;
u8
*
mmio
=
par
->
mmio_start_virtual
;
u16
flags
=
cursor
->
set
;
if
(
!
info
->
var
.
accel_flags
||
par
->
dev_flags
&
LOCKUP
)
{
return
soft_cursor
(
info
,
cursor
);
}
if
(
cursor
->
image
.
width
>
64
||
cursor
->
image
.
height
>
64
||
(
cursor
->
dest
==
NULL
&&
cursor
->
rop
==
ROP_XOR
))
return
1
;
if
((
i810_readl
(
CURBASE
,
mmio
)
&
0xf
)
!=
par
->
cursor_heap
.
physical
)
{
i810_init_cursor
(
par
);
par
->
cursor_reset
=
1
;
}
if
(
par
->
cursor_reset
)
{
flags
=
FB_CUR_SETALL
;
par
->
cursor_reset
=
0
;
}
i810_enable_cursor
(
mmio
,
OFF
);
if
(
flags
&
FB_CUR_SETPOS
)
{
u32
tmp
;
tmp
=
cursor
->
image
.
dx
-
info
->
var
.
xoffset
;
tmp
|=
(
cursor
->
image
.
dy
-
info
->
var
.
yoffset
)
<<
16
;
i810_writel
(
CURPOS
,
mmio
,
tmp
);
}
if
(
flags
&
FB_CUR_SETSIZE
)
{
i810_reset_cursor_image
(
par
);
}
if
(
flags
&
FB_CUR_SETCMAP
)
{
i810_load_cursor_colors
(
cursor
->
image
.
fg_color
,
cursor
->
image
.
bg_color
,
info
);
}
if
(
flags
&
(
FB_CUR_SETDEST
|
FB_CUR_SETSHAPE
))
{
int
size
=
((
cursor
->
image
.
width
+
7
)
/
8
)
*
cursor
->
image
.
height
;
int
i
;
switch
(
cursor
->
rop
)
{
case
ROP_XOR
:
for
(
i
=
0
;
i
<
size
;
i
++
)
{
data
[
i
]
=
(
cursor
->
image
.
data
[
i
]
&
cursor
->
mask
[
i
])
^
cursor
->
dest
[
i
];
}
break
;
case
ROP_COPY
:
default:
for
(
i
=
0
;
i
<
size
;
i
++
)
{
data
[
i
]
=
cursor
->
image
.
data
[
i
]
&
cursor
->
mask
[
i
];
}
break
;
}
i810_load_cursor_image
(
cursor
->
image
.
width
,
cursor
->
image
.
height
,
data
,
par
);
}
if
(
cursor
->
enable
)
i810_enable_cursor
(
mmio
,
ON
);
return
0
;
}
static
struct
fb_ops
i810fb_ops
__initdata
=
{
.
owner
=
THIS_MODULE
,
.
fb_open
=
i810fb_open
,
.
fb_release
=
i810fb_release
,
.
fb_check_var
=
i810fb_check_var
,
.
fb_set_par
=
i810fb_set_par
,
.
fb_setcolreg
=
i810fb_setcolreg
,
.
fb_blank
=
i810fb_blank
,
.
fb_pan_display
=
i810fb_pan_display
,
.
fb_fillrect
=
i810fb_fillrect
,
.
fb_copyarea
=
i810fb_copyarea
,
.
fb_imageblit
=
i810fb_imageblit
,
.
fb_cursor
=
i810fb_cursor
,
};
/***********************************************************************
* AGP resource allocation *
***********************************************************************/
static
void
__devinit
i810_fix_pointers
(
struct
i810fb_par
*
par
)
{
par
->
fb
.
physical
=
par
->
aperture
.
physical
+
(
par
->
fb
.
offset
<<
12
);
par
->
fb
.
virtual
=
par
->
aperture
.
virtual
+
(
par
->
fb
.
offset
<<
12
);
par
->
iring
.
physical
=
par
->
aperture
.
physical
+
(
par
->
iring
.
offset
<<
12
);
par
->
iring
.
virtual
=
par
->
aperture
.
virtual
+
(
par
->
iring
.
offset
<<
12
);
par
->
cursor_heap
.
virtual
=
par
->
aperture
.
virtual
+
(
par
->
cursor_heap
.
offset
<<
12
);
par
->
pixmap
.
virtual
=
par
->
aperture
.
virtual
+
(
par
->
pixmap
.
offset
<<
12
);
par
->
pixmap
.
physical
=
par
->
aperture
.
physical
+
(
par
->
pixmap
.
offset
<<
12
);
}
static
void
__devinit
i810_fix_offsets
(
struct
i810fb_par
*
par
)
{
if
(
vram
+
1
>
par
->
aperture
.
size
>>
20
)
vram
=
(
par
->
aperture
.
size
>>
20
)
-
1
;
if
(
v_offset_default
>
(
par
->
aperture
.
size
>>
20
))
v_offset_default
=
(
par
->
aperture
.
size
>>
20
);
if
(
vram
+
v_offset_default
+
1
>
par
->
aperture
.
size
>>
20
)
v_offset_default
=
(
par
->
aperture
.
size
>>
20
)
-
(
vram
+
1
);
par
->
fb
.
size
=
vram
<<
20
;
par
->
fb
.
offset
=
v_offset_default
<<
20
;
par
->
fb
.
offset
>>=
12
;
par
->
iring
.
offset
=
par
->
fb
.
offset
+
(
par
->
fb
.
size
>>
12
);
par
->
iring
.
size
=
RINGBUFFER_SIZE
;
par
->
pixmap
.
offset
=
par
->
iring
.
offset
+
(
RINGBUFFER_SIZE
>>
12
);
par
->
pixmap
.
size
=
PIXMAP_SIZE
;
par
->
cursor_heap
.
offset
=
par
->
pixmap
.
offset
+
(
PIXMAP_SIZE
>>
12
);
par
->
cursor_heap
.
size
=
4096
;
}
static
int
__devinit
i810_alloc_agp_mem
(
struct
fb_info
*
info
)
{
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
info
->
par
;
int
size
;
i810_fix_offsets
(
par
);
size
=
par
->
fb
.
size
+
par
->
iring
.
size
+
par
->
pixmap
.
size
;
par
->
drm_agp
=
(
drm_agp_t
*
)
inter_module_get
(
"drm_agp"
);
if
(
!
par
->
drm_agp
)
{
printk
(
"i810fb: cannot acquire agp
\n
"
);
return
-
ENODEV
;
}
par
->
drm_agp
->
acquire
();
if
(
!
(
par
->
i810_gtt
.
i810_fb_memory
=
par
->
drm_agp
->
allocate_memory
(
size
>>
12
,
AGP_NORMAL_MEMORY
)))
{
printk
(
"i810fb_alloc_fbmem: can't allocate framebuffer "
"memory
\n
"
);
par
->
drm_agp
->
release
();
return
-
ENOMEM
;
}
if
(
par
->
drm_agp
->
bind_memory
(
par
->
i810_gtt
.
i810_fb_memory
,
par
->
fb
.
offset
))
{
printk
(
"i810fb_alloc_fbmem: can't bind framebuffer memory
\n
"
);
par
->
drm_agp
->
release
();
return
-
EBUSY
;
}
if
(
!
(
par
->
i810_gtt
.
i810_cursor_memory
=
par
->
drm_agp
->
allocate_memory
(
par
->
cursor_heap
.
size
>>
12
,
AGP_PHYSICAL_MEMORY
)))
{
printk
(
"i810fb_alloc_cursormem: can't allocate"
"cursor memory
\n
"
);
par
->
drm_agp
->
release
();
return
-
ENOMEM
;
}
if
(
par
->
drm_agp
->
bind_memory
(
par
->
i810_gtt
.
i810_cursor_memory
,
par
->
cursor_heap
.
offset
))
{
printk
(
"i810fb_alloc_cursormem: cannot bind cursor memory
\n
"
);
par
->
drm_agp
->
release
();
return
-
EBUSY
;
}
par
->
cursor_heap
.
physical
=
par
->
i810_gtt
.
i810_cursor_memory
->
physical
;
i810_fix_pointers
(
par
);
par
->
drm_agp
->
release
();
return
0
;
}
/***************************************************************
* Initialization *
***************************************************************/
/**
* i810_init_monspecs
* @info: pointer to device specific info structure
*
* DESCRIPTION:
* Sets the the user monitor's horizontal and vertical
* frequency limits
*/
static
void
__devinit
i810_init_monspecs
(
struct
fb_info
*
info
)
{
if
(
!
hsync1
)
hsync1
=
HFMIN
;
if
(
!
hsync2
)
hsync2
=
HFMAX
;
info
->
monspecs
.
hfmax
=
hsync2
;
info
->
monspecs
.
hfmin
=
hsync1
;
if
(
hsync2
<
hsync1
)
info
->
monspecs
.
hfmin
=
hsync2
;
if
(
!
vsync1
)
vsync1
=
VFMIN
;
if
(
!
vsync2
)
vsync2
=
VFMAX
;
if
(
IS_DVT
&&
vsync1
<
60
)
vsync1
=
60
;
info
->
monspecs
.
vfmax
=
vsync2
;
info
->
monspecs
.
vfmin
=
vsync1
;
if
(
vsync2
<
vsync1
)
info
->
monspecs
.
vfmin
=
vsync2
;
}
/**
* i810_init_defaults - initializes default values to use
* @par: pointer to i810fb_par structure
* @info: pointer to current fb_info structure
*/
static
void
__devinit
i810_init_defaults
(
struct
i810fb_par
*
par
,
struct
fb_info
*
info
)
{
if
(
voffset
)
{
v_offset_default
=
voffset
;
}
else
{
if
(
par
->
aperture
.
size
>
32
*
1024
*
1024
)
v_offset_default
=
16
;
else
v_offset_default
=
8
;
}
if
(
!
vram
)
vram
=
1
;
if
(
accel
)
par
->
dev_flags
|=
HAS_ACCELERATION
;
if
(
sync
)
par
->
dev_flags
|=
ALWAYS_SYNC
;
if
(
bpp
<
8
)
bpp
=
8
;
if
(
!
vyres
)
vyres
=
(
vram
<<
20
)
/
(
xres
*
bpp
>>
3
);
par
->
i810fb_ops
=
i810fb_ops
;
i810fb_default
.
xres
=
xres
;
i810fb_default
.
yres
=
yres
;
i810fb_default
.
yres_virtual
=
vyres
;
i810fb_default
.
bits_per_pixel
=
bpp
;
if
(
dcolor
)
i810fb_default
.
nonstd
=
1
;
if
(
par
->
dev_flags
&
HAS_ACCELERATION
)
i810fb_default
.
accel_flags
=
1
;
i810_init_monspecs
(
info
);
}
/**
* i810_init_device - initialize device
* @par: pointer to i810fb_par structure
*/
static
void
__devinit
i810_init_device
(
struct
i810fb_par
*
par
)
{
u8
reg
,
*
mmio
=
par
->
mmio_start_virtual
;
if
(
mtrr
)
set_mtrr
(
par
);
i810_init_cursor
(
par
);
/* mvo: enable external vga-connector (for laptops) */
if
(
ext_vga
)
{
i810_writel
(
HVSYNC
,
mmio
,
0
);
i810_writel
(
PWR_CLKC
,
mmio
,
3
);
}
pci_read_config_byte
(
par
->
dev
,
0x50
,
&
reg
);
reg
&=
FREQ_MASK
;
par
->
mem_freq
=
(
reg
)
?
133
:
100
;
i810fb_init_ringbuffer
(
par
);
}
static
int
__devinit
i810_allocate_pci_resource
(
struct
i810fb_par
*
par
,
const
struct
pci_device_id
*
entry
)
{
int
err
;
if
((
err
=
pci_enable_device
(
par
->
dev
)))
{
printk
(
"i810fb_init: cannot enable device
\n
"
);
return
err
;
}
par
->
res_flags
|=
PCI_DEVICE_ENABLED
;
if
(
pci_resource_len
(
par
->
dev
,
0
)
>
512
*
1024
)
{
par
->
aperture
.
physical
=
pci_resource_start
(
par
->
dev
,
0
);
par
->
aperture
.
size
=
pci_resource_len
(
par
->
dev
,
0
);
par
->
mmio_start_phys
=
pci_resource_start
(
par
->
dev
,
1
);
}
else
{
par
->
aperture
.
physical
=
pci_resource_start
(
par
->
dev
,
1
);
par
->
aperture
.
size
=
pci_resource_len
(
par
->
dev
,
1
);
par
->
mmio_start_phys
=
pci_resource_start
(
par
->
dev
,
0
);
}
if
(
!
par
->
aperture
.
size
)
{
printk
(
"i810fb_init: device is disabled
\n
"
);
return
-
ENOMEM
;
}
if
(
!
request_mem_region
(
par
->
aperture
.
physical
,
par
->
aperture
.
size
,
i810_pci_list
[
entry
->
driver_data
]))
{
printk
(
"i810fb_init: cannot request framebuffer region
\n
"
);
return
-
ENODEV
;
}
par
->
res_flags
|=
FRAMEBUFFER_REQ
;
par
->
aperture
.
virtual
=
ioremap
(
par
->
aperture
.
physical
,
par
->
aperture
.
size
);
if
(
!
par
->
aperture
.
virtual
)
{
printk
(
"i810fb_init: cannot remap framebuffer region
\n
"
);
return
-
ENODEV
;
}
if
(
!
request_mem_region
(
par
->
mmio_start_phys
,
MMIO_SIZE
,
i810_pci_list
[
entry
->
driver_data
]))
{
printk
(
"i810fb_init: cannot request mmio region
\n
"
);
return
-
ENODEV
;
}
par
->
res_flags
|=
MMIO_REQ
;
par
->
mmio_start_virtual
=
ioremap_nocache
(
par
->
mmio_start_phys
,
MMIO_SIZE
);
if
(
!
par
->
mmio_start_virtual
)
{
printk
(
"i810fb_init: cannot remap mmio region
\n
"
);
return
-
ENODEV
;
}
return
0
;
}
int
__init
i810fb_setup
(
char
*
options
)
{
char
*
this_opt
,
*
suffix
=
NULL
;
i810_init
=
1
;
if
(
!
options
||
!*
options
)
return
0
;
while
((
this_opt
=
strsep
(
&
options
,
","
))
!=
NULL
)
{
if
(
!
strncmp
(
this_opt
,
"mtrr"
,
4
))
mtrr
=
1
;
else
if
(
!
strncmp
(
this_opt
,
"accel"
,
5
))
accel
=
1
;
else
if
(
!
strncmp
(
this_opt
,
"ext_vga"
,
7
))
ext_vga
=
1
;
else
if
(
!
strncmp
(
this_opt
,
"sync"
,
4
))
sync
=
1
;
else
if
(
!
strncmp
(
this_opt
,
"vram:"
,
5
))
vram
=
(
simple_strtoul
(
this_opt
+
5
,
NULL
,
0
));
else
if
(
!
strncmp
(
this_opt
,
"voffset:"
,
8
))
voffset
=
(
simple_strtoul
(
this_opt
+
8
,
NULL
,
0
));
else
if
(
!
strncmp
(
this_opt
,
"xres:"
,
5
))
xres
=
simple_strtoul
(
this_opt
+
5
,
NULL
,
0
);
else
if
(
!
strncmp
(
this_opt
,
"yres:"
,
5
))
yres
=
simple_strtoul
(
this_opt
+
5
,
NULL
,
0
);
else
if
(
!
strncmp
(
this_opt
,
"vyres:"
,
6
))
vyres
=
simple_strtoul
(
this_opt
+
6
,
NULL
,
0
);
else
if
(
!
strncmp
(
this_opt
,
"bpp:"
,
4
))
bpp
=
simple_strtoul
(
this_opt
+
4
,
NULL
,
0
);
else
if
(
!
strncmp
(
this_opt
,
"hsync1:"
,
7
))
{
hsync1
=
simple_strtoul
(
this_opt
+
7
,
&
suffix
,
0
);
if
(
strncmp
(
suffix
,
"H"
,
1
))
hsync1
*=
1000
;
}
else
if
(
!
strncmp
(
this_opt
,
"hsync2:"
,
7
))
{
hsync2
=
simple_strtoul
(
this_opt
+
7
,
&
suffix
,
0
);
if
(
strncmp
(
suffix
,
"H"
,
1
))
hsync2
*=
1000
;
}
else
if
(
!
strncmp
(
this_opt
,
"vsync1:"
,
7
))
vsync1
=
simple_strtoul
(
this_opt
+
7
,
NULL
,
0
);
else
if
(
!
strncmp
(
this_opt
,
"vsync2:"
,
7
))
vsync2
=
simple_strtoul
(
this_opt
+
7
,
NULL
,
0
);
else
if
(
!
strncmp
(
this_opt
,
"dcolor"
,
6
))
dcolor
=
1
;
}
return
0
;
}
static
int
__devinit
i810fb_init_pci
(
struct
pci_dev
*
dev
,
const
struct
pci_device_id
*
entry
)
{
struct
fb_info
*
info
;
struct
i810fb_par
*
par
=
NULL
;
int
err
,
vfreq
,
hfreq
,
pixclock
;
if
(
!
i810_init
)
return
-
EINVAL
;
if
(
!
(
info
=
kmalloc
(
sizeof
(
struct
fb_info
),
GFP_KERNEL
)))
{
i810fb_release_resource
(
info
,
par
);
return
-
ENOMEM
;
}
memset
(
info
,
0
,
sizeof
(
struct
fb_info
));
if
(
!
(
par
=
kmalloc
(
sizeof
(
struct
i810fb_par
),
GFP_KERNEL
)))
{
i810fb_release_resource
(
info
,
par
);
return
-
ENOMEM
;
}
memset
(
par
,
0
,
sizeof
(
struct
i810fb_par
));
par
->
dev
=
dev
;
info
->
par
=
par
;
if
((
err
=
i810_allocate_pci_resource
(
par
,
entry
)))
{
i810fb_release_resource
(
info
,
par
);
return
err
;
}
i810_init_defaults
(
par
,
info
);
if
((
err
=
i810_alloc_agp_mem
(
info
)))
{
i810fb_release_resource
(
info
,
par
);
return
err
;
}
i810_init_device
(
par
);
info
->
screen_base
=
par
->
fb
.
virtual
;
info
->
node
=
NODEV
;
info
->
fbops
=
&
par
->
i810fb_ops
;
info
->
pseudo_palette
=
par
->
pseudo_palette
;
info
->
flags
=
FBINFO_FLAG_DEFAULT
;
fb_alloc_cmap
(
&
info
->
cmap
,
256
,
0
);
info
->
var
=
i810fb_default
;
if
((
err
=
info
->
fbops
->
fb_check_var
(
&
info
->
var
,
info
)))
{
i810fb_release_resource
(
info
,
par
);
return
err
;
}
encode_fix
(
&
info
->
fix
,
info
);
err
=
register_framebuffer
(
info
);
if
(
err
<
0
)
{
i810fb_release_resource
(
info
,
par
);
printk
(
"i810fb_init: cannot register framebuffer device
\n
"
);
return
err
;
}
pci_set_drvdata
(
dev
,
info
);
pixclock
=
1000000000
/
(
info
->
var
.
pixclock
);
pixclock
*=
1000
;
hfreq
=
pixclock
/
(
info
->
var
.
xres
+
info
->
var
.
left_margin
+
info
->
var
.
hsync_len
+
info
->
var
.
right_margin
);
vfreq
=
hfreq
/
(
info
->
var
.
yres
+
info
->
var
.
upper_margin
+
info
->
var
.
vsync_len
+
info
->
var
.
lower_margin
);
printk
(
"fb: %s v%d.%d.%d%s, Tony Daplas
\n
"
" Video RAM : %dK
\n
"
" Mode : %dx%d-%dbpp@%dHz
\n
"
" Acceleration : %sabled
\n
"
" MTRR : %sabled
\n
"
" External VGA : %sabled
\n
"
" Video Timings : %s
\n
"
,
i810_pci_list
[
entry
->
driver_data
],
VERSION_MAJOR
,
VERSION_MINOR
,
VERSION_TEENIE
,
BRANCH_VERSION
,
(
int
)
par
->
fb
.
size
>>
10
,
info
->
var
.
xres
,
info
->
var
.
yres
,
info
->
var
.
bits_per_pixel
,
vfreq
,
(
par
->
dev_flags
&
HAS_ACCELERATION
)
?
"en"
:
"dis"
,
(
par
->
dev_flags
&
HAS_MTRR
)
?
"en"
:
"dis"
,
(
ext_vga
)
?
"en"
:
"dis"
,
(
IS_DVT
)
?
"Intel(R) DVT"
:
"VESA GTF (US)"
);
return
0
;
}
/***************************************************************
* Deinitialization *
***************************************************************/
static
void
i810fb_release_resource
(
struct
fb_info
*
info
,
struct
i810fb_par
*
par
)
{
if
(
par
)
{
unset_mtrr
(
par
);
if
(
par
->
drm_agp
)
{
drm_agp_t
*
agp
=
par
->
drm_agp
;
struct
gtt_data
*
gtt
=
&
par
->
i810_gtt
;
if
(
par
->
i810_gtt
.
i810_cursor_memory
)
agp
->
free_memory
(
gtt
->
i810_cursor_memory
);
if
(
par
->
i810_gtt
.
i810_fb_memory
)
agp
->
free_memory
(
gtt
->
i810_fb_memory
);
inter_module_put
(
"drm_agp"
);
par
->
drm_agp
=
NULL
;
}
if
(
par
->
mmio_start_virtual
)
iounmap
(
par
->
mmio_start_virtual
);
if
(
par
->
aperture
.
virtual
)
iounmap
(
par
->
aperture
.
virtual
);
if
(
par
->
res_flags
&
FRAMEBUFFER_REQ
)
release_mem_region
(
par
->
aperture
.
physical
,
par
->
aperture
.
size
);
if
(
par
->
res_flags
&
MMIO_REQ
)
release_mem_region
(
par
->
mmio_start_phys
,
MMIO_SIZE
);
if
(
par
->
res_flags
&
PCI_DEVICE_ENABLED
)
pci_disable_device
(
par
->
dev
);
kfree
(
par
);
}
if
(
info
)
kfree
(
info
);
}
static
void
__devexit
i810fb_remove_pci
(
struct
pci_dev
*
dev
)
{
struct
fb_info
*
info
=
pci_get_drvdata
(
dev
);
struct
i810fb_par
*
par
=
(
struct
i810fb_par
*
)
info
->
par
;
unregister_framebuffer
(
info
);
i810fb_release_resource
(
info
,
par
);
pci_set_drvdata
(
dev
,
NULL
);
printk
(
"cleanup_module: unloaded i810 framebuffer device
\n
"
);
}
#ifndef MODULE
int
__init
i810fb_init
(
void
)
{
if
(
agp_init
())
{
printk
(
"i810fb_init: cannot initialize agpgart
\n
"
);
return
-
ENODEV
;
}
if
(
agp_intel_init
())
{
printk
(
"i810fb_init: cannot initialize intel agpgart
\n
"
);
return
-
ENODEV
;
}
return
(
pci_module_init
(
&
i810fb_driver
));
}
#endif
/*********************************************************************
* Modularization *
*********************************************************************/
#ifdef MODULE
int
__init
i810fb_init
(
void
)
{
i810_init
=
1
;
hsync1
*=
1000
;
hsync2
*=
1000
;
return
(
pci_module_init
(
&
i810fb_driver
));
}
MODULE_PARM
(
vram
,
"i"
);
MODULE_PARM_DESC
(
vram
,
"System RAM to allocate to framebuffer in MiB"
" (default=4)"
);
MODULE_PARM
(
voffset
,
"i"
);
MODULE_PARM_DESC
(
voffset
,
"at what offset to place start of framebuffer "
"memory (0 to maximum aperture size), in MiB (default = 48)"
);
MODULE_PARM
(
bpp
,
"i"
);
MODULE_PARM_DESC
(
bpp
,
"Color depth for display in bits per pixel"
" (default = 8)"
);
MODULE_PARM
(
xres
,
"i"
);
MODULE_PARM_DESC
(
xres
,
"Hozizontal resolution in pixels (default = 640)"
);
MODULE_PARM
(
yres
,
"i"
);
MODULE_PARM_DESC
(
yres
,
"Vertical resolution in scanlines (default = 480)"
);
MODULE_PARM
(
vyres
,
"i"
);
MODULE_PARM_DESC
(
vyres
,
"Virtual vertical resolution in scanlines"
" (default = 480)"
);
MODULE_PARM
(
hsync1
,
"i"
);
MODULE_PARM_DESC
(
hsync1
,
"Mimimum horizontal frequency of monitor in KHz"
" (default = 31)"
);
MODULE_PARM
(
hsync2
,
"i"
);
MODULE_PARM_DESC
(
hsync2
,
"Maximum horizontal frequency of monitor in KHz"
" (default = 31)"
);
MODULE_PARM
(
vsync1
,
"i"
);
MODULE_PARM_DESC
(
vsync1
,
"Minimum vertical frequency of monitor in Hz"
" (default = 50)"
);
MODULE_PARM
(
vsync2
,
"i"
);
MODULE_PARM_DESC
(
vsync2
,
"Maximum vertical frequency of monitor in Hz"
" (default = 60)"
);
MODULE_PARM
(
accel
,
"i"
);
MODULE_PARM_DESC
(
accel
,
"Use Acceleration (BLIT) engine (default = 0)"
);
MODULE_PARM
(
mtrr
,
"i"
);
MODULE_PARM_DESC
(
mtrr
,
"Use MTRR (default = 0)"
);
MODULE_PARM
(
ext_vga
,
"i"
);
MODULE_PARM_DESC
(
ext_vga
,
"Enable external VGA connector (default = 0)"
);
MODULE_PARM
(
sync
,
"i"
);
MODULE_PARM_DESC
(
sync
,
"wait for accel engine to finish drawing"
" (default = 0)"
);
MODULE_PARM
(
dcolor
,
"i"
);
MODULE_PARM_DESC
(
dcolor
,
"use DirectColor visuals"
" (default = 0 = TrueColor)"
);
MODULE_AUTHOR
(
"Tony A. Daplas"
);
MODULE_DESCRIPTION
(
"Framebuffer device for the Intel 810/815 and"
" compatible cards"
);
MODULE_LICENSE
(
"GPL"
);
static
void
__exit
i810fb_exit
(
void
)
{
pci_unregister_driver
(
&
i810fb_driver
);
}
module_init
(
i810fb_init
);
module_exit
(
i810fb_exit
);
#endif
/* MODULE */
drivers/video/i810/i810_main.h
0 → 100644
View file @
0e2e212c
/*-*- linux-c -*-
* linux/drivers/video/i810fb_main.h -- Intel 810 frame buffer device
* main header file
*
* Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
* All Rights Reserved
*
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
#ifndef __I810_MAIN_H__
#define __I810_MAIN_H__
/* PCI */
static
const
char
*
i810_pci_list
[]
__devinitdata
=
{
"Intel(R) 810 Framebuffer Device"
,
"Intel(R) 810-DC100 Framebuffer Device"
,
"Intel(R) 810E Framebuffer Device"
,
"Intel(R) 815 (Internal Graphics 100Mhz FSB) Framebuffer Device"
,
"Intel(R) 815 (Internal Graphics only) Framebuffer Device"
,
"Intel(R) 815 (Internal Graphics with AGP) Framebuffer Device"
};
static
struct
pci_device_id
i810fb_pci_tbl
[]
__devinitdata
=
{
{
PCI_VENDOR_ID_INTEL
,
PCI_DEVICE_ID_INTEL_82810_IG1
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
0
},
{
PCI_VENDOR_ID_INTEL
,
PCI_DEVICE_ID_INTEL_82810_IG3
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
1
},
{
PCI_VENDOR_ID_INTEL
,
PCI_DEVICE_ID_INTEL_82810E_IG
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
2
},
/* mvo: added i815 PCI-ID */
{
PCI_VENDOR_ID_INTEL
,
PCI_DEVICE_ID_INTEL_82815_100
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
3
},
{
PCI_VENDOR_ID_INTEL
,
PCI_DEVICE_ID_INTEL_82815_NOAGP
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
4
},
{
PCI_VENDOR_ID_INTEL
,
PCI_DEVICE_ID_INTEL_82815_CGC
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
5
}
};
static
int
__devinit
i810fb_init_pci
(
struct
pci_dev
*
dev
,
const
struct
pci_device_id
*
entry
);
static
void
__devexit
i810fb_remove_pci
(
struct
pci_dev
*
dev
);
static
struct
pci_driver
i810fb_driver
=
{
.
name
=
"i810fb"
,
.
id_table
=
i810fb_pci_tbl
,
.
probe
=
i810fb_init_pci
,
.
remove
=
__devexit_p
(
i810fb_remove_pci
),
};
static
int
i810_init
__devinitdata
=
0
;
static
int
vram
__devinitdata
=
4
;
static
int
bpp
__devinitdata
=
8
;
static
int
mtrr
__devinitdata
=
0
;
static
int
accel
__devinitdata
=
0
;
static
int
hsync1
__devinitdata
=
0
;
static
int
hsync2
__devinitdata
=
0
;
static
int
vsync1
__devinitdata
=
0
;
static
int
vsync2
__devinitdata
=
0
;
static
int
xres
__devinitdata
=
640
;
static
int
yres
__devinitdata
=
480
;
static
int
vyres
__devinitdata
=
0
;
static
int
sync
__devinitdata
=
0
;
static
int
ext_vga
__devinitdata
=
0
;
static
int
dcolor
__devinitdata
=
0
;
/* "use once" vars */
static
char
i810fb_name
[
16
]
=
"i810fb"
;
static
struct
fb_var_screeninfo
i810fb_default
__devinitdata
=
{
/* 640x480, 8 bpp */
.
xres
=
640
,
.
yres
=
480
,
.
xres_virtual
=
640
,
.
yres_virtual
=
480
,
.
xoffset
=
0
,
.
yoffset
=
0
,
.
bits_per_pixel
=
8
,
.
grayscale
=
0
,
.
red
=
{
0
,
8
,
0
},
.
green
=
{
0
,
8
,
0
},
.
blue
=
{
0
,
8
,
0
},
.
transp
=
{
0
,
0
,
0
},
.
nonstd
=
0
,
.
activate
=
0
,
.
height
=
-
1
,
.
width
=
-
1
,
.
accel_flags
=
0
,
.
pixclock
=
20000
,
.
left_margin
=
64
,
.
right_margin
=
64
,
.
upper_margin
=
32
,
.
lower_margin
=
32
,
.
hsync_len
=
64
,
.
vsync_len
=
2
,
.
sync
=
0
,
.
vmode
=
FB_VMODE_NONINTERLACED
};
/*
* voffset - framebuffer offset in MiB from aperture start address. In order for
* the driver to work with X, we must try to use memory holes left untouched by X. The
* following table lists where X's different surfaces start at.
*
* ---------------------------------------------
* : : 64 MiB : 32 MiB :
* ----------------------------------------------
* : FrontBuffer : 0 : 0 :
* : DepthBuffer : 48 : 16 :
* : BackBuffer : 56 : 24 :
* ----------------------------------------------
*
* So for chipsets with 64 MiB Aperture sizes, 32 MiB for v_offset is okay, allowing up to
* 15 + 1 MiB of Framebuffer memory. For 32 MiB Aperture sizes, a v_offset of 8 MiB should
* work, allowing 7 + 1 MiB of Framebuffer memory.
* Note, the size of the hole may change depending on how much memory you allocate to X,
* and how the memory is split up between these surfaces.
*
* Note: Anytime the DepthBuffer or FrontBuffer is overlapped, X would still run but with
* DRI disabled. But if the Frontbuffer is overlapped, X will fail to load.
*
* Experiment with v_offset to find out which works best for you.
*/
static
u32
v_offset_default
__devinitdata
;
/* For 32 MiB Aper size, 8 should be the default */
static
u32
voffset
__devinitdata
=
0
;
static
int
i810fb_cursor
(
struct
fb_info
*
info
,
struct
fb_cursor
*
cursor
);
/* Chipset Specific Functions */
static
int
i810fb_set_par
(
struct
fb_info
*
info
);
static
int
i810fb_getcolreg
(
u8
regno
,
u8
*
red
,
u8
*
green
,
u8
*
blue
,
u8
*
transp
,
struct
fb_info
*
info
);
static
int
i810fb_setcolreg
(
unsigned
regno
,
unsigned
red
,
unsigned
green
,
unsigned
blue
,
unsigned
transp
,
struct
fb_info
*
info
);
static
int
i810fb_pan_display
(
struct
fb_var_screeninfo
*
var
,
struct
fb_info
*
info
);
static
int
i810fb_blank
(
int
blank_mode
,
struct
fb_info
*
info
);
/* Initialization */
static
void
i810fb_release_resource
(
struct
fb_info
*
info
,
struct
i810fb_par
*
par
);
extern
int
__init
agp_intel_init
(
void
);
extern
int
__init
agp_init
(
void
);
/* Video Timings */
extern
void
round_off_xres
(
u32
*
xres
);
extern
void
round_off_yres
(
u32
*
xres
,
u32
*
yres
);
extern
u32
i810_get_watermark
(
const
struct
fb_var_screeninfo
*
var
,
struct
i810fb_par
*
par
);
extern
void
i810fb_encode_registers
(
const
struct
fb_var_screeninfo
*
var
,
struct
i810fb_par
*
par
,
u32
xres
,
u32
yres
);
extern
void
i810fb_fill_var_timings
(
struct
fb_var_screeninfo
*
var
);
/* Accelerated Functions */
extern
void
i810fb_fillrect
(
struct
fb_info
*
p
,
struct
fb_fillrect
*
rect
);
extern
void
i810fb_copyarea
(
struct
fb_info
*
p
,
struct
fb_copyarea
*
region
);
extern
void
i810fb_imageblit
(
struct
fb_info
*
p
,
struct
fb_image
*
image
);
extern
int
i810fb_sync
(
struct
fb_info
*
p
);
extern
void
i810fb_init_ringbuffer
(
struct
i810fb_par
*
par
);
/* Conditionals */
#if defined(__i386__)
inline
void
flush_cache
(
void
)
{
asm
volatile
(
"wbinvd"
:::
"memory"
);
}
#else
#define flush_cache() do { } while(0)
#endif
#ifdef CONFIG_MTRR
#define KERNEL_HAS_MTRR 1
static
inline
void
__devinit
set_mtrr
(
struct
i810fb_par
*
par
)
{
par
->
mtrr_reg
=
mtrr_add
((
u32
)
par
->
aperture
.
physical
,
par
->
aperture
.
size
,
MTRR_TYPE_WRCOMB
,
1
);
if
(
par
->
mtrr_reg
<
0
)
{
printk
(
"set_mtrr: unable to set MTRR/n"
);
return
;
}
par
->
dev_flags
|=
HAS_MTRR
;
}
static
inline
void
unset_mtrr
(
struct
i810fb_par
*
par
)
{
if
(
par
->
dev_flags
&
HAS_MTRR
)
mtrr_del
(
par
->
mtrr_reg
,
(
u32
)
par
->
aperture
.
physical
,
par
->
aperture
.
size
);
}
#else
#define KERNEL_HAS_MTRR 0
#define set_mtrr(x) printk("set_mtrr: MTRR is disabled in the kernel\n")
#define unset_mtrr(x) do { } while (0)
#endif
/* CONFIG_MTRR */
#ifdef CONFIG_FB_I810_GTF
#define IS_DVT (0)
#else
#define IS_DVT (1)
#endif
#endif
/* __I810_MAIN_H__ */
drivers/video/i810/i810_regs.h
0 → 100644
View file @
0e2e212c
/*-*- linux-c -*-
* linux/drivers/video/i810_regs.h -- Intel 810/815 Register List
*
* Copyright (C) 2001 Antonino Daplas<adaplas@pol.net>
* All Rights Reserved
*
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
/*
* Intel 810 Chipset Family PRM 15 3.1
* GC Register Memory Address Map
*
* Based on:
* Intel (R) 810 Chipset Family
* Programmer s Reference Manual
* November 1999
* Revision 1.0
* Order Number: 298026-001 R
*
* All GC registers are memory-mapped. In addition, the VGA and extended VGA registers
* are I/O mapped.
*/
#ifndef __I810_REGS_H__
#define __I810_REGS_H__
/* Instruction and Interrupt Control Registers (01000h 02FFFh) */
#define FENCE 0x02000
#define PGTBL_CTL 0x02020
#define PGTBL_ER 0x02024
#define LRING 0x02030
#define IRING 0x02040
#define HWS_PGA 0x02080
#define IPEIR 0x02088
#define IPEHR 0x0208C
#define INSTDONE 0x02090
#define NOPID 0x02094
#define HWSTAM 0x02098
#define IER 0x020A0
#define IIR 0x020A4
#define IMR 0x020A8
#define ISR 0x020AC
#define EIR 0x020B0
#define EMR 0x020B4
#define ESR 0x020B8
#define INSTPM 0x020C0
#define INSTPS 0x020C4
#define BBP_PTR 0x020C8
#define ABB_SRT 0x020CC
#define ABB_END 0x020D0
#define DMA_FADD 0x020D4
#define FW_BLC 0x020D8
#define MEM_MODE 0x020DC
/* Memory Control Registers (03000h 03FFFh) */
#define DRT 0x03000
#define DRAMCL 0x03001
#define DRAMCH 0x03002
/* Span Cursor Registers (04000h 04FFFh) */
#define UI_SC_CTL 0x04008
/* I/O Control Registers (05000h 05FFFh) */
#define HVSYNC 0x05000
#define GPIOA 0x05010
#define GPIOB 0x05014
/* Clock Control and Power Management Registers (06000h 06FFFh) */
#define DCLK_0D 0x06000
#define DCLK_1D 0x06004
#define DCLK_2D 0x06008
#define LCD_CLKD 0x0600C
#define DCLK_0DS 0x06010
#define PWR_CLKC 0x06014
/* Graphics Translation Table Range Definition (10000h 1FFFFh) */
#define GTT 0x10000
/* Overlay Registers (30000h 03FFFFh) */
#define OVOADDR 0x30000
#define DOVOSTA 0x30008
#define GAMMA 0x30010
#define OBUF_0Y 0x30100
#define OBUF_1Y 0x30104
#define OBUF_0U 0x30108
#define OBUF_0V 0x3010C
#define OBUF_1U 0x30110
#define OBUF_1V 0x30114
#define OVOSTRIDE 0x30118
#define YRGB_VPH 0x3011C
#define UV_VPH 0x30120
#define HORZ_PH 0x30124
#define INIT_PH 0x30128
#define DWINPOS 0x3012C
#define DWINSZ 0x30130
#define SWID 0x30134
#define SWIDQW 0x30138
#define SHEIGHT 0x3013F
#define YRGBSCALE 0x30140
#define UVSCALE 0x30144
#define OVOCLRCO 0x30148
#define OVOCLRC1 0x3014C
#define DCLRKV 0x30150
#define DLCRKM 0x30154
#define SCLRKVH 0x30158
#define SCLRKVL 0x3015C
#define SCLRKM 0x30160
#define OVOCONF 0x30164
#define OVOCMD 0x30168
#define AWINPOS 0x30170
#define AWINZ 0x30174
/* BLT Engine Status (40000h 4FFFFh) (Software Debug) */
#define BR00 0x40000
#define BRO1 0x40004
#define BR02 0x40008
#define BR03 0x4000C
#define BR04 0x40010
#define BR05 0x40014
#define BR06 0x40018
#define BR07 0x4001C
#define BR08 0x40020
#define BR09 0x40024
#define BR10 0x40028
#define BR11 0x4002C
#define BR12 0x40030
#define BR13 0x40034
#define BR14 0x40038
#define BR15 0x4003C
#define BR16 0x40040
#define BR17 0x40044
#define BR18 0x40048
#define BR19 0x4004C
#define SSLADD 0x40074
#define DSLH 0x40078
#define DSLRADD 0x4007C
/* LCD/TV-Out and HW DVD Registers (60000h 6FFFFh) */
/* LCD/TV-Out */
#define HTOTAL 0x60000
#define HBLANK 0x60004
#define HSYNC 0x60008
#define VTOTAL 0x6000C
#define VBLANK 0x60010
#define VSYNC 0x60014
#define LCDTV_C 0x60018
#define OVRACT 0x6001C
#define BCLRPAT 0x60020
/* Display and Cursor Control Registers (70000h 7FFFFh) */
#define DISP_SL 0x70000
#define DISP_SLC 0x70004
#define PIXCONF 0x70008
#define PIXCONF1 0x70009
#define BLTCNTL 0x7000C
#define SWF 0x70014
#define DPLYBASE 0x70020
#define DPLYSTAS 0x70024
#define CURCNTR 0x70080
#define CURBASE 0x70084
#define CURPOS 0x70088
/* VGA Registers */
/* SMRAM Registers */
#define SMRAM 0x10
/* Graphics Control Registers */
#define GR_INDEX 0x3CE
#define GR_DATA 0x3CF
#define GR10 0x10
#define GR11 0x11
/* CRT Controller Registers */
#define CR_INDEX_MDA 0x3B4
#define CR_INDEX_CGA 0x3D4
#define CR_DATA_MDA 0x3B5
#define CR_DATA_CGA 0x3D5
#define CR30 0x30
#define CR31 0x31
#define CR32 0x32
#define CR33 0x33
#define CR35 0x35
#define CR39 0x39
#define CR40 0x40
#define CR41 0x41
#define CR42 0x42
#define CR70 0x70
#define CR80 0x80
#define CR81 0x82
/* Extended VGA Registers */
/* General Control and Status Registers */
#define ST00 0x3C2
#define ST01_MDA 0x3BA
#define ST01_CGA 0x3DA
#define FRC_READ 0x3CA
#define FRC_WRITE_MDA 0x3BA
#define FRC_WRITE_CGA 0x3DA
#define MSR_READ 0x3CC
#define MSR_WRITE 0x3C2
/* Sequencer Registers */
#define SR_INDEX 0x3C4
#define SR_DATA 0x3C5
#define SR01 0x01
#define SR02 0x02
#define SR03 0x03
#define SR04 0x04
#define SR07 0x07
/* Graphics Controller Registers */
#define GR00 0x00
#define GR01 0x01
#define GR02 0x02
#define GR03 0x03
#define GR04 0x04
#define GR05 0x05
#define GR06 0x06
#define GR07 0x07
#define GR08 0x08
/* Attribute Controller Registers */
#define ATTR_WRITE 0x3C0
#define ATTR_READ 0x3C1
/* VGA Color Palette Registers */
/* CLUT */
#define CLUT_DATA 0x3C9
/* DACDATA */
#define CLUT_INDEX_READ 0x3C7
/* DACRX */
#define CLUT_INDEX_WRITE 0x3C8
/* DACWX */
#define DACMASK 0x3C6
/* CRT Controller Registers */
#define CR00 0x00
#define CR01 0x01
#define CR02 0x02
#define CR03 0x03
#define CR04 0x04
#define CR05 0x05
#define CR06 0x06
#define CR07 0x07
#define CR08 0x08
#define CR09 0x09
#define CR0A 0x0A
#define CR0B 0x0B
#define CR0C 0x0C
#define CR0D 0x0D
#define CR0E 0x0E
#define CR0F 0x0F
#define CR10 0x10
#define CR11 0x11
#define CR12 0x12
#define CR13 0x13
#define CR14 0x14
#define CR15 0x15
#define CR16 0x16
#define CR17 0x17
#define CR18 0x18
#endif
/* __I810_REGS_H__ */
drivers/video/offb.c
View file @
0e2e212c
...
...
@@ -393,6 +393,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
struct
fb_fix_screeninfo
*
fix
;
struct
fb_var_screeninfo
*
var
;
struct
fb_info
*
info
;
int
size
;
if
(
!
request_mem_region
(
res_start
,
res_size
,
"offb"
))
return
;
...
...
@@ -421,7 +422,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
var
=
&
info
->
var
;
strcpy
(
fix
->
id
,
"OFfb "
);
strncat
(
fix
->
id
,
name
,
sizeof
(
fix
->
id
));
strncat
(
fix
->
id
,
name
,
sizeof
(
fix
->
id
)
-
sizeof
(
"OFfb "
)
);
fix
->
id
[
sizeof
(
fix
->
id
)
-
1
]
=
'\0'
;
var
->
xres
=
var
->
xres_virtual
=
width
;
...
...
@@ -522,8 +523,6 @@ static void __init offb_init_fb(const char *name, const char *full_name,
var
->
sync
=
0
;
var
->
vmode
=
FB_VMODE_NONINTERLACED
;
strcpy
(
fix
->
id
,
"OFfb "
);
strncat
(
fix
->
id
,
full_name
,
sizeof
(
fix
->
id
));
info
->
node
=
NODEV
;
info
->
fbops
=
&
offb_ops
;
info
->
screen_base
=
ioremap
(
address
,
fix
->
smem_len
);
...
...
drivers/video/riva/fbdev.c.new
0 → 100644
View file @
0e2e212c
/*
* linux/drivers/video/riva/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver
*
* Maintained by Ani Joshi <ajoshi@shell.unixbox.com>
*
* Copyright 1999-2000 Jeff Garzik
*
* Contributors:
*
* Ani Joshi: Lots of debugging and cleanup work, really helped
* get the driver going
*
* Ferenc Bakonyi: Bug fixes, cleanup, modularization
*
* Jindrich Makovicka: Accel code help, hw cursor, mtrr
*
* Paul Richards: Bug fixes and updates.
*
* Initial template from skeletonfb.c, created 28 Dec 1997 by Geert Uytterhoeven
* Includes riva_hw.c from nVidia, see copyright below.
* KGI code provided the basis for state storage, init, and mode switching.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*
* Known bugs and issues:
* restoring text mode fails
* doublescan modes are broken
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/pci.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
#include "rivafb.h"
#include "nvreg.h"
#ifndef CONFIG_PCI /* sanity check */
#error This driver requires PCI support.
#endif
/* version number of this driver */
#define RIVAFB_VERSION "0.9.4"
/* ------------------------------------------------------------------------- *
*
* various helpful macros and constants
*
* ------------------------------------------------------------------------- */
#undef RIVAFBDEBUG
#ifdef RIVAFBDEBUG
#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#else
#define DPRINTK(fmt, args...)
#endif
#ifndef RIVA_NDEBUG
#define assert(expr) \
if(!(expr)) { \
printk( "Assertion failed! %s,%s,%s,line=%d\n",\
#expr,__FILE__,__FUNCTION__,__LINE__); \
BUG(); \
}
#else
#define assert(expr)
#endif
#define PFX "rivafb: "
/* macro that allows you to set overflow bits */
#define SetBitField(value,from,to) SetBF(to,GetBF(value,from))
#define SetBit(n) (1<<(n))
#define Set8Bits(value) ((value)&0xff)
/* HW cursor parameters */
#define MAX_CURS 32
/* ------------------------------------------------------------------------- *
*
* prototypes
*
* ------------------------------------------------------------------------- */
static int rivafb_blank(int blank, struct fb_info *info);
extern inline void wait_for_idle(struct riva_par *par);
/* ------------------------------------------------------------------------- *
*
* card identification
*
* ------------------------------------------------------------------------- */
enum riva_chips {
CH_RIVA_128 = 0,
CH_RIVA_TNT,
CH_RIVA_TNT2,
CH_RIVA_UTNT2,
CH_RIVA_VTNT2,
CH_RIVA_UVTNT2,
CH_RIVA_ITNT2,
CH_GEFORCE_SDR,
CH_GEFORCE_DDR,
CH_QUADRO,
CH_GEFORCE2_MX,
CH_GEFORCE2_MX2,
CH_GEFORCE2_GO,
CH_QUADRO2_MXR,
CH_GEFORCE2_GTS,
CH_GEFORCE2_GTS2,
CH_GEFORCE2_ULTRA,
CH_QUADRO2_PRO,
CH_GEFORCE4_MX_460,
CH_GEFORCE4_MX_440,
CH_GEFORCE4_MX_420,
CH_GEFORCE4_440_GO,
CH_GEFORCE4_420_GO,
CH_GEFORCE4_420_GO_M32,
CH_QUADRO4_500XGL,
CH_GEFORCE4_440_GO_M64,
CH_QUADRO4_200,
CH_QUADRO4_550XGL,
CH_QUADRO4_500_GOGL,
CH_IGEFORCE2,
CH_GEFORCE3,
CH_GEFORCE3_1,
CH_GEFORCE3_2,
CH_QUADRO_DDC,
CH_GEFORCE4_TI_4600,
CH_GEFORCE4_TI_4400,
CH_GEFORCE4_TI_4200,
CH_QUADRO4_900XGL,
CH_QUADRO4_750XGL,
CH_QUADRO4_700XGL
};
/* directly indexed by riva_chips enum, above */
static struct riva_chip_info {
const char *name;
unsigned arch_rev;
} riva_chip_info[] __devinitdata = {
{ "RIVA-128", NV_ARCH_03 },
{ "RIVA-TNT", NV_ARCH_04 },
{ "RIVA-TNT2", NV_ARCH_04 },
{ "RIVA-UTNT2", NV_ARCH_04 },
{ "RIVA-VTNT2", NV_ARCH_04 },
{ "RIVA-UVTNT2", NV_ARCH_04 },
{ "RIVA-ITNT2", NV_ARCH_04 },
{ "GeForce-SDR", NV_ARCH_10},
{ "GeForce-DDR", NV_ARCH_10},
{ "Quadro", NV_ARCH_10},
{ "GeForce2-MX", NV_ARCH_10},
{ "GeForce2-MX", NV_ARCH_10},
{ "GeForce2-GO", NV_ARCH_10},
{ "Quadro2-MXR", NV_ARCH_10},
{ "GeForce2-GTS", NV_ARCH_10},
{ "GeForce2-GTS", NV_ARCH_10},
{ "GeForce2-ULTRA", NV_ARCH_10},
{ "Quadro2-PRO", NV_ARCH_10},
{ "GeForce4-MX-460", NV_ARCH_20 },
{ "GeForce4-MX-440", NV_ARCH_20 },
{ "GeForce4-MX-420", NV_ARCH_20 },
{ "GeForce4-440-GO", NV_ARCH_20 },
{ "GeForce4-420-GO", NV_ARCH_20 },
{ "GeForce4-420-GO-M32", NV_ARCH_20 },
{ "Quadro4-500-XGL", NV_ARCH_20 },
{ "GeForce4-440-GO-M64", NV_ARCH_20 },
{ "Quadro4-200", NV_ARCH_20 },
{ "Quadro4-550-XGL", NV_ARCH_20 },
{ "Quadro4-500-GOGL", NV_ARCH_20 },
{ "GeForce2", NV_ARCH_20 },
{ "GeForce3", NV_ARCH_20 },
{ "GeForce3 Ti 200", NV_ARCH_20 },
{ "GeForce3 Ti 500", NV_ARCH_20 },
{ "Quadro DDC", NV_ARCH_20 },
{ "GeForce4 Ti 4600", NV_ARCH_20 },
{ "GeForce4 Ti 4400", NV_ARCH_20 },
{ "GeForce4 Ti 4200", NV_ARCH_20 },
{ "Quadro4-900-XGL", NV_ARCH_20 },
{ "Quadro4-750-XGL", NV_ARCH_20 },
{ "Quadro4-700-XGL", NV_ARCH_20 }
};
static struct pci_device_id rivafb_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_128 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_TNT },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_TNT2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_UTNT2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_VTNT2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_VTNT2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_ITNT2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE_SDR },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE_DDR },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_MX },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_MX2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GO },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_MXR },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_ULTRA },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_PRO },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_MX_460 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_MX_440 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_MX_420 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_440_GO },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_420_GO },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_420_GO_M32 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_500XGL },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_440_GO_M64 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_200 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_550XGL },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_500_GOGL },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_IGEFORCE2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_1 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO_DDC },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4600 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4400 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4200 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_900XGL },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_750XGL },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_700XGL },
{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl);
/* ------------------------------------------------------------------------- *
*
* global variables
*
* ------------------------------------------------------------------------- */
/* command line data, set in rivafb_setup() */
static u32 pseudo_palette[17];
#ifdef CONFIG_MTRR
static char nomtrr __initdata = 0;
#endif
#ifndef MODULE
static char *mode_option __initdata = NULL;
#endif
static struct fb_fix_screeninfo rivafb_fix = {
id: "nVidia",
type: FB_TYPE_PACKED_PIXELS,
xpanstep: 1,
ypanstep: 1,
};
static struct fb_var_screeninfo rivafb_default_var = {
xres: 640,
yres: 480,
xres_virtual: 640,
yres_virtual: 480,
xoffset: 0,
yoffset: 0,
bits_per_pixel: 8,
grayscale: 0,
red: {0, 6, 0},
green: {0, 6, 0},
blue: {0, 6, 0},
transp: {0, 0, 0},
nonstd: 0,
activate: 0,
height: -1,
width: -1,
accel_flags: FB_ACCELF_TEXT,
pixclock: 39721,
left_margin: 40,
right_margin: 24,
upper_margin: 32,
lower_margin: 11,
hsync_len: 96,
vsync_len: 2,
sync: 0,
vmode: FB_VMODE_NONINTERLACED
};
/* from GGI */
static const struct riva_regs reg_template = {
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ATTR */
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x41, 0x01, 0x0F, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* CRT */
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, /* 0x10 */
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, /* 0x40 */
},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, /* GRA */
0xFF},
{0x03, 0x01, 0x0F, 0x00, 0x0E}, /* SEQ */
0xEB /* MISC */
};
/* ------------------------------------------------------------------------- *
*
* MMIO access macros
*
* ------------------------------------------------------------------------- */
static inline void CRTCout(struct riva_par *par, unsigned char index,
unsigned char val)
{
VGA_WR08(par->riva.PCIO, 0x3d4, index);
VGA_WR08(par->riva.PCIO, 0x3d5, val);
}
static inline unsigned char CRTCin(struct riva_par *par,
unsigned char index)
{
VGA_WR08(par->riva.PCIO, 0x3d4, index);
return (VGA_RD08(par->riva.PCIO, 0x3d5));
}
static inline void GRAout(struct riva_par *par, unsigned char index,
unsigned char val)
{
VGA_WR08(par->riva.PVIO, 0x3ce, index);
VGA_WR08(par->riva.PVIO, 0x3cf, val);
}
static inline unsigned char GRAin(struct riva_par *par,
unsigned char index)
{
VGA_WR08(par->riva.PVIO, 0x3ce, index);
return (VGA_RD08(par->riva.PVIO, 0x3cf));
}
static inline void SEQout(struct riva_par *par, unsigned char index,
unsigned char val)
{
VGA_WR08(par->riva.PVIO, 0x3c4, index);
VGA_WR08(par->riva.PVIO, 0x3c5, val);
}
static inline unsigned char SEQin(struct riva_par *par,
unsigned char index)
{
VGA_WR08(par->riva.PVIO, 0x3c4, index);
return (VGA_RD08(par->riva.PVIO, 0x3c5));
}
static inline void ATTRout(struct riva_par *par, unsigned char index,
unsigned char val)
{
VGA_WR08(par->riva.PCIO, 0x3c0, index);
VGA_WR08(par->riva.PCIO, 0x3c0, val);
}
static inline unsigned char ATTRin(struct riva_par *par,
unsigned char index)
{
VGA_WR08(par->riva.PCIO, 0x3c0, index);
return (VGA_RD08(par->riva.PCIO, 0x3c1));
}
static inline void MISCout(struct riva_par *par, unsigned char val)
{
VGA_WR08(par->riva.PVIO, 0x3c2, val);
}
static inline unsigned char MISCin(struct riva_par *par)
{
return (VGA_RD08(par->riva.PVIO, 0x3cc));
}
/* ------------------------------------------------------------------------- *
*
* cursor stuff
*
* ------------------------------------------------------------------------- */
/**
* rivafb_load_cursor_image - load cursor image to hardware
* @data: address to monochrome bitmap (1 = foreground color, 0 = background)
* @mask: address to mask (1 = write image pixel, 0 = do not write pixel)
* @par: pointer to private data
* @w: width of cursor image in pixels
* @h: height of cursor image in scanlines
* @bg: background color (ARGB1555) - alpha bit determines opacity
* @fg: foreground color (ARGB1555)
*
* DESCRIPTiON:
* Loads cursor image based on a monochrome source and mask bitmap. The
* mask bit determines if the image pixel is to be written to the framebuffer
* or not. The imaage bits determines the color of the pixel, 0 for
* background, 1 for foreground. Only the affected region (as determined
* by @w and @h parameters) will be updated.
*
* CALLED FROM:
* rivafb_cursor()
*/
static void rivafb_load_cursor_image(u8 *data, u8 *mask, struct riva_par *par,
int w, int h, u16 bg, u16 fg)
{
int i, j, k = 0;
u32 b, m, tmp;
for (i = 0; i < h; i++) {
b = *((u32 *)data)++;
m = *((u32 *)mask)++;
for (j = 0; j < w/2; j++) {
tmp = 0;
#if defined (__BIG_ENDIAN__)
if (m & (1 << 31))
tmp = (b & (1 << 31)) ? fg << 16 : bg << 16;
b <<= 1;
m <<= 1;
if (m & (1 << 31))
tmp |= (b & (1 << 31)) ? fg : bg;
b <<= 1;
m <<= 1;
#else
if (m & 1)
tmp = (b & 1) ? fg : bg;
b >>= 1;
m >>= 1;
if (m & 1)
tmp |= (b & 1) ? fg << 16 : bg << 16;
b >>= 1;
m >>= 1;
#endif
writel(tmp, par->riva.CURSOR + k++);
}
k += (MAX_CURS - w)/2;
}
}
/* ------------------------------------------------------------------------- *
*
* general utility functions
*
* ------------------------------------------------------------------------- */
/**
* riva_wclut - set CLUT entry
* @chip: pointer to RIVA_HW_INST object
* @regnum: register number
* @red: red component
* @green: green component
* @blue: blue component
*
* DESCRIPTION:
* Sets color register @regnum.
*
* CALLED FROM:
* rivafb_setcolreg()
*/
static void riva_wclut(RIVA_HW_INST *chip,
unsigned char regnum, unsigned char red,
unsigned char green, unsigned char blue)
{
VGA_WR08(chip->PDIO, 0x3c8, regnum);
VGA_WR08(chip->PDIO, 0x3c9, red);
VGA_WR08(chip->PDIO, 0x3c9, green);
VGA_WR08(chip->PDIO, 0x3c9, blue);
}
/**
* riva_save_state - saves current chip state
* @par: pointer to riva_par object containing info for current riva board
* @regs: pointer to riva_regs object
*
* DESCRIPTION:
* Saves current chip state to @regs.
*
* CALLED FROM:
* rivafb_init_one()
*/
/* from GGI */
static void riva_save_state(struct riva_par *par, struct riva_regs *regs)
{
int i;
par->riva.LockUnlock(&par->riva, 0);
par->riva.UnloadStateExt(&par->riva, ®s->ext);
regs->misc_output = MISCin(par);
for (i = 0; i < NUM_CRT_REGS; i++) {
regs->crtc[i] = CRTCin(par, i);
}
for (i = 0; i < NUM_ATC_REGS; i++) {
regs->attr[i] = ATTRin(par, i);
}
for (i = 0; i < NUM_GRC_REGS; i++) {
regs->gra[i] = GRAin(par, i);
}
for (i = 0; i < NUM_SEQ_REGS; i++) {
regs->seq[i] = SEQin(par, i);
}
}
/**
* riva_load_state - loads current chip state
* @par: pointer to riva_par object containing info for current riva board
* @regs: pointer to riva_regs object
*
* DESCRIPTION:
* Loads chip state from @regs.
*
* CALLED FROM:
* riva_load_video_mode()
* rivafb_init_one()
* rivafb_remove_one()
*/
/* from GGI */
static void riva_load_state(struct riva_par *par, struct riva_regs *regs)
{
RIVA_HW_STATE *state = ®s->ext;
int i;
CRTCout(par, 0x11, 0x00);
par->riva.LockUnlock(&par->riva, 0);
par->riva.LoadStateExt(&par->riva, state);
MISCout(par, regs->misc_output);
for (i = 0; i < NUM_CRT_REGS; i++) {
switch (i) {
case 0x19:
case 0x20 ... 0x40:
break;
default:
CRTCout(par, i, regs->crtc[i]);
}
}
for (i = 0; i < NUM_ATC_REGS; i++) {
ATTRout(par, i, regs->attr[i]);
}
for (i = 0; i < NUM_GRC_REGS; i++) {
GRAout(par, i, regs->gra[i]);
}
for (i = 0; i < NUM_SEQ_REGS; i++) {
SEQout(par, i, regs->seq[i]);
}
}
/**
* riva_load_video_mode - calculate timings
* @info: pointer to fb_info object containing info for current riva board
* @video_mode: video mode to set
*
* DESCRIPTION:
* Calculate some timings and then send em off to riva_load_state().
*
* CALLED FROM:
* rivafb_set_var()
*/
static void riva_load_video_mode(struct fb_info *info)
{
int bpp, width, hDisplaySize, hDisplay, hStart,
hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock;
int hBlankStart, hBlankEnd, vBlankStart, vBlankEnd;
struct riva_par *par = (struct riva_par *) info->par;
struct riva_regs newmode;
/* time to calculate */
rivafb_blank(1, info);
bpp = info->var.bits_per_pixel;
if (bpp == 16 && info->var.green.length == 5)
bpp = 15;
width = info->var.xres_virtual;
hDisplaySize = info->var.xres;
hDisplay = (hDisplaySize / 8) - 1;
hStart = (hDisplaySize + info->var.right_margin) / 8 + 2;
hEnd = (hDisplaySize + info->var.right_margin +
info->var.hsync_len) / 8 - 1;
hTotal = (hDisplaySize + info->var.right_margin +
info->var.hsync_len + info->var.left_margin) / 8 - 5;
hBlankStart = hDisplay;
hBlankEnd = hTotal + 4;
height = info->var.yres_virtual;
vDisplay = info->var.yres - 1;
vStart = info->var.yres + info->var.lower_margin - 1;
vEnd = info->var.yres + info->var.lower_margin +
info->var.vsync_len - 1;
vTotal = info->var.yres + info->var.lower_margin +
info->var.vsync_len + info->var.upper_margin + 2;
vBlankStart = vDisplay;
vBlankEnd = vTotal + 1;
dotClock = PICOS2KHZ(info->var.pixclock);
memcpy(&newmode, ®_template, sizeof(struct riva_regs));
newmode.crtc[0x0] = Set8Bits (hTotal - 4);
if (par->FlatPanel) {
vStart = vTotal - 3;
vEnd = vTotal - 2;
vBlankStart = vStart;
hStart = hTotal - 3;
hEnd = hTotal - 2;
hBlankEnd = hTotal + 4;
}
newmode.crtc[0x0] = Set8Bits (hTotal);
newmode.crtc[0x1] = Set8Bits (hDisplay);
newmode.crtc[0x2] = Set8Bits (hBlankStart);
newmode.crtc[0x3] = SetBitField (hBlankEnd, 4: 0, 4:0) | SetBit (7);
newmode.crtc[0x4] = Set8Bits (hStart);
newmode.crtc[0x5] = SetBitField (hBlankEnd, 5: 5, 7:7)
| SetBitField (hEnd, 4: 0, 4:0);
newmode.crtc[0x6] = SetBitField (vTotal, 7: 0, 7:0);
newmode.crtc[0x7] = SetBitField (vTotal, 8: 8, 0:0)
| SetBitField (vDisplay, 8: 8, 1:1)
| SetBitField (vStart, 8: 8, 2:2)
| SetBitField (vBlankStart, 8: 8, 3:3)
| SetBit (4)
| SetBitField (vTotal, 9: 9, 5:5)
| SetBitField (vDisplay, 9: 9, 6:6)
| SetBitField (vStart, 9: 9, 7:7);
newmode.crtc[0x9] = SetBitField (vBlankStart, 9: 9, 5:5)
| SetBit (6);
newmode.crtc[0x10] = Set8Bits (vStart);
newmode.crtc[0x11] = SetBitField (vEnd, 3: 0, 3:0)
| SetBit (5);
newmode.crtc[0x12] = Set8Bits (vDisplay);
newmode.crtc[0x13] = (width / 8) * ((bpp + 1) / 8);
newmode.crtc[0x15] = Set8Bits (vBlankStart);
newmode.crtc[0x16] = Set8Bits (vBlankEnd + 1);
newmode.ext.screen = SetBitField(hBlankEnd,6:6,4:4)
| SetBitField(vBlankStart,10:10,3:3)
| SetBitField(vStart,10:10,2:2)
| SetBitField(vDisplay,10:10,1:1)
| SetBitField(vTotal,10:10,0:0);
newmode.ext.horiz = SetBitField(hTotal,8:8,0:0)
| SetBitField(hDisplay,8:8,1:1)
| SetBitField(hBlankStart,8:8,2:2)
| SetBitField(hStart,8:8,3:3);
newmode.ext.extra = SetBitField(vTotal,11:11,0:0)
| SetBitField(vDisplay,11:11,2:2)
| SetBitField(vStart,11:11,4:4)
| SetBitField(vBlankStart,11:11,6:6);
newmode.ext.interlace = 0xff; /* interlace off */
if(par->riva.Architecture >= NV_ARCH_10)
par->riva.CURSOR = (U032 *)(info->screen_base + par->riva.CursorStart);
par->riva.CalcStateExt(&par->riva, &newmode.ext, bpp, width,
hDisplaySize, height, dotClock);
newmode.ext.scale = par->riva.PRAMDAC[0x00000848/4] & 0xfff000ff;
if(par->FlatPanel == 1) {
newmode.ext.pixel |= (1 << 7);
newmode.ext.scale |= (1 << 8) ;
}
if(par->SecondCRTC) {
newmode.ext.head = par->riva.PCRTC0[0x00000860/4] & ~0x00001000;
newmode.ext.head2 = par->riva.PCRTC0[0x00002860/4] | 0x00001000;
newmode.ext.crtcOwner = 3;
newmode.ext.pllsel |= 0x20000800;
newmode.ext.vpll2 = newmode.ext.vpll;
} else if(par->riva.twoHeads) {
newmode.ext.head = par->riva.PCRTC0[0x00000860/4] | 0x00001000;
newmode.ext.head2 = par->riva.PCRTC0[0x00002860/4] & ~0x00001000;
newmode.ext.crtcOwner = 0;
newmode.ext.vpll2 = par->riva.PRAMDAC0[0x00000520/4];
}
newmode.ext.cursorConfig = 0x02000100;
par->current_state = newmode;
riva_load_state(par, &par->current_state);
rivafb_blank(0, info);
}
/**
* rivafb_do_maximize -
* @info: pointer to fb_info object containing info for current riva board
* @var:
* @nom:
* @den:
*
* DESCRIPTION:
* .
*
* RETURNS:
* -EINVAL on failure, 0 on success
*
*
* CALLED FROM:
* rivafb_set_var()
*/
static int rivafb_do_maximize(struct fb_info *info,
struct fb_var_screeninfo *var,
int nom, int den)
{
static struct {
int xres, yres;
} modes[] = {
{1600, 1280},
{1280, 1024},
{1024, 768},
{800, 600},
{640, 480},
{-1, -1}
};
int i;
/* use highest possible virtual resolution */
if (var->xres_virtual == -1 && var->yres_virtual == -1) {
printk(KERN_WARNING PFX
"using maximum available virtual resolution\n");
for (i = 0; modes[i].xres != -1; i++) {
if (modes[i].xres * nom / den * modes[i].yres <
info->fix.smem_len / 2)
break;
}
if (modes[i].xres == -1) {
printk(KERN_ERR PFX
"could not find a virtual resolution that fits into video memory!!\n");
DPRINTK("EXIT - EINVAL error\n");
return -EINVAL;
}
var->xres_virtual = modes[i].xres;
var->yres_virtual = modes[i].yres;
printk(KERN_INFO PFX
"virtual resolution set to maximum of %dx%d\n",
var->xres_virtual, var->yres_virtual);
} else if (var->xres_virtual == -1) {
var->xres_virtual = (info->fix.smem_len * den /
(nom * var->yres_virtual * 2)) & ~15;
printk(KERN_WARNING PFX
"setting virtual X resolution to %d\n", var->xres_virtual);
} else if (var->yres_virtual == -1) {
var->xres_virtual = (var->xres_virtual + 15) & ~15;
var->yres_virtual = info->fix.smem_len * den /
(nom * var->xres_virtual * 2);
printk(KERN_WARNING PFX
"setting virtual Y resolution to %d\n", var->yres_virtual);
} else {
var->xres_virtual = (var->xres_virtual + 15) & ~15;
if (var->xres_virtual * nom / den * var->yres_virtual > info->fix.smem_len) {
printk(KERN_ERR PFX
"mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
var->xres, var->yres, var->bits_per_pixel);
DPRINTK("EXIT - EINVAL error\n");
return -EINVAL;
}
}
if (var->xres_virtual * nom / den >= 8192) {
printk(KERN_WARNING PFX
"virtual X resolution (%d) is too high, lowering to %d\n",
var->xres_virtual, 8192 * den / nom - 16);
var->xres_virtual = 8192 * den / nom - 16;
}
if (var->xres_virtual < var->xres) {
printk(KERN_ERR PFX
"virtual X resolution (%d) is smaller than real\n", var->xres_virtual);
return -EINVAL;
}
if (var->yres_virtual < var->yres) {
printk(KERN_ERR PFX
"virtual Y resolution (%d) is smaller than real\n", var->yres_virtual);
return -EINVAL;
}
return 0;
}
/* acceleration routines */
inline void wait_for_idle(struct riva_par *par)
{
while (par->riva.Busy(&par->riva));
}
/* set copy ROP, no mask */
static void riva_setup_ROP(struct riva_par *par)
{
RIVA_FIFO_FREE(par->riva, Patt, 5);
par->riva.Patt->Shape = 0;
par->riva.Patt->Color0 = 0xffffffff;
par->riva.Patt->Color1 = 0xffffffff;
par->riva.Patt->Monochrome[0] = 0xffffffff;
par->riva.Patt->Monochrome[1] = 0xffffffff;
RIVA_FIFO_FREE(par->riva, Rop, 1);
par->riva.Rop->Rop3 = 0xCC;
}
void riva_setup_accel(struct riva_par *par)
{
RIVA_FIFO_FREE(par->riva, Clip, 2);
par->riva.Clip->TopLeft = 0x0;
par->riva.Clip->WidthHeight = 0x80008000;
riva_setup_ROP(par);
}
/**
* rivafb_fillrect - hardware accelerated color fill function
* @info: pointer to fb_info structure
* @rect: pointer to fb_fillrect structure
*
* DESCRIPTION:
* This function fills up a region of framebuffer memory with a solid
* color with a choice of two different ROP's, copy or invert.
*
* CALLED FROM:
* framebuffer hook
*/
static void rivafb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
{
struct riva_par *par = (struct riva_par *) info->par;
u_int color, rop = 0;
if (info->var.bits_per_pixel == 8)
color = rect->color;
else
color = par->riva_palette[rect->color];
switch (rect->rop) {
case ROP_XOR:
rop = 0x66;
break;
case ROP_COPY:
default:
rop = 0xCC;
break;
}
RIVA_FIFO_FREE(par->riva, Rop, 1);
par->riva.Rop->Rop3 = rop;
RIVA_FIFO_FREE(par->riva, Bitmap, 1);
par->riva.Bitmap->Color1A = color;
RIVA_FIFO_FREE(par->riva, Bitmap, 2);
par->riva.Bitmap->UnclippedRectangle[0].TopLeft =
(rect->dx << 16) | rect->dy;
par->riva.Bitmap->UnclippedRectangle[0].WidthHeight =
(rect->width << 16) | rect->height;
}
/**
* rivafb_copyarea - hardware accelerated blit function
* @info: pointer to fb_info structure
* @region: pointer to fb_copyarea structure
*
* DESCRIPTION:
* This copies an area of pixels from one location to another
*
* CALLED FROM:
* framebuffer hook
*/
static void rivafb_copyarea(struct fb_info *info, struct fb_copyarea *region)
{
struct riva_par *par = (struct riva_par *) info->par;
RIVA_FIFO_FREE(par->riva, Blt, 3);
par->riva.Blt->TopLeftSrc = (region->sy << 16) | region->sx;
par->riva.Blt->TopLeftDst = (region->dy << 16) | region->dx;
par->riva.Blt->WidthHeight = (region->height << 16) | region->width;
wait_for_idle(par);
}
static u8 byte_rev[256] = {
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
};
/**
* rivafb_imageblit: hardware accelerated color expand function
* @info: pointer to fb_info structure
* @image: pointer to fb_image structure
*
* DESCRIPTION:
* If the source is a monochrome bitmap, the function fills up a a region
* of framebuffer memory with pixels whose color is determined by the bit
* setting of the bitmap, 1 - foreground, 0 - background.
*
* If the source is not a monochrome bitmap, color expansion is not done.
* In this case, it is channeled to a software function.
*
* CALLED FROM:
* framebuffer hook
*/
static void rivafb_imageblit(struct fb_info *info, struct fb_image *image)
{
struct riva_par *par = (struct riva_par *) info->par;
u8 *cdat = image->data, *dat;
int w, h, dx, dy;
volatile u32 *d;
u32 fgx = 0, bgx = 0, size, width, mod;
int i, j;
if (image->depth != 1) {
wait_for_idle(par);
cfb_imageblit(info, image);
return;
}
w = image->width;
h = image->height;
dx = image->dx;
dy = image->dy;
width = (w + 7)/8;
size = width * h;
dat = cdat;
for (i = 0; i < size; i++) {
*dat = byte_rev[*dat];
dat++;
}
switch (info->var.bits_per_pixel) {
case 8:
fgx = image->fg_color | ~((1 << 8) - 1);
bgx = image->bg_color | ~((1 << 8) - 1);
break;
case 16:
/* set alpha bit */
if (info->var.green.length == 5) {
fgx = 1 << 15;
bgx = fgx;
}
/* Fall through... */
case 32:
fgx |= par->riva_palette[image->fg_color];
bgx |= par->riva_palette[image->bg_color];
break;
}
RIVA_FIFO_FREE(par->riva, Bitmap, 7);
par->riva.Bitmap->ClipE.TopLeft = (dy << 16) | (dx & 0xFFFF);
par->riva.Bitmap->ClipE.BottomRight = (((dy + h) << 16) |
((dx + w) & 0xffff));
par->riva.Bitmap->Color0E = bgx;
par->riva.Bitmap->Color1E = fgx;
par->riva.Bitmap->WidthHeightInE = (h << 16) | ((w + 31) & ~31);
par->riva.Bitmap->WidthHeightOutE = (h << 16) | ((w + 31) & ~31);
par->riva.Bitmap->PointE = (dy << 16) | (dx & 0xFFFF);
d = &par->riva.Bitmap->MonochromeData01E;
mod = width % 4;
if (width >= 4) {
while (h--) {
size = width / 4;
while (size >= 16) {
RIVA_FIFO_FREE(par->riva, Bitmap, 16);
for (i = 0; i < 16; i++)
d[i] = *((u32 *)cdat)++;
size -= 16;
}
if (size) {
RIVA_FIFO_FREE(par->riva, Bitmap, size);
for (i = 0; i < size; i++)
d[i] = *((u32 *) cdat)++;
}
if (mod) {
u32 tmp;
RIVA_FIFO_FREE(par->riva, Bitmap, 1);
for (i = 0; i < mod; i++)
((u8 *)&tmp)[i] = *cdat++;
d[i] = tmp;
}
}
}
else {
u32 k, tmp;
for (i = h; i > 0; i-=16) {
if (i >= 16)
size = 16;
else
size = i;
RIVA_FIFO_FREE(par->riva, Bitmap, size);
for (j = 0; j < size; j++) {
for (k = 0; k < width; k++)
((u8 *)&tmp)[k] = *cdat++;
d[j] = tmp;
}
}
}
}
/**
* rivafb_cursor - hardware cursor function
* @info: pointer to info structure
* @cursor: pointer to fbcursor structure
*
* DESCRIPTION:
* A cursor function that supports displaying a cursor image via hardware.
* Within the kernel, copy and invert rops are supported. If exported
* to user space, only the copy rop will be supported.
*
* CALLED FROM
* framebuffer hook
*/
static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
static u8 data[MAX_CURS*MAX_CURS/8], mask[MAX_CURS*MAX_CURS/8];
struct riva_par *par = (struct riva_par *) info->par;
int i, j, d_idx = 0, s_idx = 0;
u16 flags = cursor->set, fg, bg;
/*
* Can't do invert if one of the operands (dest) is missing,
* ie, only opaque cursor supported. This should be
* standard for GUI apps.
*/
if (cursor->dest == NULL && cursor->rop == ROP_XOR)
return 1;
if (par->cursor_reset) {
flags = FB_CUR_SETALL;
par->cursor_reset = 0;
}
par->riva.ShowHideCursor(&par->riva, 0);
if (flags & FB_CUR_SETPOS) {
u32 xx, yy, temp;
yy = cursor->image.dy - info->var.yoffset;
xx = cursor->image.dx - info->var.xoffset;
temp = xx & 0xFFFF;
temp |= yy << 16;
par->riva.PRAMDAC[0x0000300/4] = temp;
}
if (flags & FB_CUR_SETSIZE) {
memset(data, 0, MAX_CURS * MAX_CURS/8);
memset(mask, 0, MAX_CURS * MAX_CURS/8);
memset_io(par->riva.CURSOR, 0, MAX_CURS * MAX_CURS * 2);
}
if (flags & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETDEST)) {
int bg_idx = cursor->image.bg_color;
int fg_idx = cursor->image.fg_color;
switch (cursor->rop) {
case ROP_XOR:
for (i = 0; i < cursor->image.height; i++) {
for (j = 0; j < (cursor->image.width + 7)/8;
j++) {
d_idx = i * MAX_CURS/8 + j;
data[d_idx] = byte_rev[((u8 *)cursor->image.data)[s_idx] ^
((u8 *)cursor->dest)[s_idx]];
mask[d_idx] = byte_rev[((u8 *)cursor->mask)[s_idx]];
s_idx++;
}
}
break;
case ROP_COPY:
default:
for (i = 0; i < cursor->image.height; i++) {
for (j = 0; j < (cursor->image.width + 7)/8; j++) {
d_idx = i * MAX_CURS/8 + j;
data[d_idx] = byte_rev[((u8 *)cursor->image.data)[s_idx]];
mask[d_idx] = byte_rev[((u8 *)cursor->mask)[s_idx]];
s_idx++;
}
}
break;
}
bg = ((par->cmap[bg_idx].red & 0xf8) << 7) |
((par->cmap[bg_idx].green & 0xf8) << 2) |
((par->cmap[bg_idx].blue & 0xf8) >> 3) | 1 << 15;
fg = ((par->cmap[fg_idx].red & 0xf8) << 7) |
((par->cmap[fg_idx].green & 0xf8) << 2) |
((par->cmap[fg_idx].blue & 0xf8) >> 3) | 1 << 15;
par->riva.LockUnlock(&par->riva, 0);
rivafb_load_cursor_image(data, mask, par, cursor->image.width,
cursor->image.height, bg, fg);
}
if (cursor->enable)
par->riva.ShowHideCursor(&par->riva, 1);
return 0;
}
static int rivafb_sync(struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
wait_for_idle(par);
return 0;
}
/* ------------------------------------------------------------------------- *
*
* internal fb_ops helper functions
*
* ------------------------------------------------------------------------- */
/**
* riva_get_cmap_len - query current color map length
* @var: standard kernel fb changeable data
*
* DESCRIPTION:
* Get current color map length.
*
* RETURNS:
* Length of color map
*
* CALLED FROM:
* riva_getcolreg()
* rivafb_setcolreg()
* rivafb_get_cmap()
* rivafb_set_cmap()
*/
static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
{
int rc = 16; /* reasonable default */
assert(var != NULL);
switch (var->green.length) {
case 5:
rc = 32; /* fix for 15 bpp depths on Riva 128 based cards */
break;
case 6:
rc = 64; /* directcolor... 16 entries SW palette */
break; /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
default:
rc = 256; /* pseudocolor... 256 entries HW palette */
break;
}
return rc;
}
/* ------------------------------------------------------------------------- *
*
* framebuffer operations
*
* ------------------------------------------------------------------------- */
static int rivafb_open(struct fb_info *info, int user)
{
struct riva_par *par = (struct riva_par *) info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt) {
memset(&par->state, 0, sizeof(struct vgastate));
par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONT0;
/* save the DAC for Riva128 */
if (par->riva.Architecture == NV_ARCH_03)
par->state.flags |= VGA_SAVE_CMAP;
save_vga(&par->state);
RivaGetConfig(&par->riva, par->Chipset);
riva_save_state(par, &par->initial_state);
}
atomic_inc(&par->ref_count);
return 0;
}
static int rivafb_release(struct fb_info *info, int user)
{
struct riva_par *par = (struct riva_par *) info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt)
return -EINVAL;
if (cnt == 1) {
riva_load_state(par, &par->initial_state);
par->riva.LockUnlock(&par->riva, 1);
restore_vga(&par->state);
}
atomic_dec(&par->ref_count);
return 0;
}
static int rivafb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
int nom, den; /* translating from pixels->bytes */
if (par->riva.Architecture == NV_ARCH_03 &&
var->bits_per_pixel == 16)
var->bits_per_pixel = 15;
switch (var->bits_per_pixel) {
case 1 ... 8:
var->bits_per_pixel = 8;
nom = 1;
den = 1;
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 0;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
break;
case 9 ... 15:
var->green.length = 5;
/* fall through */
case 16:
var->bits_per_pixel = 16;
nom = 2;
den = 1;
if (var->green.length == 5) {
/* 0rrrrrgg gggbbbbb */
var->red.offset = 10;
var->green.offset = 5;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 5;
var->blue.length = 5;
} else {
/* rrrrrggg gggbbbbb */
var->red.offset = 11;
var->green.offset = 5;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 6;
var->blue.length = 5;
}
break;
case 17 ... 32:
var->bits_per_pixel = 32;
nom = 4;
den = 1;
var->red.offset = 16;
var->green.offset = 8;
var->blue.offset = 0;
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
break;
default:
printk(KERN_ERR PFX
"mode %dx%dx%d rejected...color depth not supported.\n",
var->xres, var->yres, var->bits_per_pixel);
DPRINTK("EXIT, returning -EINVAL\n");
return -EINVAL;
}
if (rivafb_do_maximize(info, var, nom, den) < 0)
return -EINVAL;
if (var->xoffset < 0)
var->xoffset = 0;
if (var->yoffset < 0)
var->yoffset = 0;
/* truncate xoffset and yoffset to maximum if too high */
if (var->xoffset > var->xres_virtual - var->xres)
var->xoffset = var->xres_virtual - var->xres - 1;
if (var->yoffset > var->yres_virtual - var->yres)
var->yoffset = var->yres_virtual - var->yres - 1;
var->red.msb_right =
var->green.msb_right =
var->blue.msb_right =
var->transp.offset = var->transp.length = var->transp.msb_right = 0;
return 0;
}
static int rivafb_set_par(struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
riva_load_video_mode(info);
if (info->var.accel_flags) {
riva_setup_accel(par);
info->fbops->fb_fillrect = rivafb_fillrect;
info->fbops->fb_copyarea = rivafb_copyarea;
info->fbops->fb_imageblit = rivafb_imageblit;
info->fbops->fb_cursor = rivafb_cursor;
info->fbops->fb_sync = rivafb_sync;
}
else {
info->fbops->fb_fillrect = cfb_fillrect;
info->fbops->fb_copyarea = cfb_copyarea;
info->fbops->fb_imageblit = cfb_imageblit;
info->fbops->fb_cursor = soft_cursor;
info->fbops->fb_sync = NULL;
}
info->fix.line_length = (info->var.xres_virtual * (info->var.bits_per_pixel >> 3));
info->fix.visual = (info->var.bits_per_pixel == 8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
return 0;
}
/**
* rivafb_pan_display
* @var: standard kernel fb changeable data
* @con: TODO
* @info: pointer to rivafb_info object containing info for current riva board
*
* DESCRIPTION:
* Pan (or wrap, depending on the `vmode' field) the display using the
* `xoffset' and `yoffset' fields of the `var' structure.
* If the values don't fit, return -EINVAL.
*
* This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
*/
static int rivafb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
unsigned int base;
if (var->xoffset > (var->xres_virtual - var->xres))
return -EINVAL;
if (var->yoffset > (var->yres_virtual - var->yres))
return -EINVAL;
if (var->vmode & FB_VMODE_YWRAP) {
if (var->yoffset < 0
|| var->yoffset >= info->var.yres_virtual
|| var->xoffset) return -EINVAL;
} else {
if (var->xoffset + info->var.xres > info->var.xres_virtual ||
var->yoffset + info->var.yres > info->var.yres_virtual)
return -EINVAL;
}
base = var->yoffset * info->fix.line_length + var->xoffset;
par->riva.SetStartAddress(&par->riva, base);
info->var.xoffset = var->xoffset;
info->var.yoffset = var->yoffset;
if (var->vmode & FB_VMODE_YWRAP)
info->var.vmode |= FB_VMODE_YWRAP;
else
info->var.vmode &= ~FB_VMODE_YWRAP;
/*
* HACK: The hardware cursor occasionally disappears during fast scrolling.
* We just reset the cursor each time we change the start address.
* This also has a beneficial side effect of restoring the cursor
* image when switching from X.
*/
par->cursor_reset = 1;
DPRINTK("EXIT, returning 0\n");
return 0;
}
static int rivafb_blank(int blank, struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
unsigned char tmp, vesa;
tmp = SEQin(par, 0x01) & ~0x20; /* screen on/off */
vesa = CRTCin(par, 0x1a) & ~0xc0; /* sync on/off */
if (blank) {
tmp |= 0x20;
switch (blank - 1) {
case VESA_NO_BLANKING:
break;
case VESA_VSYNC_SUSPEND:
vesa |= 0x80;
break;
case VESA_HSYNC_SUSPEND:
vesa |= 0x40;
break;
case VESA_POWERDOWN:
vesa |= 0xc0;
break;
}
}
SEQout(par, 0x01, tmp);
CRTCout(par, 0x1a, vesa);
DPRINTK("EXIT\n");
return 0;
}
/**
* rivafb_setcolreg
* @regno: register index
* @red: red component
* @green: green component
* @blue: blue component
* @transp: transparency
* @info: pointer to rivafb_info object containing info for current riva board
*
* DESCRIPTION:
* Set a single color register. The values supplied have a 16 bit
* magnitude.
*
* RETURNS:
* Return != 0 for invalid regno.
*
* CALLED FROM:
* rivafb_set_cmap()
* fbcmap.c:fb_set_cmap()
* fbgen.c:fbgen_get_cmap()
* fbgen.c:do_install_cmap()
* fbgen.c:fbgen_set_var()
* fbgen.c:fbgen_switch()
* fbgen.c:fbgen_blank()
* fbgen.c:fbgen_blank()
*/
static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
RIVA_HW_INST *chip = &par->riva;
int i;
if (regno >= riva_get_cmap_len(&info->var))
return -EINVAL;
if (info->var.grayscale) {
/* gray = 0.30*R + 0.59*G + 0.11*B */
red = green = blue =
(red * 77 + green * 151 + blue * 28) >> 8;
}
if (!regno) {
for (i = 0; i < 256; i++) {
par->cmap[i].red = 0;
par->cmap[i].green = 0;
par->cmap[i].blue = 0;
}
}
par->cmap[regno].red = (u8) red;
par->cmap[regno].green = (u8) green;
par->cmap[regno].blue = (u8) blue;
if (info->var.green.length == 5) {
/* RGB555: all components have 32 entries, 8 indices apart */
for (i = 0; i < 8; i++)
riva_wclut(chip, (regno*8)+i, (u8) red, (u8) green, (u8) blue);
}
else if (info->var.green.length == 6) {
/*
* RGB 565: red and blue have 32 entries, 8 indices apart, while
* green has 64 entries, 4 indices apart
*/
if (regno < 32) {
for (i = 0; i < 8; i++) {
riva_wclut(chip, (regno*8)+i, (u8) red,
par->cmap[regno*2].green,
(u8) blue);
}
}
for (i = 0; i < 4; i++) {
riva_wclut(chip, (regno*4)+i, par->cmap[regno/2].red,
(u8) green, par->cmap[regno/2].blue);
}
}
else {
riva_wclut(chip, regno, (u8) red, (u8) green, (u8) blue);
}
if (regno < 16) {
switch (info->var.bits_per_pixel) {
case 16:
if (info->var.green.length == 5) {
/* 0rrrrrgg gggbbbbb */
((u32 *)(info->pseudo_palette))[regno] =
(regno << 10) | (regno << 5) | regno;
par->riva_palette[regno] =
((red & 0xf800) >> 1) |
((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
} else {
/* rrrrrggg gggbbbbb */
((u32 *)(info->pseudo_palette))[regno] =
(regno << 11) | (regno << 6) | regno;
par->riva_palette[regno] = ((red & 0xf800) >> 0) |
((green & 0xf800) >> 5) | ((blue & 0xf800) >> 11);
}
break;
case 32:
((u32 *)(info->pseudo_palette))[regno] =
(regno << 16) | (regno << 8) | regno;
par->riva_palette[regno] =
((red & 0xff00) << 8) |
((green & 0xff00)) | ((blue & 0xff00) >> 8);
break;
default:
/* do nothing */
break;
}
}
return 0;
}
/* ------------------------------------------------------------------------- *
*
* initialization helper functions
*
* ------------------------------------------------------------------------- */
/* kernel interface */
static struct fb_ops riva_fb_ops = {
.owner = THIS_MODULE,
.fb_open = rivafb_open,
.fb_release = rivafb_release,
.fb_check_var = rivafb_check_var,
.fb_set_par = rivafb_set_par,
.fb_setcolreg = rivafb_setcolreg,
.fb_pan_display=rivafb_pan_display,
.fb_blank = rivafb_blank,
.fb_fillrect = rivafb_fillrect,
.fb_copyarea = rivafb_copyarea,
.fb_imageblit = rivafb_imageblit,
.fb_cursor = rivafb_cursor,
.fb_sync = rivafb_sync,
};
static int __devinit riva_set_fbinfo(struct fb_info *info)
{
unsigned int cmap_len;
info->node = NODEV;
info->flags = FBINFO_FLAG_DEFAULT;
info->fbops = &riva_fb_ops;
info->var = rivafb_default_var;
info->fix = rivafb_fix;
/* FIXME: set monspecs to what??? */
info->display_fg = NULL;
info->pseudo_palette = pseudo_palette;
cmap_len = riva_get_cmap_len(&info->var);
fb_alloc_cmap(&info->cmap, cmap_len, 0);
#ifndef MODULE
if (mode_option)
fb_find_mode(&info->var, info, mode_option,
NULL, 0, NULL, 8);
#endif
info->fix.line_length = (info->var.xres_virtual * (info->var.bits_per_pixel >> 3));
info->fix.visual = (info->var.bits_per_pixel == 8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
return 0;
}
/* ------------------------------------------------------------------------- *
*
* PCI bus
*
* ------------------------------------------------------------------------- */
static void __devinit rivafb_get_mem_len(struct riva_par *par,
struct fb_fix_screeninfo *fix)
{
RIVA_HW_INST *chip = &par->riva;
switch (chip->Architecture) {
case NV_ARCH_03:
if (chip->PFB[0x00000000/4] & 0x00000020) {
if (((chip->PMC[0x00000000/4] & 0xF0) == 0x20)
&& ((chip->PMC[0x00000000/4] & 0x0F) >= 0x02)) {
/*
* SDRAM 128 ZX.
*/
switch (chip->PFB[0x00000000/4] & 0x03) {
case 2:
fix->smem_len = 1024 * 1024 * 4;
break;
case 1:
fix->smem_len = 1024 * 1024 * 2;
break;
default:
fix->smem_len = 1024 * 1024 * 8;
break;
}
}
else {
fix->smem_len = 1024 * 1024 * 8;
}
}
else {
/*
* SGRAM 128.
*/
switch (chip->PFB[0x00000000/4] & 0x00000003) {
case 0:
fix->smem_len = 1024 * 1024 * 8;
break;
case 2:
fix->smem_len = 1024 * 1024 * 4;
break;
default:
fix->smem_len = 1024 * 1024 * 2;
break;
}
}
break;
case NV_ARCH_04:
if (chip->PFB[0x00000000/4] & 0x00000100) {
fix->smem_len = (((chip->PFB[0x00000000/4] >> 12)
& 0x0F) * 1024 * 2 + 1024 * 2) * 1024;
}
else {
switch (chip->PFB[0x00000000/4] & 0x00000003) {
case 0:
fix->smem_len = 1024 * 1024 * 32;
break;
case 1:
fix->smem_len = 1024 * 1024 * 4;
break;
case 2:
fix->smem_len = 1024 * 1024 * 8;
break;
case 3:
default:
fix->smem_len = 1024 * 1024 * 16;
break;
}
}
break;
case NV_ARCH_10:
case NV_ARCH_20:
switch ((chip->PFB[0x0000020C/4] >> 20) & 0x000000FF) {
case 0x02:
fix->smem_len = 1024 * 1024 * 2;
break;
case 0x04:
fix->smem_len = 1024 * 1024 * 4;
break;
case 0x08:
fix->smem_len = 1024 * 1024 * 8;
break;
case 0x10:
fix->smem_len = 1024 * 1024 * 16;
break;
case 0x20:
fix->smem_len = 1024 * 1024 * 32;
break;
case 0x40:
fix->smem_len = 1024 * 1024 * 64;
break;
case 0x80:
fix->smem_len = 1024 * 1024 * 128;
break;
default:
fix->smem_len = 1024 * 1024 * 16;
break;
}
}
}
static int __devinit rivafb_init_one(struct pci_dev *pd,
const struct pci_device_id *ent)
{
struct riva_chip_info *rci = &riva_chip_info[ent->driver_data];
struct riva_par *default_par;
struct fb_info *info;
assert(pd != NULL);
assert(rci != NULL);
info = kmalloc(sizeof(struct fb_info), GFP_KERNEL);
if (!info)
goto err_out;
default_par = kmalloc(sizeof(struct riva_par), GFP_KERNEL);
if (!default_par)
goto err_out_kfree;
memset(info, 0, sizeof(struct fb_info));
memset(default_par, 0, sizeof(struct riva_par));
strcat(rivafb_fix.id, rci->name);
default_par->riva.Architecture = rci->arch_rev;
default_par->Chipset = pd->device;
printk(KERN_INFO PFX "nVidia device/chipset %X\n",default_par->Chipset);
/*default_par->FlatPanel = flatpanel;
if (flatpanel == 1)
printk(KERN_INFO PFX "flatpanel support enabled\n");
default_par->forceCRTC = forceCRTC;
*/
rivafb_fix.mmio_len = pci_resource_len(pd, 0);
rivafb_fix.smem_len = pci_resource_len(pd, 1);
rivafb_fix.mmio_start = pci_resource_start(pd, 0);
rivafb_fix.smem_start = pci_resource_start(pd, 1);
if (!request_mem_region(rivafb_fix.mmio_start,
rivafb_fix.mmio_len, "rivafb")) {
printk(KERN_ERR PFX "cannot reserve MMIO region\n");
goto err_out_kfree;
}
default_par->ctrl_base = ioremap(rivafb_fix.mmio_start,
rivafb_fix.mmio_len);
if (!default_par->ctrl_base) {
printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
goto err_out_free_base0;
}
info->screen_base = ioremap(rivafb_fix.smem_start,
rivafb_fix.smem_len);
if (!info->screen_base) {
printk(KERN_ERR PFX "cannot ioremap FB base\n");
goto err_out_iounmap_ctrl;
}
default_par->riva.EnableIRQ = 0;
default_par->riva.PRAMDAC = (unsigned *)(default_par->ctrl_base +
0x00680000);
default_par->riva.PFB = (unsigned *)(default_par->ctrl_base +
0x00100000);
default_par->riva.PFIFO = (unsigned *)(default_par->ctrl_base +
0x00002000);
default_par->riva.PGRAPH = (unsigned *)(default_par->ctrl_base +
0x00400000);
default_par->riva.PEXTDEV = (unsigned *)(default_par->ctrl_base +
0x00101000);
default_par->riva.PTIMER = (unsigned *)(default_par->ctrl_base +
0x00009000);
default_par->riva.PMC = (unsigned *)(default_par->ctrl_base +
0x00000000);
default_par->riva.FIFO = (unsigned *)(default_par->ctrl_base +
0x00800000);
default_par->riva.PCIO = (U008 *)(default_par->ctrl_base + 0x00601000);
default_par->riva.PDIO = (U008 *)(default_par->ctrl_base + 0x00681000);
default_par->riva.PVIO = (U008 *)(default_par->ctrl_base + 0x000C0000);
default_par->riva.IO = (MISCin(default_par) & 0x01) ? 0x3D0 : 0x3B0;
switch (default_par->riva.Architecture) {
case NV_ARCH_03:
default_par->riva.PRAMIN = (unsigned *)(info->screen_base +
0x00C00000);
default_par->dclk_max = 256000000;
rivafb_fix.accel = FB_ACCEL_NV3;
break;
case NV_ARCH_04:
case NV_ARCH_10:
case NV_ARCH_20:
default_par->riva.PCRTC = (unsigned *)(default_par->ctrl_base
+ 0x00600000);
default_par->riva.PRAMIN = (unsigned *)(default_par->ctrl_base
+ 0x00710000);
default_par->dclk_max = 250000000;
rivafb_fix.accel = FB_ACCEL_NV4;
break;
}
rivafb_get_mem_len(default_par, &rivafb_fix);
info->par = default_par;
if (!request_mem_region(rivafb_fix.smem_start,
rivafb_fix.smem_len, "rivafb")) {
printk(KERN_ERR PFX "cannot reserve FB region\n");
goto err_out_free_base0;
}
info->screen_base = ioremap(rivafb_fix.smem_start,
rivafb_fix.smem_len);
if (!info->screen_base) {
printk(KERN_ERR PFX "cannot ioremap FB base\n");
goto err_out_iounmap_ctrl;
}
#ifdef CONFIG_MTRR
if (!nomtrr) {
default_par->mtrr.vram = mtrr_add(rivafb_fix.smem_start,
rivafb_fix.smem_len,
MTRR_TYPE_WRCOMB, 1);
if (default_par->mtrr.vram < 0) {
printk(KERN_ERR PFX "unable to setup MTRR\n");
} else {
default_par->mtrr.vram_valid = 1;
/* let there be speed */
printk(KERN_INFO PFX "RIVA MTRR set to ON\n");
}
}
#endif /* CONFIG_MTRR */
if (riva_set_fbinfo(info) < 0) {
printk(KERN_ERR PFX "error setting initial video mode\n");
goto err_out_cursor;
}
if (register_framebuffer(info) < 0) {
printk(KERN_ERR PFX
"error registering riva framebuffer\n");
goto err_out_load_state;
}
pci_set_drvdata(pd,info);
printk(KERN_INFO PFX
"PCI nVidia NV%x framebuffer ver %s (%s, %dMB @ 0x%lX)\n",
default_par->riva.Architecture,
RIVAFB_VERSION,
info->fix.id,
info->fix.smem_len / (1024 * 1024),
info->fix.smem_start);
return 0;
err_out_load_state:
err_out_cursor:
/* err_out_iounmap_fb: */
iounmap(info->screen_base);
err_out_iounmap_ctrl:
iounmap(default_par->ctrl_base);
err_out_free_base1:
release_mem_region(info->fix.smem_start, info->fix.smem_len);
err_out_free_base0:
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
err_out_kfree:
kfree(info);
err_out:
return -ENODEV;
}
static void __devexit rivafb_remove_one(struct pci_dev *pd)
{
struct fb_info *info = pci_get_drvdata(pd);
struct riva_par *par = (struct riva_par *) info->par;
if (!info)
return;
unregister_framebuffer(info);
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
mtrr_del(par->mtrr.vram, info->fix.smem_start,
info->fix.smem_len);
#endif /* CONFIG_MTRR */
iounmap(par->ctrl_base);
iounmap(info->screen_base);
release_mem_region(info->fix.mmio_start,
info->fix.mmio_len);
release_mem_region(info->fix.smem_start,
info->fix.smem_len);
kfree(info);
pci_set_drvdata(pd, NULL);
}
/* ------------------------------------------------------------------------- *
*
* initialization
*
* ------------------------------------------------------------------------- */
#ifndef MODULE
int __init rivafb_setup(char *options)
{
char *this_opt;
if (!options || !*options)
return 0;
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt)
continue;
#ifdef CONFIG_MTRR
if (!strncmp(this_opt, "nomtrr", 6)) {
nomtrr = 1;
} else
#endif
mode_option = this_opt;
}
return 0;
}
#endif /* !MODULE */
static struct pci_driver rivafb_driver = {
name: "rivafb",
id_table: rivafb_pci_tbl,
probe: rivafb_init_one,
remove: __devexit_p(rivafb_remove_one),
};
/* ------------------------------------------------------------------------- *
*
* modularization
*
* ------------------------------------------------------------------------- */
int __init rivafb_init(void)
{
pci_register_driver(&rivafb_driver);
return 0;
}
#ifdef MODULE
static void __exit rivafb_exit(void)
{
pci_unregister_driver(&rivafb_driver);
}
module_init(rivafb_init);
module_exit(rivafb_exit);
MODULE_PARM(flatpanel, "i");
MODULE_PARM_DESC(flatpanel, "Enables experimental flat panel support for some chipsets. (0 or 1=enabled) (default=0)");
MODULE_PARM(forceCRTC, "i");
MODULE_PARM_DESC(forceCRTC, "Forces usage of a particular CRTC in case autodetection fails. (0 or 1) (default=autodetect)");
MODULE_PARM(noaccel, "i");
MODULE_PARM_DESC(noaccel, "Disables hardware acceleration (0 or 1=disabled) (default=0)");
#ifdef CONFIG_MTRR
MODULE_PARM(nomtrr, "i");
MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) (default=0)");
#endif
#endif /* MODULE */
MODULE_AUTHOR("Ani Joshi, maintainer");
MODULE_DESCRIPTION("Framebuffer driver for nVidia Riva 128, TNT, TNT2, GeForce Series");
MODULE_LICENSE("GPL");
include/linux/fb.h
View file @
0e2e212c
...
...
@@ -97,6 +97,7 @@
#define FB_ACCEL_SIS_GLAMOUR 36
/* SiS 300/630/540 */
#define FB_ACCEL_3DLABS_PERMEDIA3 37
/* 3Dlabs Permedia 3 */
#define FB_ACCEL_ATI_RADEON 38
/* ATI Radeon family */
#define FB_ACCEL_I810 39
/* Intel 810/815 */
#define FB_ACCEL_NEOMAGIC_NM2070 90
/* NeoMagic NM2070 */
#define FB_ACCEL_NEOMAGIC_NM2090 91
/* NeoMagic NM2090 */
...
...
@@ -432,9 +433,11 @@ struct fb_info {
#define fb_readb(addr) (*(volatile u8 *) (addr))
#define fb_readw(addr) (*(volatile u16 *) (addr))
#define fb_readl(addr) (*(volatile u32 *) (addr))
#define fb_readq(addr) (*(volatile u64 *) (addr))
#define fb_writeb(b,addr) (*(volatile u8 *) (addr) = (b))
#define fb_writew(b,addr) (*(volatile u16 *) (addr) = (b))
#define fb_writel(b,addr) (*(volatile u32 *) (addr) = (b))
#define fb_writeq(b,addr) (*(volatile u64 *) (addr) = (b))
#define fb_memset memset
#endif
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment