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
1af3131d
Commit
1af3131d
authored
Dec 25, 2002
by
Richard Henderson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[FB] First cut at updating tgafb to 2.5 fb api. A large
scale rewrite modeled off of skeletonfb.c.
parent
a83c24f3
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
695 additions
and
955 deletions
+695
-955
drivers/video/Makefile
drivers/video/Makefile
+1
-1
drivers/video/tgafb.c
drivers/video/tgafb.c
+614
-885
include/video/tgafb.h
include/video/tgafb.h
+80
-69
No files found.
drivers/video/Makefile
View file @
1af3131d
...
...
@@ -48,7 +48,7 @@ obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o
obj-$(CONFIG_FB_CLGEN)
+=
clgenfb.o
obj-$(CONFIG_FB_TRIDENT)
+=
tridentfb.o
obj-$(CONFIG_FB_S3TRIO)
+=
S3triofb.o
obj-$(CONFIG_FB_TGA)
+=
tgafb.o
obj-$(CONFIG_FB_TGA)
+=
tgafb.o
cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_VESA)
+=
vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_VGA16)
+=
vga16fb.o cfbfillrect.o cfbcopyarea.o
\
cfbimgblt.o vgastate.o
...
...
drivers/video/tgafb.c
View file @
1af3131d
...
...
@@ -2,10 +2,10 @@
* linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device
*
* Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha
*
*
* $Id: tgafb.c,v 1.12.2.3 2000/04/04 06:44:56 mato Exp $
*
* This driver is partly based on the original TGA framebuffer device, which
* This driver is partly based on the original TGA framebuffer device, which
* was partly based on the original TGA console driver, which are
*
* Copyright (C) 1997 Geert Uytterhoeven
...
...
@@ -28,982 +28,711 @@
* KNOWN PROBLEMS/TO DO ==================================================== */
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/
pci
.h>
#include <linux/
fb
.h>
#include <linux/selection.h>
#include <linux/
console
.h>
#include <linux/
pci
.h>
#include <asm/io.h>
#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
#include <video/fbcon-cfb32.h>
#include "tgafb.h"
#include <video/tgafb.h>
/*
* Global declarations
*/
static
struct
tgafb_info
fb_info
;
static
struct
tgafb_par
current_par
;
static
int
current_par_valid
=
0
;
static
struct
display
disp
;
static
char
default_fontname
[
40
]
__initdata
=
{
0
};
static
struct
fb_var_screeninfo
default_var
;
static
int
default_var_valid
=
0
;
/*
* Local functions.
*/
static
struct
{
u_char
red
,
green
,
blue
,
pad
;
}
palette
[
256
];
#ifdef FBCON_HAS_CFB32
static
u32
fbcon_cfb32_cmap
[
16
];
static
int
tgafb_check_var
(
struct
fb_var_screeninfo
*
,
struct
fb_info
*
);
static
int
tgafb_set_par
(
struct
fb_info
*
);
static
void
tgafb_set_pll
(
struct
tga_par
*
,
int
);
static
int
tgafb_setcolreg
(
unsigned
,
unsigned
,
unsigned
,
unsigned
,
unsigned
,
struct
fb_info
*
);
static
int
tgafb_blank
(
int
,
struct
fb_info
*
);
static
void
tgafb_init_fix
(
struct
fb_info
*
);
static
int
tgafb_pci_register
(
struct
pci_dev
*
,
const
struct
pci_device_id
*
);
#ifdef MODULE
static
void
tgafb_pci_unregister
(
struct
pci_dev
*
);
#endif
static
const
char
*
mode_option
=
"640x480@60"
;
/*
* Hardware presets
*/
static
unsigned
int
fb_offset_presets
[
4
]
=
{
TGA_8PLANE_FB_OFFSET
,
TGA_24PLANE_FB_OFFSET
,
0xffffffff
,
TGA_24PLUSZ_FB_OFFSET
};
/*
* Frame buffer operations
*/
static
unsigned
int
deep_presets
[
4
]
=
{
0x00014000
,
0x0001440d
,
0xffffffff
,
0x0001441d
static
struct
fb_ops
tgafb_ops
=
{
.
owner
=
THIS_MODULE
,
.
fb_check_var
=
tgafb_check_var
,
.
fb_set_par
=
tgafb_set_par
,
.
fb_setcolreg
=
tgafb_setcolreg
,
.
fb_blank
=
tgafb_blank
,
.
fb_fillrect
=
cfb_fillrect
,
.
fb_copyarea
=
cfb_copyarea
,
.
fb_imageblit
=
cfb_imageblit
,
};
static
unsigned
int
rasterop_presets
[
4
]
=
{
0x00000003
,
0x00000303
,
0xffffffff
,
0x00000303
};
static
unsigned
int
mode_presets
[
4
]
=
{
0x00002000
,
0x00002300
,
0xffffffff
,
0x00002300
};
/*
* PCI registration operations
*/
static
unsigned
int
base_addr_presets
[
4
]
=
{
0x00000000
,
0x00000001
,
0xffffffff
,
0x00000001
static
struct
pci_device_id
const
tgafb_pci_table
[]
=
{
{
PCI_VENDOR_ID_DEC
,
PCI_DEVICE_ID_DEC_TGA
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
0
}
};
/*
* Predefined video modes
* This is a subset of the standard VESA modes, recalculated from XFree86.
*
* XXX Should we store these in terms of the encoded par structs? Even better,
* fbcon should provide a general mechanism for doing something like this.
*/
static
struct
{
const
char
*
name
;
struct
fb_var_screeninfo
var
;
}
tgafb_predefined
[]
__initdata
=
{
{
"640x480-60"
,
{
640
,
480
,
640
,
480
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
39722
,
40
,
24
,
32
,
11
,
96
,
2
,
0
,
FB_VMODE_NONINTERLACED
}},
{
"800x600-56"
,
{
800
,
600
,
800
,
600
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
27777
,
128
,
24
,
22
,
1
,
72
,
2
,
0
,
FB_VMODE_NONINTERLACED
}},
{
"640x480-72"
,
{
640
,
480
,
640
,
480
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
31746
,
144
,
40
,
30
,
8
,
40
,
3
,
0
,
FB_VMODE_NONINTERLACED
}},
{
"800x600-60"
,
{
800
,
600
,
800
,
600
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
25000
,
88
,
40
,
23
,
1
,
128
,
4
,
FB_SYNC_HOR_HIGH_ACT
|
FB_SYNC_VERT_HIGH_ACT
,
FB_VMODE_NONINTERLACED
}},
{
"800x600-72"
,
{
800
,
600
,
800
,
600
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
20000
,
64
,
56
,
23
,
37
,
120
,
6
,
FB_SYNC_HOR_HIGH_ACT
|
FB_SYNC_VERT_HIGH_ACT
,
FB_VMODE_NONINTERLACED
}},
{
"1024x768-60"
,
{
1024
,
768
,
1024
,
768
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
15384
,
168
,
8
,
29
,
3
,
144
,
6
,
0
,
FB_VMODE_NONINTERLACED
}},
{
"1152x864-60"
,
{
1152
,
864
,
1152
,
864
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
11123
,
208
,
64
,
16
,
4
,
256
,
8
,
0
,
FB_VMODE_NONINTERLACED
}},
{
"1024x768-70"
,
{
1024
,
768
,
1024
,
768
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
13333
,
144
,
24
,
29
,
3
,
136
,
6
,
0
,
FB_VMODE_NONINTERLACED
}},
{
"1024x768-76"
,
{
1024
,
768
,
1024
,
768
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
11764
,
208
,
8
,
36
,
16
,
120
,
3
,
0
,
FB_VMODE_NONINTERLACED
}},
{
"1152x864-70"
,
{
1152
,
864
,
1152
,
864
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
10869
,
106
,
56
,
20
,
1
,
160
,
10
,
0
,
FB_VMODE_NONINTERLACED
}},
{
"1280x1024-61"
,
{
1280
,
1024
,
1280
,
1024
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
9090
,
200
,
48
,
26
,
1
,
184
,
3
,
0
,
FB_VMODE_NONINTERLACED
}},
{
"1024x768-85"
,
{
1024
,
768
,
1024
,
768
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
10111
,
192
,
32
,
34
,
14
,
160
,
6
,
0
,
FB_VMODE_NONINTERLACED
}},
{
"1280x1024-70"
,
{
1280
,
1024
,
1280
,
1024
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
7905
,
224
,
32
,
28
,
8
,
160
,
8
,
0
,
FB_VMODE_NONINTERLACED
}},
{
"1152x864-84"
,
{
1152
,
864
,
1152
,
864
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
7407
,
184
,
312
,
32
,
0
,
128
,
12
,
0
,
FB_VMODE_NONINTERLACED
}},
{
"1280x1024-76"
,
{
1280
,
1024
,
1280
,
1024
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
7407
,
248
,
32
,
34
,
3
,
104
,
3
,
0
,
FB_VMODE_NONINTERLACED
}},
{
"1280x1024-85"
,
{
1280
,
1024
,
1280
,
1024
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
6349
,
224
,
64
,
44
,
1
,
160
,
3
,
0
,
FB_VMODE_NONINTERLACED
}},
/* These are modes used by the two fixed-frequency monitors I have at home.
* You may or may not find these useful.
*/
{
"WYSE1"
,
{
/* 1280x1024 @ 72 Hz, 130 Mhz clock */
1280
,
1024
,
1280
,
1024
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
7692
,
192
,
32
,
47
,
0
,
192
,
5
,
FB_SYNC_HOR_HIGH_ACT
|
FB_SYNC_VERT_HIGH_ACT
,
FB_VMODE_NONINTERLACED
}},
{
"IBM3"
,
{
/* 1280x1024 @ 70 Hz, 120 Mhz clock */
1280
,
1024
,
1280
,
1024
,
0
,
0
,
0
,
0
,
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
8
,
0
},
{
0
,
0
,
0
},
0
,
0
,
-
1
,
-
1
,
FB_ACCELF_TEXT
,
8333
,
192
,
32
,
47
,
0
,
192
,
5
,
0
,
FB_VMODE_NONINTERLACED
}}
static
struct
pci_driver
tgafb_driver
=
{
.
name
=
"tgafb"
,
.
id_table
=
tgafb_pci_table
,
.
probe
=
tgafb_pci_register
,
.
remove
=
__devexit_p
(
tgafb_pci_unregister
),
};
#define NUM_TOTAL_MODES ARRAY_SIZE(tgafb_predefined)
/*
* Interface used by the world
*/
static
void
tgafb_detect
(
void
);
static
int
tgafb_encode_fix
(
struct
fb_fix_screeninfo
*
fix
,
const
void
*
fb_par
,
struct
fb_info_gen
*
info
);
static
int
tgafb_decode_var
(
const
struct
fb_var_screeninfo
*
var
,
void
*
fb_par
,
struct
fb_info_gen
*
info
);
static
int
tgafb_encode_var
(
struct
fb_var_screeninfo
*
var
,
const
void
*
fb_par
,
struct
fb_info_gen
*
info
);
static
void
tgafb_get_par
(
void
*
fb_par
,
struct
fb_info_gen
*
info
);
static
void
tgafb_set_par
(
const
void
*
fb_par
,
struct
fb_info_gen
*
info
);
static
int
tgafb_getcolreg
(
u_int
regno
,
u_int
*
red
,
u_int
*
green
,
u_int
*
blue
,
u_int
*
transp
,
struct
fb_info
*
info
);
static
int
tgafb_setcolreg
(
u_int
regno
,
u_int
red
,
u_int
green
,
u_int
blue
,
u_int
transp
,
struct
fb_info
*
info
);
static
int
tgafb_blank
(
int
blank
,
struct
fb_info_gen
*
info
);
static
void
tgafb_set_disp
(
const
void
*
fb_par
,
struct
display
*
disp
,
struct
fb_info_gen
*
info
);
#ifndef MODULE
int
tgafb_setup
(
char
*
);
#endif
static
void
tgafb_set_pll
(
int
f
);
#if 1
static
int
tgafb_set_cmap
(
struct
fb_cmap
*
cmap
,
int
kspc
,
int
con
,
struct
fb_info
*
info
);
static
void
tgafb_update_palette
(
void
);
#endif
/*
* Chipset specific functions
*/
static
void
tgafb_detect
(
void
)
/**
* tgafb_check_var - Optional function. Validates a var passed in.
* @var: frame buffer variable screen structure
* @info: frame buffer structure that represents a single frame buffer
*/
static
int
tgafb_check_var
(
struct
fb_var_screeninfo
*
var
,
struct
fb_info
*
info
)
{
return
;
}
struct
tga_par
*
par
=
(
struct
tga_par
*
)
info
->
par
;
if
(
par
->
tga_type
==
TGA_TYPE_8PLANE
)
{
if
(
var
->
bits_per_pixel
>
8
)
return
-
EINVAL
;
}
else
{
if
(
var
->
bits_per_pixel
>
32
)
return
-
EINVAL
;
}
if
(
var
->
xres_virtual
!=
var
->
xres
||
var
->
yres_virtual
!=
var
->
yres
)
return
-
EINVAL
;
if
(
var
->
nonstd
)
return
-
EINVAL
;
if
(
1000000000
/
var
->
pixclock
>
TGA_PLL_MAX_FREQ
)
return
-
EINVAL
;
if
((
var
->
vmode
&
FB_VMODE_MASK
)
!=
FB_VMODE_NONINTERLACED
)
return
-
EINVAL
;
static
int
tgafb_encode_fix
(
struct
fb_fix_screeninfo
*
fix
,
const
void
*
fb_par
,
struct
fb_info_gen
*
info
)
{
struct
tgafb_par
*
par
=
(
struct
tgafb_par
*
)
fb_par
;
strcpy
(
fix
->
id
,
fb_info
.
gen
.
info
.
modename
);
fix
->
type
=
FB_TYPE_PACKED_PIXELS
;
fix
->
type_aux
=
0
;
if
(
fb_info
.
tga_type
==
TGA_TYPE_8PLANE
)
{
fix
->
visual
=
FB_VISUAL_PSEUDOCOLOR
;
}
else
{
fix
->
visual
=
FB_VISUAL_TRUECOLOR
;
}
fix
->
line_length
=
par
->
xres
*
(
par
->
bits_per_pixel
>>
3
);
fix
->
smem_start
=
fb_info
.
tga_fb_base
;
fix
->
smem_len
=
fix
->
line_length
*
par
->
yres
;
fix
->
mmio_start
=
fb_info
.
tga_regs_base
;
fix
->
mmio_len
=
0x1000
;
/* Is this sufficient? */
fix
->
xpanstep
=
fix
->
ypanstep
=
fix
->
ywrapstep
=
0
;
fix
->
accel
=
FB_ACCEL_DEC_TGA
;
return
0
;
return
0
;
}
static
int
tgafb_decode_var
(
const
struct
fb_var_screeninfo
*
var
,
void
*
fb_par
,
struct
fb_info_gen
*
info
)
/**
* tgafb_set_par - Optional function. Alters the hardware state.
* @info: frame buffer structure that represents a single frame buffer
*/
static
int
tgafb_set_par
(
struct
fb_info
*
info
)
{
struct
tgafb_par
*
par
=
(
struct
tgafb_par
*
)
fb_par
;
static
unsigned
int
const
deep_presets
[
4
]
=
{
0x00014000
,
0x0001440d
,
0xffffffff
,
0x0001441d
};
static
unsigned
int
const
rasterop_presets
[
4
]
=
{
0x00000003
,
0x00000303
,
0xffffffff
,
0x00000303
};
static
unsigned
int
const
mode_presets
[
4
]
=
{
0x00002000
,
0x00002300
,
0xffffffff
,
0x00002300
};
static
unsigned
int
const
base_addr_presets
[
4
]
=
{
0x00000000
,
0x00000001
,
0xffffffff
,
0x00000001
};
struct
tga_par
*
par
=
(
struct
tga_par
*
)
info
->
par
;
u32
htimings
,
vtimings
,
pll_freq
;
u8
tga_type
;
int
i
,
j
;
/* Encode video timings. */
htimings
=
(((
info
->
var
.
xres
/
4
)
&
TGA_HORIZ_ACT_LSB
)
|
(((
info
->
var
.
xres
/
4
)
&
0x600
<<
19
)
&
TGA_HORIZ_ACT_MSB
));
vtimings
=
(
info
->
var
.
yres
&
TGA_VERT_ACTIVE
);
htimings
|=
((
info
->
var
.
right_margin
/
4
)
<<
9
)
&
TGA_HORIZ_FP
;
vtimings
|=
(
info
->
var
.
lower_margin
<<
11
)
&
TGA_VERT_FP
;
htimings
|=
((
info
->
var
.
hsync_len
/
4
)
<<
14
)
&
TGA_HORIZ_SYNC
;
vtimings
|=
(
info
->
var
.
vsync_len
<<
16
)
&
TGA_VERT_SYNC
;
htimings
|=
((
info
->
var
.
left_margin
/
4
)
<<
21
)
&
TGA_HORIZ_BP
;
vtimings
|=
(
info
->
var
.
upper_margin
<<
22
)
&
TGA_VERT_BP
;
if
(
info
->
var
.
sync
&
FB_SYNC_HOR_HIGH_ACT
)
htimings
|=
TGA_HORIZ_POLARITY
;
if
(
info
->
var
.
sync
&
FB_SYNC_VERT_HIGH_ACT
)
vtimings
|=
TGA_VERT_POLARITY
;
par
->
htimings
=
htimings
;
par
->
vtimings
=
vtimings
;
par
->
sync_on_green
=
!!
(
info
->
var
.
sync
&
FB_SYNC_ON_GREEN
);
/* Store other useful values in par. */
par
->
xres
=
info
->
var
.
xres
;
par
->
yres
=
info
->
var
.
yres
;
par
->
pll_freq
=
pll_freq
=
1000000000
/
info
->
var
.
pixclock
;
par
->
bits_per_pixel
=
info
->
var
.
bits_per_pixel
;
tga_type
=
par
->
tga_type
;
/* First, disable video. */
TGA_WRITE_REG
(
par
,
TGA_VALID_VIDEO
|
TGA_VALID_BLANK
,
TGA_VALID_REG
);
/* Write the DEEP register. */
while
(
TGA_READ_REG
(
par
,
TGA_CMD_STAT_REG
)
&
1
)
/* wait for not busy */
continue
;
mb
();
TGA_WRITE_REG
(
par
,
deep_presets
[
tga_type
],
TGA_DEEP_REG
);
while
(
TGA_READ_REG
(
par
,
TGA_CMD_STAT_REG
)
&
1
)
/* wait for not busy */
continue
;
mb
();
/* Write some more registers. */
TGA_WRITE_REG
(
par
,
rasterop_presets
[
tga_type
],
TGA_RASTEROP_REG
);
TGA_WRITE_REG
(
par
,
mode_presets
[
tga_type
],
TGA_MODE_REG
);
TGA_WRITE_REG
(
par
,
base_addr_presets
[
tga_type
],
TGA_BASE_ADDR_REG
);
/* Calculate & write the PLL. */
tgafb_set_pll
(
par
,
pll_freq
);
/* Write some more registers. */
TGA_WRITE_REG
(
par
,
0xffffffff
,
TGA_PLANEMASK_REG
);
TGA_WRITE_REG
(
par
,
0xffffffff
,
TGA_PIXELMASK_REG
);
TGA_WRITE_REG
(
par
,
0x12345678
,
TGA_BLOCK_COLOR0_REG
);
TGA_WRITE_REG
(
par
,
0x12345678
,
TGA_BLOCK_COLOR1_REG
);
/* Init video timing regs. */
TGA_WRITE_REG
(
par
,
htimings
,
TGA_HORIZ_REG
);
TGA_WRITE_REG
(
par
,
vtimings
,
TGA_VERT_REG
);
/* Initalise RAMDAC. */
if
(
tga_type
==
TGA_TYPE_8PLANE
)
{
/* Init BT485 RAMDAC registers. */
BT485_WRITE
(
par
,
0xa2
|
(
par
->
sync_on_green
?
0x8
:
0x0
),
BT485_CMD_0
);
BT485_WRITE
(
par
,
0x01
,
BT485_ADDR_PAL_WRITE
);
BT485_WRITE
(
par
,
0x14
,
BT485_CMD_3
);
/* cursor 64x64 */
BT485_WRITE
(
par
,
0x40
,
BT485_CMD_1
);
BT485_WRITE
(
par
,
0x20
,
BT485_CMD_2
);
/* cursor off, for now */
BT485_WRITE
(
par
,
0xff
,
BT485_PIXEL_MASK
);
/* Fill palette registers. */
BT485_WRITE
(
par
,
0x00
,
BT485_ADDR_PAL_WRITE
);
TGA_WRITE_REG
(
par
,
BT485_DATA_PAL
,
TGA_RAMDAC_SETUP_REG
);
for
(
i
=
0
;
i
<
16
;
i
++
)
{
j
=
color_table
[
i
];
TGA_WRITE_REG
(
par
,
default_red
[
j
]
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
default_grn
[
j
]
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
default_blu
[
j
]
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
}
for
(
i
=
0
;
i
<
240
*
3
;
i
+=
4
)
{
TGA_WRITE_REG
(
par
,
0x55
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
0x00
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
0x00
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
0x00
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
}
}
else
{
/* 24-plane or 24plusZ */
/* Init BT463 registers. */
BT463_WRITE
(
par
,
BT463_REG_ACC
,
BT463_CMD_REG_0
,
0x40
);
BT463_WRITE
(
par
,
BT463_REG_ACC
,
BT463_CMD_REG_1
,
0x08
);
BT463_WRITE
(
par
,
BT463_REG_ACC
,
BT463_CMD_REG_2
,
(
par
->
sync_on_green
?
0x80
:
0x40
));
BT463_WRITE
(
par
,
BT463_REG_ACC
,
BT463_READ_MASK_0
,
0xff
);
BT463_WRITE
(
par
,
BT463_REG_ACC
,
BT463_READ_MASK_1
,
0xff
);
BT463_WRITE
(
par
,
BT463_REG_ACC
,
BT463_READ_MASK_2
,
0xff
);
BT463_WRITE
(
par
,
BT463_REG_ACC
,
BT463_READ_MASK_3
,
0x0f
);
BT463_WRITE
(
par
,
BT463_REG_ACC
,
BT463_BLINK_MASK_0
,
0x00
);
BT463_WRITE
(
par
,
BT463_REG_ACC
,
BT463_BLINK_MASK_1
,
0x00
);
BT463_WRITE
(
par
,
BT463_REG_ACC
,
BT463_BLINK_MASK_2
,
0x00
);
BT463_WRITE
(
par
,
BT463_REG_ACC
,
BT463_BLINK_MASK_3
,
0x00
);
/* Fill the palette. */
BT463_LOAD_ADDR
(
par
,
0x0000
);
TGA_WRITE_REG
(
par
,
BT463_PALETTE
<<
2
,
TGA_RAMDAC_REG
);
for
(
i
=
0
;
i
<
16
;
i
++
)
{
j
=
color_table
[
i
];
TGA_WRITE_REG
(
par
,
default_red
[
j
]
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
default_grn
[
j
]
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
default_blu
[
j
]
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
}
for
(
i
=
0
;
i
<
512
*
3
;
i
+=
4
)
{
TGA_WRITE_REG
(
par
,
0x55
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
0x00
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
0x00
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
0x00
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
}
/* Fill window type table after start of vertical retrace. */
while
(
!
(
TGA_READ_REG
(
par
,
TGA_INTR_STAT_REG
)
&
0x01
))
continue
;
TGA_WRITE_REG
(
par
,
0x01
,
TGA_INTR_STAT_REG
);
mb
();
while
(
!
(
TGA_READ_REG
(
par
,
TGA_INTR_STAT_REG
)
&
0x01
))
continue
;
TGA_WRITE_REG
(
par
,
0x01
,
TGA_INTR_STAT_REG
);
BT463_LOAD_ADDR
(
par
,
BT463_WINDOW_TYPE_BASE
);
TGA_WRITE_REG
(
par
,
BT463_REG_ACC
<<
2
,
TGA_RAMDAC_SETUP_REG
);
for
(
i
=
0
;
i
<
16
;
i
++
)
{
TGA_WRITE_REG
(
par
,
0x00
|
(
BT463_REG_ACC
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
0x01
|
(
BT463_REG_ACC
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
0x80
|
(
BT463_REG_ACC
<<
10
),
TGA_RAMDAC_REG
);
}
/* round up some */
if
(
fb_info
.
tga_type
==
TGA_TYPE_8PLANE
)
{
if
(
var
->
bits_per_pixel
>
8
)
{
return
-
EINVAL
;
}
par
->
bits_per_pixel
=
8
;
}
else
{
if
(
var
->
bits_per_pixel
>
32
)
{
return
-
EINVAL
;
}
par
->
bits_per_pixel
=
32
;
}
/* check the values for sanity */
if
(
var
->
xres_virtual
!=
var
->
xres
||
var
->
yres_virtual
!=
var
->
yres
||
var
->
nonstd
||
(
1000000000
/
var
->
pixclock
)
>
TGA_PLL_MAX_FREQ
||
(
var
->
vmode
&
FB_VMODE_MASK
)
!=
FB_VMODE_NONINTERLACED
#if 0 /* fbmon not done. uncomment for 2.5.x -brad */
|| !fbmon_valid_timings(var->pixclock, var->htotal, var->vtotal, info))
#else
)
#endif
return
-
EINVAL
;
/* encode video timings */
par
->
htimings
=
((
var
->
xres
/
4
)
&
TGA_HORIZ_ACT_LSB
)
|
(((
var
->
xres
/
4
)
&
0x600
<<
19
)
&
TGA_HORIZ_ACT_MSB
);
par
->
vtimings
=
(
var
->
yres
&
TGA_VERT_ACTIVE
);
par
->
htimings
|=
((
var
->
right_margin
/
4
)
<<
9
)
&
TGA_HORIZ_FP
;
par
->
vtimings
|=
(
var
->
lower_margin
<<
11
)
&
TGA_VERT_FP
;
par
->
htimings
|=
((
var
->
hsync_len
/
4
)
<<
14
)
&
TGA_HORIZ_SYNC
;
par
->
vtimings
|=
(
var
->
vsync_len
<<
16
)
&
TGA_VERT_SYNC
;
par
->
htimings
|=
((
var
->
left_margin
/
4
)
<<
21
)
&
TGA_HORIZ_BP
;
par
->
vtimings
|=
(
var
->
upper_margin
<<
22
)
&
TGA_VERT_BP
;
if
(
var
->
sync
&
FB_SYNC_HOR_HIGH_ACT
)
par
->
htimings
|=
TGA_HORIZ_POLARITY
;
if
(
var
->
sync
&
FB_SYNC_VERT_HIGH_ACT
)
par
->
vtimings
|=
TGA_VERT_POLARITY
;
if
(
var
->
sync
&
FB_SYNC_ON_GREEN
)
{
par
->
sync_on_green
=
1
;
}
else
{
par
->
sync_on_green
=
0
;
}
/* store other useful values in par */
par
->
xres
=
var
->
xres
;
par
->
yres
=
var
->
yres
;
par
->
pll_freq
=
1000000000
/
var
->
pixclock
;
par
->
bits_per_pixel
=
var
->
bits_per_pixel
;
return
0
;
}
/* Finally, enable video scan (and pray for the monitor... :-) */
TGA_WRITE_REG
(
par
,
TGA_VALID_VIDEO
,
TGA_VALID_REG
);
static
int
tgafb_encode_var
(
struct
fb_var_screeninfo
*
var
,
const
void
*
fb_par
,
struct
fb_info_gen
*
info
)
{
struct
tgafb_par
*
par
=
(
struct
tgafb_par
*
)
fb_par
;
/* decode video timings */
var
->
xres
=
((
par
->
htimings
&
TGA_HORIZ_ACT_LSB
)
|
((
par
->
htimings
&
TGA_HORIZ_ACT_MSB
)
>>
19
))
*
4
;
var
->
yres
=
(
par
->
vtimings
&
TGA_VERT_ACTIVE
);
var
->
right_margin
=
((
par
->
htimings
&
TGA_HORIZ_FP
)
>>
9
)
*
4
;
var
->
lower_margin
=
((
par
->
vtimings
&
TGA_VERT_FP
)
>>
11
);
var
->
hsync_len
=
((
par
->
htimings
&
TGA_HORIZ_SYNC
)
>>
14
)
*
4
;
var
->
vsync_len
=
((
par
->
vtimings
&
TGA_VERT_SYNC
)
>>
16
);
var
->
left_margin
=
((
par
->
htimings
&
TGA_HORIZ_BP
)
>>
21
)
*
4
;
var
->
upper_margin
=
((
par
->
vtimings
&
TGA_VERT_BP
)
>>
22
);
if
(
par
->
htimings
&
TGA_HORIZ_POLARITY
)
var
->
sync
|=
FB_SYNC_HOR_HIGH_ACT
;
if
(
par
->
vtimings
&
TGA_VERT_POLARITY
)
var
->
sync
|=
FB_SYNC_VERT_HIGH_ACT
;
if
(
par
->
sync_on_green
==
1
)
var
->
sync
|=
FB_SYNC_ON_GREEN
;
var
->
xres_virtual
=
var
->
xres
;
var
->
yres_virtual
=
var
->
yres
;
var
->
xoffset
=
var
->
yoffset
=
0
;
/* depth-related */
if
(
fb_info
.
tga_type
==
TGA_TYPE_8PLANE
)
{
var
->
red
.
offset
=
0
;
var
->
green
.
offset
=
0
;
var
->
blue
.
offset
=
0
;
}
else
{
var
->
red
.
offset
=
16
;
var
->
green
.
offset
=
8
;
var
->
blue
.
offset
=
0
;
}
var
->
bits_per_pixel
=
par
->
bits_per_pixel
;
var
->
grayscale
=
0
;
var
->
red
.
length
=
var
->
green
.
length
=
var
->
blue
.
length
=
8
;
var
->
red
.
msb_right
=
var
->
green
.
msb_right
=
var
->
blue
.
msb_right
=
0
;
var
->
transp
.
offset
=
var
->
transp
.
length
=
var
->
transp
.
msb_right
=
0
;
/* others */
var
->
xoffset
=
var
->
yoffset
=
0
;
var
->
pixclock
=
1000000000
/
par
->
pll_freq
;
var
->
nonstd
=
0
;
var
->
activate
=
0
;
var
->
height
=
var
->
width
=
-
1
;
var
->
accel_flags
=
0
;
return
0
;
return
0
;
}
static
void
tgafb_get_par
(
void
*
fb_par
,
struct
fb_info_gen
*
info
)
#define DIFFCHECK(X) \
do { \
if (m <= 0x3f) { \
int delta = f - (TGA_PLL_BASE_FREQ * (X)) / (r << shift); \
if (delta < 0) \
delta = -delta; \
if (delta < min_diff) \
min_diff = delta, vm = m, va = a, vr = r; \
} \
} while (0)
static
void
tgafb_set_pll
(
struct
tga_par
*
par
,
int
f
)
{
struct
tgafb_par
*
par
=
(
struct
tgafb_par
*
)
fb_par
;
int
n
,
shift
,
base
,
min_diff
,
target
;
int
r
,
a
,
m
,
vm
=
34
,
va
=
1
,
vr
=
30
;
for
(
r
=
0
;
r
<
12
;
r
++
)
TGA_WRITE_REG
(
par
,
!
r
,
TGA_CLOCK_REG
);
if
(
current_par_valid
)
*
par
=
current_par
;
else
{
if
(
fb_info
.
tga_type
==
TGA_TYPE_8PLANE
)
default_var
.
bits_per_pixel
=
8
;
if
(
f
>
TGA_PLL_MAX_FREQ
)
f
=
TGA_PLL_MAX_FREQ
;
if
(
f
>=
TGA_PLL_MAX_FREQ
/
2
)
shift
=
0
;
else
if
(
f
>=
TGA_PLL_MAX_FREQ
/
4
)
shift
=
1
;
else
default_var
.
bits_per_pixel
=
3
2
;
shift
=
2
;
tgafb_decode_var
(
&
default_var
,
par
,
info
);
}
}
TGA_WRITE_REG
(
par
,
shift
&
1
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
par
,
shift
>>
1
,
TGA_CLOCK_REG
);
for
(
r
=
0
;
r
<
10
;
r
++
)
TGA_WRITE_REG
(
par
,
0
,
TGA_CLOCK_REG
);
static
void
tgafb_set_par
(
const
void
*
fb_par
,
struct
fb_info_gen
*
info
)
{
int
i
,
j
;
struct
tgafb_par
*
par
=
(
struct
tgafb_par
*
)
fb_par
;
#if 0
/* XXX this will break console switching with X11, maybe I need to test KD_GRAPHICS? */
/* if current_par is valid, check to see if we need to change anything */
if (current_par_valid) {
if (!memcmp(par, ¤t_par, sizeof current_par)) {
return;
if
(
f
<=
120000
)
{
TGA_WRITE_REG
(
par
,
0
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
par
,
0
,
TGA_CLOCK_REG
);
}
}
#endif
current_par
=
*
par
;
current_par_valid
=
1
;
/* first, disable video */
TGA_WRITE_REG
(
TGA_VALID_VIDEO
|
TGA_VALID_BLANK
,
TGA_VALID_REG
);
/* write the DEEP register */
while
(
TGA_READ_REG
(
TGA_CMD_STAT_REG
)
&
1
)
/* wait for not busy */
continue
;
mb
();
TGA_WRITE_REG
(
deep_presets
[
fb_info
.
tga_type
],
TGA_DEEP_REG
);
while
(
TGA_READ_REG
(
TGA_CMD_STAT_REG
)
&
1
)
/* wait for not busy */
continue
;
mb
();
/* write some more registers */
TGA_WRITE_REG
(
rasterop_presets
[
fb_info
.
tga_type
],
TGA_RASTEROP_REG
);
TGA_WRITE_REG
(
mode_presets
[
fb_info
.
tga_type
],
TGA_MODE_REG
);
TGA_WRITE_REG
(
base_addr_presets
[
fb_info
.
tga_type
],
TGA_BASE_ADDR_REG
);
/* calculate & write the PLL */
tgafb_set_pll
(
par
->
pll_freq
);
/* write some more registers */
TGA_WRITE_REG
(
0xffffffff
,
TGA_PLANEMASK_REG
);
TGA_WRITE_REG
(
0xffffffff
,
TGA_PIXELMASK_REG
);
TGA_WRITE_REG
(
0x12345678
,
TGA_BLOCK_COLOR0_REG
);
TGA_WRITE_REG
(
0x12345678
,
TGA_BLOCK_COLOR1_REG
);
/* init video timing regs */
TGA_WRITE_REG
(
par
->
htimings
,
TGA_HORIZ_REG
);
TGA_WRITE_REG
(
par
->
vtimings
,
TGA_VERT_REG
);
/* initalise RAMDAC */
if
(
fb_info
.
tga_type
==
TGA_TYPE_8PLANE
)
{
/* init BT485 RAMDAC registers */
BT485_WRITE
(
0xa2
|
(
par
->
sync_on_green
?
0x8
:
0x0
),
BT485_CMD_0
);
BT485_WRITE
(
0x01
,
BT485_ADDR_PAL_WRITE
);
BT485_WRITE
(
0x14
,
BT485_CMD_3
);
/* cursor 64x64 */
BT485_WRITE
(
0x40
,
BT485_CMD_1
);
BT485_WRITE
(
0x20
,
BT485_CMD_2
);
/* cursor off, for now */
BT485_WRITE
(
0xff
,
BT485_PIXEL_MASK
);
/* fill palette registers */
BT485_WRITE
(
0x00
,
BT485_ADDR_PAL_WRITE
);
TGA_WRITE_REG
(
BT485_DATA_PAL
,
TGA_RAMDAC_SETUP_REG
);
for
(
i
=
0
;
i
<
16
;
i
++
)
{
j
=
color_table
[
i
];
TGA_WRITE_REG
(
default_red
[
j
]
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
default_grn
[
j
]
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
default_blu
[
j
]
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
palette
[
i
].
red
=
default_red
[
j
];
palette
[
i
].
green
=
default_grn
[
j
];
palette
[
i
].
blue
=
default_blu
[
j
];
else
if
(
f
<=
200000
)
{
TGA_WRITE_REG
(
par
,
1
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
par
,
0
,
TGA_CLOCK_REG
);
}
for
(
i
=
0
;
i
<
240
*
3
;
i
+=
4
)
{
TGA_WRITE_REG
(
0x55
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
0x00
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
0x00
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
0x00
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
}
}
else
{
/* 24-plane or 24plusZ */
/* init BT463 registers */
BT463_WRITE
(
BT463_REG_ACC
,
BT463_CMD_REG_0
,
0x40
);
BT463_WRITE
(
BT463_REG_ACC
,
BT463_CMD_REG_1
,
0x08
);
BT463_WRITE
(
BT463_REG_ACC
,
BT463_CMD_REG_2
,
(
par
->
sync_on_green
?
0x80
:
0x40
));
BT463_WRITE
(
BT463_REG_ACC
,
BT463_READ_MASK_0
,
0xff
);
BT463_WRITE
(
BT463_REG_ACC
,
BT463_READ_MASK_1
,
0xff
);
BT463_WRITE
(
BT463_REG_ACC
,
BT463_READ_MASK_2
,
0xff
);
BT463_WRITE
(
BT463_REG_ACC
,
BT463_READ_MASK_3
,
0x0f
);
BT463_WRITE
(
BT463_REG_ACC
,
BT463_BLINK_MASK_0
,
0x00
);
BT463_WRITE
(
BT463_REG_ACC
,
BT463_BLINK_MASK_1
,
0x00
);
BT463_WRITE
(
BT463_REG_ACC
,
BT463_BLINK_MASK_2
,
0x00
);
BT463_WRITE
(
BT463_REG_ACC
,
BT463_BLINK_MASK_3
,
0x00
);
/* fill the palette */
BT463_LOAD_ADDR
(
0x0000
);
TGA_WRITE_REG
((
BT463_PALETTE
<<
2
),
TGA_RAMDAC_REG
);
for
(
i
=
0
;
i
<
16
;
i
++
)
{
j
=
color_table
[
i
];
TGA_WRITE_REG
(
default_red
[
j
]
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
default_grn
[
j
]
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
default_blu
[
j
]
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
else
{
TGA_WRITE_REG
(
par
,
0
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
par
,
1
,
TGA_CLOCK_REG
);
}
for
(
i
=
0
;
i
<
512
*
3
;
i
+=
4
)
{
TGA_WRITE_REG
(
0x55
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
0x00
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
0x00
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
0x00
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
}
/* fill window type table after start of vertical retrace */
while
(
!
(
TGA_READ_REG
(
TGA_INTR_STAT_REG
)
&
0x01
))
continue
;
TGA_WRITE_REG
(
0x01
,
TGA_INTR_STAT_REG
);
mb
();
while
(
!
(
TGA_READ_REG
(
TGA_INTR_STAT_REG
)
&
0x01
))
continue
;
TGA_WRITE_REG
(
0x01
,
TGA_INTR_STAT_REG
);
BT463_LOAD_ADDR
(
BT463_WINDOW_TYPE_BASE
);
TGA_WRITE_REG
((
BT463_REG_ACC
<<
2
),
TGA_RAMDAC_SETUP_REG
);
for
(
i
=
0
;
i
<
16
;
i
++
)
{
TGA_WRITE_REG
(
0x00
|
(
BT463_REG_ACC
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
0x01
|
(
BT463_REG_ACC
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
0x80
|
(
BT463_REG_ACC
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
1
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
par
,
0
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
par
,
0
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
par
,
1
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
par
,
0
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
par
,
1
,
TGA_CLOCK_REG
);
target
=
(
f
<<
shift
)
/
TGA_PLL_BASE_FREQ
;
min_diff
=
TGA_PLL_MAX_FREQ
;
r
=
7
/
target
;
if
(
!
r
)
r
=
1
;
base
=
target
*
r
;
while
(
base
<
449
)
{
for
(
n
=
base
<
7
?
7
:
base
;
n
<
base
+
target
&&
n
<
449
;
n
++
)
{
m
=
((
n
+
3
)
/
7
)
-
1
;
a
=
0
;
DIFFCHECK
((
m
+
1
)
*
7
);
m
++
;
DIFFCHECK
((
m
+
1
)
*
7
);
m
=
(
n
/
6
)
-
1
;
if
((
a
=
n
%
6
))
DIFFCHECK
(
n
);
}
r
++
;
base
+=
target
;
}
}
/* finally, enable video scan
(and pray for the monitor... :-) */
TGA_WRITE_REG
(
TGA_VALID_VIDEO
,
TGA_VALID_REG
);
}
vr
--
;
for
(
r
=
0
;
r
<
8
;
r
++
)
TGA_WRITE_REG
(
par
,
(
vm
>>
r
)
&
1
,
TGA_CLOCK_REG
);
for
(
r
=
0
;
r
<
8
;
r
++
)
TGA_WRITE_REG
(
par
,
(
va
>>
r
)
&
1
,
TGA_CLOCK_REG
);
for
(
r
=
0
;
r
<
7
;
r
++
)
TGA_WRITE_REG
(
par
,
(
vr
>>
r
)
&
1
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
par
,
((
vr
>>
7
)
&
1
)
|
2
,
TGA_CLOCK_REG
);
}
#define DIFFCHECK(x) { if( m <= 0x3f ) { \
int delta = f - (TGA_PLL_BASE_FREQ * (x)) / (r << shift); \
if (delta < 0) delta = -delta; \
if (delta < min_diff) min_diff = delta, vm = m, va = a, vr = r; } }
static
void
tgafb_set_pll
(
int
f
)
/**
* tgafb_setcolreg - Optional function. Sets a color register.
* @regno: boolean, 0 copy local, 1 get_user() function
* @red: frame buffer colormap structure
* @green: The green value which can be up to 16 bits wide
* @blue: The blue value which can be up to 16 bits wide.
* @transp: If supported the alpha value which can be up to 16 bits wide.
* @info: frame buffer info structure
*/
static
int
tgafb_setcolreg
(
unsigned
regno
,
unsigned
red
,
unsigned
green
,
unsigned
blue
,
unsigned
transp
,
struct
fb_info
*
info
)
{
int
n
,
shift
,
base
,
min_diff
,
target
;
int
r
,
a
,
m
,
vm
=
34
,
va
=
1
,
vr
=
30
;
for
(
r
=
0
;
r
<
12
;
r
++
)
TGA_WRITE_REG
(
!
r
,
TGA_CLOCK_REG
);
if
(
f
>
TGA_PLL_MAX_FREQ
)
f
=
TGA_PLL_MAX_FREQ
;
if
(
f
>=
TGA_PLL_MAX_FREQ
/
2
)
shift
=
0
;
else
if
(
f
>=
TGA_PLL_MAX_FREQ
/
4
)
shift
=
1
;
else
shift
=
2
;
TGA_WRITE_REG
(
shift
&
1
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
shift
>>
1
,
TGA_CLOCK_REG
);
for
(
r
=
0
;
r
<
10
;
r
++
)
{
TGA_WRITE_REG
(
0
,
TGA_CLOCK_REG
);
}
if
(
f
<=
120000
)
{
TGA_WRITE_REG
(
0
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
0
,
TGA_CLOCK_REG
);
}
else
if
(
f
<=
200000
)
{
TGA_WRITE_REG
(
1
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
0
,
TGA_CLOCK_REG
);
}
else
{
TGA_WRITE_REG
(
0
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
1
,
TGA_CLOCK_REG
);
}
TGA_WRITE_REG
(
1
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
0
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
0
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
1
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
0
,
TGA_CLOCK_REG
);
TGA_WRITE_REG
(
1
,
TGA_CLOCK_REG
);
target
=
(
f
<<
shift
)
/
TGA_PLL_BASE_FREQ
;
min_diff
=
TGA_PLL_MAX_FREQ
;
r
=
7
/
target
;
if
(
!
r
)
r
=
1
;
base
=
target
*
r
;
while
(
base
<
449
)
{
for
(
n
=
base
<
7
?
7
:
base
;
n
<
base
+
target
&&
n
<
449
;
n
++
)
{
m
=
((
n
+
3
)
/
7
)
-
1
;
a
=
0
;
DIFFCHECK
((
m
+
1
)
*
7
);
m
++
;
DIFFCHECK
((
m
+
1
)
*
7
);
m
=
(
n
/
6
)
-
1
;
if
(
(
a
=
n
%
6
))
DIFFCHECK
(
n
);
struct
tga_par
*
par
=
(
struct
tga_par
*
)
info
->
par
;
if
(
regno
>
255
)
return
1
;
red
>>=
8
;
green
>>=
8
;
blue
>>=
8
;
if
(
par
->
tga_type
==
TGA_TYPE_8PLANE
)
{
BT485_WRITE
(
par
,
regno
,
BT485_ADDR_PAL_WRITE
);
TGA_WRITE_REG
(
par
,
BT485_DATA_PAL
,
TGA_RAMDAC_SETUP_REG
);
TGA_WRITE_REG
(
par
,
red
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
green
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
blue
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
}
r
++
;
base
+=
target
;
}
vr
--
;
for
(
r
=
0
;
r
<
8
;
r
++
)
{
TGA_WRITE_REG
((
vm
>>
r
)
&
1
,
TGA_CLOCK_REG
);
}
for
(
r
=
0
;
r
<
8
;
r
++
)
{
TGA_WRITE_REG
((
va
>>
r
)
&
1
,
TGA_CLOCK_REG
);
}
for
(
r
=
0
;
r
<
7
;
r
++
)
{
TGA_WRITE_REG
((
vr
>>
r
)
&
1
,
TGA_CLOCK_REG
);
}
TGA_WRITE_REG
(((
vr
>>
7
)
&
1
)
|
2
,
TGA_CLOCK_REG
);
}
/* How to set a single color register on 24-plane cards?? */
static
int
tgafb_getcolreg
(
u_int
regno
,
u_int
*
red
,
u_int
*
green
,
u_int
*
blue
,
u_int
*
transp
,
struct
fb_info
*
info
)
{
if
(
regno
>
255
)
return
1
;
*
red
=
(
palette
[
regno
].
red
<<
8
)
|
palette
[
regno
].
red
;
*
green
=
(
palette
[
regno
].
green
<<
8
)
|
palette
[
regno
].
green
;
*
blue
=
(
palette
[
regno
].
blue
<<
8
)
|
palette
[
regno
].
blue
;
*
transp
=
0
;
return
0
;
return
0
;
}
static
int
tgafb_setcolreg
(
u_int
regno
,
u_int
red
,
u_int
green
,
u_int
blue
,
u_int
transp
,
struct
fb_info
*
info
)
/**
* tgafb_blank - Optional function. Blanks the display.
* @blank_mode: the blank mode we want.
* @info: frame buffer structure that represents a single frame buffer
*/
static
int
tgafb_blank
(
int
blank
,
struct
fb_info
*
info
)
{
if
(
regno
>
255
)
return
1
;
red
>>=
8
;
green
>>=
8
;
blue
>>=
8
;
palette
[
regno
].
red
=
red
;
palette
[
regno
].
green
=
green
;
palette
[
regno
].
blue
=
blue
;
#ifdef FBCON_HAS_CFB32
if
(
regno
<
16
&&
fb_info
.
tga_type
!=
TGA_TYPE_8PLANE
)
fbcon_cfb32_cmap
[
regno
]
=
(
red
<<
16
)
|
(
green
<<
8
)
|
blue
;
#endif
if
(
fb_info
.
tga_type
==
TGA_TYPE_8PLANE
)
{
BT485_WRITE
(
regno
,
BT485_ADDR_PAL_WRITE
);
TGA_WRITE_REG
(
BT485_DATA_PAL
,
TGA_RAMDAC_SETUP_REG
);
TGA_WRITE_REG
(
red
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
green
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
blue
|
(
BT485_DATA_PAL
<<
8
),
TGA_RAMDAC_REG
);
}
/* How to set a single color register on 24-plane cards?? */
struct
tga_par
*
par
=
(
struct
tga_par
*
)
info
->
par
;
u32
vhcr
,
vvcr
,
vvvr
;
unsigned
long
flags
;
local_irq_save
(
flags
);
vhcr
=
TGA_READ_REG
(
par
,
TGA_HORIZ_REG
);
vvcr
=
TGA_READ_REG
(
par
,
TGA_VERT_REG
);
vvvr
=
TGA_READ_REG
(
par
,
TGA_VALID_REG
);
vvvr
&=
~
(
TGA_VALID_VIDEO
|
TGA_VALID_BLANK
);
switch
(
blank
)
{
case
0
:
/* Unblanking */
if
(
par
->
vesa_blanked
)
{
TGA_WRITE_REG
(
par
,
vhcr
&
0xbfffffff
,
TGA_HORIZ_REG
);
TGA_WRITE_REG
(
par
,
vvcr
&
0xbfffffff
,
TGA_VERT_REG
);
par
->
vesa_blanked
=
0
;
}
TGA_WRITE_REG
(
par
,
vvvr
|
TGA_VALID_VIDEO
,
TGA_VALID_REG
);
break
;
case
1
:
/* Normal blanking */
TGA_WRITE_REG
(
par
,
vvvr
|
TGA_VALID_VIDEO
|
TGA_VALID_BLANK
,
TGA_VALID_REG
);
break
;
case
2
:
/* VESA blank (vsync off) */
TGA_WRITE_REG
(
par
,
vvcr
|
0x40000000
,
TGA_VERT_REG
);
TGA_WRITE_REG
(
par
,
vvvr
|
TGA_VALID_BLANK
,
TGA_VALID_REG
);
par
->
vesa_blanked
=
1
;
break
;
case
3
:
/* VESA blank (hsync off) */
TGA_WRITE_REG
(
par
,
vhcr
|
0x40000000
,
TGA_HORIZ_REG
);
TGA_WRITE_REG
(
par
,
vvvr
|
TGA_VALID_BLANK
,
TGA_VALID_REG
);
par
->
vesa_blanked
=
1
;
break
;
case
4
:
/* Poweroff */
TGA_WRITE_REG
(
par
,
vhcr
|
0x40000000
,
TGA_HORIZ_REG
);
TGA_WRITE_REG
(
par
,
vvcr
|
0x40000000
,
TGA_VERT_REG
);
TGA_WRITE_REG
(
par
,
vvvr
|
TGA_VALID_BLANK
,
TGA_VALID_REG
);
par
->
vesa_blanked
=
1
;
break
;
}
return
0
;
local_irq_restore
(
flags
);
return
0
;
}
#if 1
/*
* FIXME: since I don't know how to set a single arbitrary color register
* on 24-plane cards, all color palette registers have to be updated
*/
static
int
tgafb_set_cmap
(
struct
fb_cmap
*
cmap
,
int
kspc
,
int
con
,
struct
fb_info
*
info
)
{
int
err
;
if
(
!
fb_display
[
con
].
cmap
.
len
)
{
/* no colormap allocated? */
if
((
err
=
fb_alloc_cmap
(
&
fb_display
[
con
].
cmap
,
256
,
0
)))
return
err
;
}
if
(
con
==
info
->
currcon
)
{
/* current console? */
err
=
fb_set_cmap
(
cmap
,
kspc
,
info
);
#if 1
if
(
fb_info
.
tga_type
!=
TGA_TYPE_8PLANE
)
tgafb_update_palette
();
#endif
return
err
;
}
else
fb_copy_cmap
(
cmap
,
&
fb_display
[
con
].
cmap
,
kspc
?
0
:
1
);
return
0
;
}
/*
* Initialisation
*/
static
void
tgafb_update_palette
(
void
)
static
void
tgafb_init_fix
(
struct
fb_info
*
info
)
{
int
i
;
BT463_LOAD_ADDR
(
0x0000
);
TGA_WRITE_REG
((
BT463_PALETTE
<<
2
),
TGA_RAMDAC_REG
);
struct
tga_par
*
par
=
(
struct
tga_par
*
)
info
->
par
;
u8
tga_type
=
par
->
tga_type
;
const
char
*
tga_type_name
;
for
(
i
=
0
;
i
<
256
;
i
++
)
{
TGA_WRITE_REG
(
palette
[
i
].
red
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
palette
[
i
].
green
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
palette
[
i
].
blue
|
(
BT463_PALETTE
<<
10
),
TGA_RAMDAC_REG
);
}
}
#endif
switch
(
tga_type
)
{
case
TGA_TYPE_8PLANE
:
tga_type_name
=
"Digital ZLXp-E1"
;
break
;
case
TGA_TYPE_24PLANE
:
tga_type_name
=
"Digital ZLXp-E2"
;
break
;
case
TGA_TYPE_24PLUSZ
:
tga_type_name
=
"Digital ZLXp-E3"
;
break
;
default:
tga_type_name
=
"Unknown"
;
break
;
}
strncpy
(
info
->
fix
.
id
,
tga_type_name
,
sizeof
(
info
->
fix
.
id
)
-
1
);
info
->
fix
.
id
[
sizeof
(
info
->
fix
.
id
)
-
1
]
=
0
;
static
int
tgafb_blank
(
int
blank
,
struct
fb_info_gen
*
info
)
{
static
int
tga_vesa_blanked
=
0
;
u32
vhcr
,
vvcr
,
vvvr
;
unsigned
long
flags
;
local_irq_save
(
flags
);
vhcr
=
TGA_READ_REG
(
TGA_HORIZ_REG
);
vvcr
=
TGA_READ_REG
(
TGA_VERT_REG
);
vvvr
=
TGA_READ_REG
(
TGA_VALID_REG
)
&
~
(
TGA_VALID_VIDEO
|
TGA_VALID_BLANK
);
switch
(
blank
)
{
case
0
:
/* Unblanking */
if
(
tga_vesa_blanked
)
{
TGA_WRITE_REG
(
vhcr
&
0xbfffffff
,
TGA_HORIZ_REG
);
TGA_WRITE_REG
(
vvcr
&
0xbfffffff
,
TGA_VERT_REG
);
tga_vesa_blanked
=
0
;
}
TGA_WRITE_REG
(
vvvr
|
TGA_VALID_VIDEO
,
TGA_VALID_REG
);
break
;
case
1
:
/* Normal blanking */
TGA_WRITE_REG
(
vvvr
|
TGA_VALID_VIDEO
|
TGA_VALID_BLANK
,
TGA_VALID_REG
);
break
;
case
2
:
/* VESA blank (vsync off) */
TGA_WRITE_REG
(
vvcr
|
0x40000000
,
TGA_VERT_REG
);
TGA_WRITE_REG
(
vvvr
|
TGA_VALID_BLANK
,
TGA_VALID_REG
);
tga_vesa_blanked
=
1
;
break
;
case
3
:
/* VESA blank (hsync off) */
TGA_WRITE_REG
(
vhcr
|
0x40000000
,
TGA_HORIZ_REG
);
TGA_WRITE_REG
(
vvvr
|
TGA_VALID_BLANK
,
TGA_VALID_REG
);
tga_vesa_blanked
=
1
;
break
;
case
4
:
/* Poweroff */
TGA_WRITE_REG
(
vhcr
|
0x40000000
,
TGA_HORIZ_REG
);
TGA_WRITE_REG
(
vvcr
|
0x40000000
,
TGA_VERT_REG
);
TGA_WRITE_REG
(
vvvr
|
TGA_VALID_BLANK
,
TGA_VALID_REG
);
tga_vesa_blanked
=
1
;
break
;
}
local_irq_restore
(
flags
);
return
0
;
}
info
->
fix
.
type
=
FB_TYPE_PACKED_PIXELS
;
info
->
fix
.
type_aux
=
0
;
info
->
fix
.
visual
=
(
tga_type
==
TGA_TYPE_8PLANE
?
FB_VISUAL_PSEUDOCOLOR
:
FB_VISUAL_TRUECOLOR
);
info
->
fix
.
line_length
=
par
->
xres
*
(
par
->
bits_per_pixel
>>
3
);
info
->
fix
.
smem_start
=
(
size_t
)
par
->
tga_fb_base
;
info
->
fix
.
smem_len
=
info
->
fix
.
line_length
*
par
->
yres
;
info
->
fix
.
mmio_start
=
(
size_t
)
par
->
tga_regs_base
;
info
->
fix
.
mmio_len
=
0x1000
;
/* Is this sufficient? */
static
void
tgafb_set_disp
(
const
void
*
fb_par
,
struct
display
*
disp
,
struct
fb_info_gen
*
info
)
{
switch
(
fb_info
.
tga_type
)
{
#ifdef FBCON_HAS_CFB8
case
TGA_TYPE_8PLANE
:
disp
->
dispsw
=
&
fbcon_cfb8
;
break
;
#endif
#ifdef FBCON_HAS_CFB32
case
TGA_TYPE_24PLANE
:
case
TGA_TYPE_24PLUSZ
:
disp
->
dispsw
=
&
fbcon_cfb32
;
disp
->
dispsw_data
=
&
fbcon_cfb32_cmap
;
break
;
#endif
default:
disp
->
dispsw
=
&
fbcon_dummy
;
}
info
->
fix
.
xpanstep
=
0
;
info
->
fix
.
ypanstep
=
0
;
info
->
fix
.
ywrapstep
=
0
;
disp
->
scrollmode
=
SCROLL_YREDRAW
;
info
->
fix
.
accel
=
FB_ACCEL_DEC_TGA
;
}
static
__devinit
int
tgafb_pci_register
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
)
{
static
unsigned
int
const
fb_offset_presets
[
4
]
=
{
TGA_8PLANE_FB_OFFSET
,
TGA_24PLANE_FB_OFFSET
,
0xffffffff
,
TGA_24PLUSZ_FB_OFFSET
};
struct
all_info
{
struct
fb_info
info
;
struct
tga_par
par
;
u32
pseudo_palette
[
16
];
}
*
all
;
void
*
mem_base
;
unsigned
long
bar0_start
,
bar0_len
;
u8
tga_type
;
int
ret
;
/* Enable device in PCI config. */
if
(
pci_enable_device
(
pdev
))
{
printk
(
KERN_ERR
"tgafb: Cannot enable PCI device
\n
"
);
return
-
ENODEV
;
}
struct
fbgen_hwswitch
tgafb_hwswitch
=
{
tgafb_detect
,
tgafb_encode_fix
,
tgafb_decode_var
,
tgafb_encode_var
,
tgafb_get_par
,
tgafb_set_par
,
tgafb_getcolreg
,
NULL
,
tgafb_blank
,
tgafb_set_disp
};
/* Allocate the fb and par structures. */
all
=
kmalloc
(
sizeof
(
*
all
),
GFP_KERNEL
);
if
(
!
all
)
{
printk
(
KERN_ERR
"tgafb: Cannot allocate memory
\n
"
);
return
-
ENOMEM
;
}
memset
(
all
,
0
,
sizeof
(
*
all
));
/* Request the mem regions. */
bar0_start
=
pci_resource_start
(
pdev
,
0
);
bar0_len
=
pci_resource_len
(
pdev
,
0
);
ret
=
-
ENODEV
;
if
(
!
request_mem_region
(
bar0_start
,
bar0_len
,
"tgafb"
))
{
printk
(
KERN_ERR
"tgafb: cannot reserve FB region
\n
"
);
goto
err0
;
}
/*
* Hardware Independent functions
*/
/* Map the framebuffer. */
mem_base
=
ioremap
(
bar0_start
,
bar0_len
);
if
(
!
mem_base
)
{
printk
(
KERN_ERR
"tgafb: Cannot map MMIO
\n
"
);
goto
err1
;
}
/* Grab info about the card. */
tga_type
=
(
readl
(
mem_base
)
>>
12
)
&
0x0f
;
all
->
par
.
pdev
=
pdev
;
all
->
par
.
tga_mem_base
=
mem_base
;
all
->
par
.
tga_fb_base
=
mem_base
+
fb_offset_presets
[
tga_type
];
all
->
par
.
tga_regs_base
=
mem_base
+
TGA_REGS_OFFSET
;
all
->
par
.
tga_type
=
tga_type
;
pci_read_config_byte
(
pdev
,
PCI_REVISION_ID
,
&
all
->
par
.
tga_chip_rev
);
pci_set_drvdata
(
pdev
,
&
all
->
info
);
/* Setup framebuffer. */
all
->
info
.
node
=
NODEV
;
all
->
info
.
flags
=
FBINFO_FLAG_DEFAULT
;
all
->
info
.
fbops
=
&
tgafb_ops
;
all
->
info
.
currcon
=
-
1
;
all
->
info
.
par
=
&
all
->
par
;
all
->
info
.
pseudo_palette
=
all
->
pseudo_palette
;
/* This should give a reasonable default video mode. */
ret
=
fb_find_mode
(
&
all
->
info
.
var
,
&
all
->
info
,
mode_option
,
NULL
,
0
,
NULL
,
tga_type
==
TGA_TYPE_8PLANE
?
8
:
32
);
if
(
ret
==
0
||
ret
==
4
)
{
printk
(
KERN_ERR
"tgafb: Could not find valid video mode
\n
"
);
ret
=
-
EINVAL
;
goto
err1
;
}
/*
* Frame buffer operations
*/
if
(
fb_alloc_cmap
(
&
all
->
info
.
cmap
,
256
,
0
))
{
printk
(
KERN_ERR
"tgafb: Could not allocate color map
\n
"
);
ret
=
-
ENOMEM
;
goto
err1
;
}
static
struct
fb_ops
tgafb_ops
=
{
.
owner
=
THIS_MODULE
,
.
fb_get_fix
=
fbgen_get_fix
,
.
fb_get_var
=
fbgen_get_var
,
.
fb_set_var
=
fbgen_set_var
,
.
fb_get_cmap
=
fbgen_get_cmap
,
.
fb_set_cmap
=
tgafb_set_cmap
,
.
fb_setcolreg
=
tgafb_setcolreg
,
.
fb_blank
=
fbgen_blank
,
};
tgafb_set_par
(
&
all
->
info
);
tgafb_init_fix
(
&
all
->
info
);
if
(
register_framebuffer
(
&
all
->
info
)
<
0
)
{
printk
(
KERN_ERR
"tgafb: Could not register framebuffer
\n
"
);
ret
=
-
EINVAL
;
goto
err1
;
}
#ifndef MODULE
/*
* Setup
*/
int
__init
tgafb_setup
(
char
*
options
)
{
char
*
this_opt
;
int
i
;
if
(
options
&&
*
options
)
{
while
((
this_opt
=
strsep
(
&
options
,
","
))
!=
NULL
)
{
if
(
!*
this_opt
)
{
continue
;
}
if
(
!
strncmp
(
this_opt
,
"font:"
,
5
))
{
strncpy
(
default_fontname
,
this_opt
+
5
,
sizeof
default_fontname
);
}
else
if
(
!
strncmp
(
this_opt
,
"mode:"
,
5
))
{
for
(
i
=
0
;
i
<
NUM_TOTAL_MODES
;
i
++
)
{
if
(
!
strcmp
(
this_opt
+
5
,
tgafb_predefined
[
i
].
name
))
default_var
=
tgafb_predefined
[
i
].
var
;
default_var_valid
=
1
;
}
}
else
{
printk
(
KERN_ERR
"tgafb: unknown parameter %s
\n
"
,
this_opt
);
}
}
}
return
0
;
printk
(
KERN_INFO
"tgafb: DC21030 [TGA] detected, rev=0x%02x
\n
"
,
all
->
par
.
tga_chip_rev
);
printk
(
KERN_INFO
"tgafb: at PCI bus %d, device %d, function %d
\n
"
,
pdev
->
bus
->
number
,
PCI_SLOT
(
pdev
->
devfn
),
PCI_FUNC
(
pdev
->
devfn
));
printk
(
KERN_INFO
"fb%d: %s frame buffer device at 0x%lx
\n
"
,
minor
(
all
->
info
.
node
),
all
->
info
.
fix
.
id
,
bar0_start
);
return
0
;
err1:
release_mem_region
(
bar0_start
,
bar0_len
);
err0:
kfree
(
all
);
return
ret
;
}
#endif
/*
* Initialisation
*/
int
__init
tgafb_init
(
void
)
int
__init
tgafb_init
(
void
)
{
struct
pci_dev
*
pdev
;
pdev
=
pci_find_device
(
PCI_VENDOR_ID_DEC
,
PCI_DEVICE_ID_DEC_TGA
,
NULL
);
if
(
!
pdev
)
return
-
ENXIO
;
/* divine board type */
fb_info
.
tga_mem_base
=
(
unsigned
long
)
ioremap
(
pdev
->
resource
[
0
].
start
,
0
);
fb_info
.
tga_type
=
(
readl
(
fb_info
.
tga_mem_base
)
>>
12
)
&
0x0f
;
fb_info
.
tga_regs_base
=
fb_info
.
tga_mem_base
+
TGA_REGS_OFFSET
;
fb_info
.
tga_fb_base
=
(
fb_info
.
tga_mem_base
+
fb_offset_presets
[
fb_info
.
tga_type
]);
pci_read_config_byte
(
pdev
,
PCI_REVISION_ID
,
&
fb_info
.
tga_chip_rev
);
/* setup framebuffer */
fb_info
.
gen
.
info
.
node
=
NODEV
;
fb_info
.
gen
.
info
.
flags
=
FBINFO_FLAG_DEFAULT
;
fb_info
.
gen
.
info
.
fbops
=
&
tgafb_ops
;
fb_info
.
gen
.
info
.
screen_base
=
(
char
*
)
fb_info
.
tga_fb_base
;
fb_info
.
gen
.
info
.
disp
=
&
disp
;
fb_info
.
gen
.
info
.
currcon
=
-
1
;
fb_info
.
gen
.
info
.
changevar
=
NULL
;
fb_info
.
gen
.
info
.
switch_con
=
&
fbgen_switch
;
fb_info
.
gen
.
info
.
updatevar
=
&
fbgen_update_var
;
strcpy
(
fb_info
.
gen
.
info
.
fontname
,
default_fontname
);
fb_info
.
gen
.
parsize
=
sizeof
(
struct
tgafb_par
);
fb_info
.
gen
.
fbhw
=
&
tgafb_hwswitch
;
fb_info
.
gen
.
fbhw
->
detect
();
printk
(
KERN_INFO
"tgafb: DC21030 [TGA] detected, rev=0x%02x
\n
"
,
fb_info
.
tga_chip_rev
);
printk
(
KERN_INFO
"tgafb: at PCI bus %d, device %d, function %d
\n
"
,
pdev
->
bus
->
number
,
PCI_SLOT
(
pdev
->
devfn
),
PCI_FUNC
(
pdev
->
devfn
));
switch
(
fb_info
.
tga_type
)
{
case
TGA_TYPE_8PLANE
:
strcpy
(
fb_info
.
gen
.
info
.
modename
,
"Digital ZLXp-E1"
);
break
;
case
TGA_TYPE_24PLANE
:
strcpy
(
fb_info
.
gen
.
info
.
modename
,
"Digital ZLXp-E2"
);
break
;
case
TGA_TYPE_24PLUSZ
:
strcpy
(
fb_info
.
gen
.
info
.
modename
,
"Digital ZLXp-E3"
);
break
;
}
/* This should give a reasonable default video mode */
if
(
!
default_var_valid
)
{
default_var
=
tgafb_predefined
[
0
].
var
;
}
fbgen_get_var
(
&
disp
.
var
,
-
1
,
&
fb_info
.
gen
.
info
);
disp
.
var
.
activate
=
FB_ACTIVATE_NOW
;
fbgen_do_set_var
(
&
disp
.
var
,
1
,
&
fb_info
.
gen
);
fbgen_set_disp
(
-
1
,
&
fb_info
.
gen
);
do_install_cmap
(
0
,
&
fb_info
.
gen
);
if
(
register_framebuffer
(
&
fb_info
.
gen
.
info
)
<
0
)
return
-
EINVAL
;
printk
(
KERN_INFO
"fb%d: %s frame buffer device at 0x%lx
\n
"
,
minor
(
fb_info
.
gen
.
info
.
node
),
fb_info
.
gen
.
info
.
modename
,
pdev
->
resource
[
0
].
start
);
return
0
;
return
pci_module_init
(
&
tgafb_driver
);
}
#ifdef MODULE
static
void
__exit
tgafb_pci_unregister
(
struct
pci_dev
*
pdev
)
{
struct
fb_info
*
info
=
pci_get_drvdata
(
pdev
);
struct
tga_par
*
par
=
info
->
par
;
if
(
!
info
)
return
;
unregister_framebuffer
(
info
);
iounmap
(
par
->
tga_mem_base
);
release_mem_region
(
pci_resource_start
(
pdev
,
0
),
pci_resource_len
(
pdev
,
0
));
kfree
(
info
);
}
/*
* Cleanup
*/
void
__exit
tgafb_cleanup
(
void
)
static
void
__exit
tgafb_exit
(
void
)
{
unregister_framebuffer
(
&
fb_info
.
gen
.
info
);
pci_unregister_driver
(
&
tgafb_driver
);
}
#endif
/* MODULE */
#ifndef MODULE
int
__init
tgafb_setup
(
char
*
arg
)
{
char
*
this_opt
;
if
(
arg
&&
*
arg
)
{
while
((
this_opt
=
strsep
(
&
arg
,
","
)))
{
if
(
!*
this_opt
)
continue
;
if
(
!
strncmp
(
this_opt
,
"mode:"
,
5
))
mode_option
=
this_opt
+
5
;
else
printk
(
KERN_ERR
"tgafb: unknown parameter %s
\n
"
,
this_opt
);
}
}
return
0
;
}
#endif
/* !MODULE */
/*
* Modularisation
*/
/*
* Modularisation
*/
#ifdef MODULE
MODULE_LICENSE
(
"GPL"
);
module_init
(
tgafb_init
);
module_exit
(
tgafb_exit
);
#endif
module_exit
(
tgafb_cleanup
);
MODULE_DESCRIPTION
(
"framebuffer driver for TGA chipset"
);
MODULE_LICENSE
(
"GPL"
);
drivers
/video/tgafb.h
→
include
/video/tgafb.h
View file @
1af3131d
...
...
@@ -13,17 +13,17 @@
#ifndef TGAFB_H
#define TGAFB_H
/*
* TGA hardware description (minimal)
*/
/*
* TGA hardware description (minimal)
*/
#define TGA_TYPE_8PLANE 0
#define TGA_TYPE_24PLANE 1
#define TGA_TYPE_24PLUSZ 3
/*
* Offsets within Memory Space
*/
/*
* Offsets within Memory Space
*/
#define TGA_ROM_OFFSET 0x0000000
#define TGA_REGS_OFFSET 0x0100000
...
...
@@ -52,9 +52,9 @@
#define TGA_CMD_STAT_REG 0x01f8
/*
* u
seful defines for managing the registers
*/
/*
* U
seful defines for managing the registers
*/
#define TGA_HORIZ_ODD 0x80000000
#define TGA_HORIZ_POLARITY 0x40000000
...
...
@@ -77,17 +77,17 @@
#define TGA_VALID_CURSOR 0x04
/*
* u
seful defines for managing the ICS1562 PLL clock
*/
/*
* U
seful defines for managing the ICS1562 PLL clock
*/
#define TGA_PLL_BASE_FREQ 14318
/* .18 */
#define TGA_PLL_MAX_FREQ 230000
/*
* u
seful defines for managing the BT485 on the 8-plane TGA
*/
/*
* U
seful defines for managing the BT485 on the 8-plane TGA
*/
#define BT485_READ_BIT 0x01
#define BT485_WRITE_BIT 0x00
...
...
@@ -111,9 +111,9 @@
#define BT485_CUR_HIGH_Y 0x1e
/*
* u
seful defines for managing the BT463 on the 24-plane TGAs
*/
/*
* U
seful defines for managing the BT463 on the 24-plane TGAs
*/
#define BT463_ADDR_LO 0x0
#define BT463_ADDR_HI 0x1
...
...
@@ -139,61 +139,72 @@
#define BT463_WINDOW_TYPE_BASE 0x0300
/*
* The framebuffer driver private data.
*/
/*
* Macros for reading/writing TGA and RAMDAC registers
*/
#define TGA_WRITE_REG(v,r) \
{ writel((v), fb_info.tga_regs_base+(r)); mb(); }
#define TGA_READ_REG(r) readl(fb_info.tga_regs_base+(r))
#define BT485_WRITE(v,r) \
TGA_WRITE_REG((r),TGA_RAMDAC_SETUP_REG); \
TGA_WRITE_REG(((v)&0xff)|((r)<<8),TGA_RAMDAC_REG);
#define BT463_LOAD_ADDR(a) \
TGA_WRITE_REG(BT463_ADDR_LO<<2, TGA_RAMDAC_SETUP_REG); \
TGA_WRITE_REG((BT463_ADDR_LO<<10)|((a)&0xff), TGA_RAMDAC_REG); \
TGA_WRITE_REG(BT463_ADDR_HI<<2, TGA_RAMDAC_SETUP_REG); \
TGA_WRITE_REG((BT463_ADDR_HI<<10)|(((a)>>8)&0xff), TGA_RAMDAC_REG);
#define BT463_WRITE(m,a,v) \
BT463_LOAD_ADDR((a)); \
TGA_WRITE_REG(((m)<<2),TGA_RAMDAC_SETUP_REG); \
TGA_WRITE_REG(((m)<<10)|((v)&0xff),TGA_RAMDAC_REG);
/*
* This structure describes the board.
*/
struct
tgafb_info
{
/* Use the generic framebuffer ops */
struct
fb_info_gen
gen
;
/* Device dependent information */
u8
tga_type
;
/* TGA_TYPE_XXX */
u8
tga_chip_rev
;
/* dc21030 revision */
u64
tga_mem_base
;
u64
tga_fb_base
;
u64
tga_regs_base
;
struct
fb_var_screeninfo
default_var
;
/* default video mode */
struct
tga_par
{
/* PCI device. */
struct
pci_dev
*
pdev
;
/* Device dependent information. */
void
*
tga_mem_base
;
void
*
tga_fb_base
;
void
*
tga_regs_base
;
u8
tga_type
;
/* TGA_TYPE_XXX */
u8
tga_chip_rev
;
/* dc21030 revision */
/* Remember blank mode. */
u8
vesa_blanked
;
/* Define the video mode. */
u32
xres
,
yres
;
/* resolution in pixels */
u32
htimings
;
/* horizontal timing register */
u32
vtimings
;
/* vertical timing register */
u32
pll_freq
;
/* pixclock in mhz */
u32
bits_per_pixel
;
/* bits per pixel */
u32
sync_on_green
;
/* set if sync is on green */
};
/*
* This structure uniquely defines a video mode.
*/
/*
* Macros for reading/writing TGA and RAMDAC registers
*/
struct
tgafb_par
{
u32
xres
,
yres
;
/* resolution in pixels */
u32
htimings
;
/* horizontal timing register */
u32
vtimings
;
/* vertical timing register */
u32
pll_freq
;
/* pixclock in mhz */
u32
bits_per_pixel
;
/* bits per pixel */
u32
sync_on_green
;
/* set if sync is on green */
};
static
inline
void
TGA_WRITE_REG
(
struct
tga_par
*
par
,
u32
v
,
u32
r
)
{
writel
(
v
,
par
->
tga_regs_base
+
r
);
}
static
inline
u32
TGA_READ_REG
(
struct
tga_par
*
par
,
u32
r
)
{
return
readl
(
par
->
tga_regs_base
+
r
);
}
static
inline
void
BT485_WRITE
(
struct
tga_par
*
par
,
u8
v
,
u8
r
)
{
TGA_WRITE_REG
(
par
,
r
,
TGA_RAMDAC_SETUP_REG
);
TGA_WRITE_REG
(
par
,
v
|
(
r
<<
8
),
TGA_RAMDAC_REG
);
}
static
inline
void
BT463_LOAD_ADDR
(
struct
tga_par
*
par
,
u16
a
)
{
TGA_WRITE_REG
(
par
,
BT463_ADDR_LO
<<
2
,
TGA_RAMDAC_SETUP_REG
);
TGA_WRITE_REG
(
par
,
(
BT463_ADDR_LO
<<
10
)
|
(
a
&
0xff
),
TGA_RAMDAC_REG
);
TGA_WRITE_REG
(
par
,
BT463_ADDR_HI
<<
2
,
TGA_RAMDAC_SETUP_REG
);
TGA_WRITE_REG
(
par
,
(
BT463_ADDR_HI
<<
10
)
|
(
a
>>
8
),
TGA_RAMDAC_REG
);
}
static
inline
void
BT463_WRITE
(
struct
tga_par
*
par
,
u32
m
,
u16
a
,
u8
v
)
{
BT463_LOAD_ADDR
(
par
,
a
);
TGA_WRITE_REG
(
par
,
m
<<
2
,
TGA_RAMDAC_SETUP_REG
);
TGA_WRITE_REG
(
par
,
m
<<
10
|
v
,
TGA_RAMDAC_REG
);
}
#endif
/* TGAFB_H */
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