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
Kirill Smelkov
linux
Commits
57b55f79
Commit
57b55f79
authored
Feb 26, 2003
by
David S. Miller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[FRAMEBUFFER]: Convert bw2, cg6, and cg3 drivers to new APIs.
parent
41ae6422
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
1771 additions
and
562 deletions
+1771
-562
drivers/video/Kconfig
drivers/video/Kconfig
+3
-3
drivers/video/Makefile
drivers/video/Makefile
+5
-4
drivers/video/bw2.c
drivers/video/bw2.c
+448
-0
drivers/video/bwtwofb.c
drivers/video/bwtwofb.c
+0
-269
drivers/video/cg3.c
drivers/video/cg3.c
+507
-0
drivers/video/cg6.c
drivers/video/cg6.c
+793
-0
drivers/video/cgthreefb.c
drivers/video/cgthreefb.c
+0
-286
drivers/video/fbmem.c
drivers/video/fbmem.c
+15
-0
No files found.
drivers/video/Kconfig
View file @
57b55f79
...
...
@@ -376,19 +376,19 @@ config FB_SUN3
bool "Sun3 framebuffer support"
depends on FB && (SUN3 || SUN3X)
config FB_BW
TWO
config FB_BW
2
bool "BWtwo support"
depends on FB && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
help
This is the frame buffer device driver for the BWtwo frame buffer.
config FB_CG
THREE
config FB_CG
3
bool "CGthree support"
depends on FB && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
help
This is the frame buffer device driver for the CGthree frame buffer.
config FB_CG
SIX
config FB_CG
6
bool "CGsix (GX,TurboGX) support"
depends on FB && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
help
...
...
drivers/video/Makefile
View file @
57b55f79
...
...
@@ -71,16 +71,17 @@ obj-$(CONFIG_FB_PVR2) += pvr2fb.o
obj-$(CONFIG_FB_VOODOO1)
+=
sstfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
# One by one these are being converted over to the new APIs
#obj-$(CONFIG_FB_CREATOR) += creatorfb.o sbusfb.o
#obj-$(CONFIG_FB_CGSIX) += cgsixfb.o sbusfb.o
#obj-$(CONFIG_FB_BWTWO) += bwtwofb.o sbusfb.o
#obj-$(CONFIG_FB_CGTHREE) += cgthreefb.o sbusfb.o
#obj-$(CONFIG_FB_TCX) += tcxfb.o sbusfb.o
#obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o
#obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o
#obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o
obj-$(CONFIG_FB_FFB)
+=
ffb.o sbuslib.o cfbimgblt.o cfbcopyarea.o
obj-$(CONFIG_FB_CG6)
+=
cg6.o sbuslib.o cfbimgblt.o cfbcopyarea.o
obj-$(CONFIG_FB_CG3)
+=
cg3.o sbuslib.o cfbimgblt.o cfbcopyarea.o
\
cfbfillrect.o
obj-$(CONFIG_FB_BW2)
+=
bw2.o sbuslib.o cfbimgblt.o cfbcopyarea.o
\
cfbfillrect.o
# Files generated that shall be removed upon make clean
clean-files
:=
promcon_tbl.c
...
...
drivers/video/bw2.c
0 → 100644
View file @
57b55f79
/* bw2.c: BWTWO frame buffer driver
*
* Copyright (C) 2003 David S. Miller (davem@redhat.com)
* Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*
* Driver layout based loosely on tgafb.c, see that file for credits.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/fb.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/sbus.h>
#include <asm/oplib.h>
#include <asm/fbio.h>
#ifdef CONFIG_SPARC32
#include <asm/sun4paddr.h>
#endif
#include "sbuslib.h"
/*
* Local functions.
*/
static
int
bw2_check_var
(
struct
fb_var_screeninfo
*
,
struct
fb_info
*
);
static
int
bw2_set_par
(
struct
fb_info
*
);
static
int
bw2_blank
(
int
,
struct
fb_info
*
);
static
int
bw2_mmap
(
struct
fb_info
*
,
struct
file
*
,
struct
vm_area_struct
*
);
/*
* Frame buffer operations
*/
static
struct
fb_ops
bw2_ops
=
{
.
owner
=
THIS_MODULE
,
.
fb_check_var
=
bw2_check_var
,
.
fb_set_par
=
bw2_set_par
,
.
fb_blank
=
bw2_blank
,
.
fb_fillrect
=
cfb_fillrect
,
.
fb_copyarea
=
cfb_copyarea
,
.
fb_imageblit
=
cfb_imageblit
,
.
fb_mmap
=
bw2_mmap
,
.
fb_cursor
=
soft_cursor
,
};
/* OBio addresses for the bwtwo registers */
#define BWTWO_REGISTER_OFFSET 0x400000
struct
bt_regs
{
volatile
u32
addr
;
volatile
u32
color_map
;
volatile
u32
control
;
volatile
u32
cursor
;
};
struct
bw2_regs
{
struct
bt_regs
cmap
;
volatile
u8
control
;
volatile
u8
status
;
volatile
u8
cursor_start
;
volatile
u8
cursor_end
;
volatile
u8
h_blank_start
;
volatile
u8
h_blank_end
;
volatile
u8
h_sync_start
;
volatile
u8
h_sync_end
;
volatile
u8
comp_sync_end
;
volatile
u8
v_blank_start_high
;
volatile
u8
v_blank_start_low
;
volatile
u8
v_blank_end
;
volatile
u8
v_sync_start
;
volatile
u8
v_sync_end
;
volatile
u8
xfer_holdoff_start
;
volatile
u8
xfer_holdoff_end
;
};
/* Status Register Constants */
#define BWTWO_SR_RES_MASK 0x70
#define BWTWO_SR_1600_1280 0x50
#define BWTWO_SR_1152_900_76_A 0x40
#define BWTWO_SR_1152_900_76_B 0x60
#define BWTWO_SR_ID_MASK 0x0f
#define BWTWO_SR_ID_MONO 0x02
#define BWTWO_SR_ID_MONO_ECL 0x03
#define BWTWO_SR_ID_MSYNC 0x04
#define BWTWO_SR_ID_NOCONN 0x0a
/* Control Register Constants */
#define BWTWO_CTL_ENABLE_INTS 0x80
#define BWTWO_CTL_ENABLE_VIDEO 0x40
#define BWTWO_CTL_ENABLE_TIMING 0x20
#define BWTWO_CTL_ENABLE_CURCMP 0x10
#define BWTWO_CTL_XTAL_MASK 0x0C
#define BWTWO_CTL_DIVISOR_MASK 0x03
/* Status Register Constants */
#define BWTWO_STAT_PENDING_INT 0x80
#define BWTWO_STAT_MSENSE_MASK 0x70
#define BWTWO_STAT_ID_MASK 0x0f
struct
bw2_par
{
spinlock_t
lock
;
struct
bw2_regs
*
regs
;
u32
flags
;
#define BW2_FLAG_BLANKED 0x00000001
unsigned
long
physbase
;
unsigned
long
fbsize
;
struct
sbus_dev
*
sdev
;
struct
list_head
list
;
};
/**
* bw2_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
bw2_check_var
(
struct
fb_var_screeninfo
*
var
,
struct
fb_info
*
info
)
{
if
(
var
->
bits_per_pixel
!=
8
)
return
-
EINVAL
;
if
(
var
->
xres_virtual
!=
var
->
xres
||
var
->
yres_virtual
!=
var
->
yres
)
return
-
EINVAL
;
if
(
var
->
nonstd
)
return
-
EINVAL
;
if
((
var
->
vmode
&
FB_VMODE_MASK
)
!=
FB_VMODE_NONINTERLACED
)
return
-
EINVAL
;
if
(
var
->
xres
!=
info
->
var
.
xres
||
var
->
yres
!=
info
->
var
.
yres
)
return
-
EINVAL
;
return
0
;
}
/**
* bw2_set_par - Optional function. Alters the hardware state.
* @info: frame buffer structure that represents a single frame buffer
*/
static
int
bw2_set_par
(
struct
fb_info
*
info
)
{
return
0
;
}
/**
* bw2_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
bw2_blank
(
int
blank
,
struct
fb_info
*
info
)
{
struct
bw2_par
*
par
=
(
struct
bw2_par
*
)
info
->
par
;
struct
bw2_regs
*
regs
=
par
->
regs
;
unsigned
long
flags
;
u8
val
;
spin_lock_irqsave
(
&
par
->
lock
,
flags
);
switch
(
blank
)
{
case
0
:
/* Unblanking */
val
=
sbus_readb
(
&
regs
->
control
);
val
|=
BWTWO_CTL_ENABLE_VIDEO
;
sbus_writeb
(
val
,
&
regs
->
control
);
par
->
flags
&=
~
BW2_FLAG_BLANKED
;
break
;
case
1
:
/* Normal blanking */
case
2
:
/* VESA blank (vsync off) */
case
3
:
/* VESA blank (hsync off) */
case
4
:
/* Poweroff */
val
=
sbus_readb
(
&
regs
->
control
);
val
&=
~
BWTWO_CTL_ENABLE_VIDEO
;
sbus_writeb
(
val
,
&
regs
->
control
);
par
->
flags
|=
BW2_FLAG_BLANKED
;
break
;
}
spin_unlock_irqrestore
(
&
par
->
lock
,
flags
);
return
0
;
}
static
struct
sbus_mmap_map
bw2_mmap_map
[]
=
{
{
0
,
0
,
SBUS_MMAP_FBSIZE
(
1
)
},
{
0
,
0
,
0
}
};
static
int
bw2_mmap
(
struct
fb_info
*
info
,
struct
file
*
file
,
struct
vm_area_struct
*
vma
)
{
struct
bw2_par
*
par
=
(
struct
bw2_par
*
)
info
->
par
;
return
sbusfb_mmap_helper
(
bw2_mmap_map
,
par
->
physbase
,
par
->
fbsize
,
(
par
->
sdev
?
par
->
sdev
->
reg_addrs
[
0
].
which_io
:
0
),
vma
);
}
/*
* Initialisation
*/
static
void
bw2_init_fix
(
struct
fb_info
*
info
,
int
linebytes
)
{
strncpy
(
info
->
fix
.
id
,
"bwtwo"
,
sizeof
(
info
->
fix
.
id
)
-
1
);
info
->
fix
.
id
[
sizeof
(
info
->
fix
.
id
)
-
1
]
=
0
;
info
->
fix
.
type
=
FB_TYPE_PACKED_PIXELS
;
info
->
fix
.
visual
=
FB_VISUAL_MONO01
;
info
->
fix
.
line_length
=
linebytes
;
info
->
fix
.
accel
=
FB_ACCEL_SUN_BWTWO
;
}
static
u8
bw2regs_1600
[]
__initdata
=
{
0x14
,
0x8b
,
0x15
,
0x28
,
0x16
,
0x03
,
0x17
,
0x13
,
0x18
,
0x7b
,
0x19
,
0x05
,
0x1a
,
0x34
,
0x1b
,
0x2e
,
0x1c
,
0x00
,
0x1d
,
0x0a
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x21
,
0
};
static
u8
bw2regs_ecl
[]
__initdata
=
{
0x14
,
0x65
,
0x15
,
0x1e
,
0x16
,
0x04
,
0x17
,
0x0c
,
0x18
,
0x5e
,
0x19
,
0x03
,
0x1a
,
0xa7
,
0x1b
,
0x23
,
0x1c
,
0x00
,
0x1d
,
0x08
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x20
,
0
};
static
u8
bw2regs_analog
[]
__initdata
=
{
0x14
,
0xbb
,
0x15
,
0x2b
,
0x16
,
0x03
,
0x17
,
0x13
,
0x18
,
0xb0
,
0x19
,
0x03
,
0x1a
,
0xa6
,
0x1b
,
0x22
,
0x1c
,
0x01
,
0x1d
,
0x05
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x20
,
0
};
static
u8
bw2regs_76hz
[]
__initdata
=
{
0x14
,
0xb7
,
0x15
,
0x27
,
0x16
,
0x03
,
0x17
,
0x0f
,
0x18
,
0xae
,
0x19
,
0x03
,
0x1a
,
0xae
,
0x1b
,
0x2a
,
0x1c
,
0x01
,
0x1d
,
0x09
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x24
,
0
};
static
u8
bw2regs_66hz
[]
__initdata
=
{
0x14
,
0xbb
,
0x15
,
0x2b
,
0x16
,
0x04
,
0x17
,
0x14
,
0x18
,
0xae
,
0x19
,
0x03
,
0x1a
,
0xa8
,
0x1b
,
0x24
,
0x1c
,
0x01
,
0x1d
,
0x05
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x20
,
0
};
static
void
bw2_do_default_mode
(
struct
bw2_par
*
par
,
struct
fb_info
*
info
,
int
*
linebytes
)
{
u8
status
,
mon
;
u8
*
p
;
status
=
sbus_readb
(
&
par
->
regs
->
status
);
mon
=
status
&
BWTWO_SR_RES_MASK
;
switch
(
status
&
BWTWO_SR_ID_MASK
)
{
case
BWTWO_SR_ID_MONO_ECL
:
if
(
mon
==
BWTWO_SR_1600_1280
)
{
p
=
bw2regs_1600
;
info
->
var
.
xres
=
info
->
var
.
xres_virtual
=
1600
;
info
->
var
.
yres
=
info
->
var
.
yres_virtual
=
1280
;
*
linebytes
=
1600
/
8
;
}
else
p
=
bw2regs_ecl
;
break
;
case
BWTWO_SR_ID_MONO
:
p
=
bw2regs_analog
;
break
;
case
BWTWO_SR_ID_MSYNC
:
if
(
mon
==
BWTWO_SR_1152_900_76_A
||
mon
==
BWTWO_SR_1152_900_76_B
)
p
=
bw2regs_76hz
;
else
p
=
bw2regs_66hz
;
break
;
case
BWTWO_SR_ID_NOCONN
:
return
;
default:
prom_printf
(
"bw2: can't handle SR %02x
\n
"
,
status
);
prom_halt
();
}
for
(
;
*
p
;
p
+=
2
)
{
u8
*
regp
=
&
((
u8
*
)
par
->
regs
)[
p
[
0
]];
sbus_writeb
(
p
[
1
],
regp
);
}
}
struct
all_info
{
struct
fb_info
info
;
struct
bw2_par
par
;
struct
list_head
list
;
};
static
LIST_HEAD
(
bw2_list
);
static
void
bw2_init_one
(
struct
sbus_dev
*
sdev
)
{
struct
all_info
*
all
;
struct
resource
*
resp
;
#ifdef CONFIG_SUN4
struct
resource
res
;
#endif
int
linebytes
;
all
=
kmalloc
(
sizeof
(
*
all
),
GFP_KERNEL
);
if
(
!
all
)
{
printk
(
KERN_ERR
"bw2: Cannot allocate memory.
\n
"
);
return
;
}
memset
(
all
,
0
,
sizeof
(
*
all
));
INIT_LIST_HEAD
(
&
all
->
list
);
spin_lock_init
(
&
all
->
par
.
lock
);
all
->
par
.
sdev
=
sdev
;
#ifdef CONFIG_SUN4
if
(
!
sdev
)
{
all
->
par
.
physbase
=
sun4_bwtwo_physaddr
;
res
.
start
=
sun4_bwtwo_physaddr
;
res
.
end
=
res
.
start
+
BWTWO_REGISTER_OFFSET
+
sizeof
(
struct
bw2_regs
)
-
1
;
res
.
flags
=
IORESOURCE_IO
;
resp
=
&
res
;
all
->
info
.
var
.
xres
=
all
->
info
.
var
.
xres_virtual
=
1152
;
all
->
info
.
var
.
yres
=
all
->
info
.
var
.
yres_virtual
=
900
;
all
->
info
.
bits_per_pixel
=
1
;
linebytes
=
1152
/
8
;
}
else
#else
{
if
(
!
sdev
)
BUG
();
all
->
par
.
physbase
=
sdev
->
reg_addrs
[
0
].
phys_addr
;
resp
=
&
sdev
->
resource
[
0
];
sbusfb_fill_var
(
&
all
->
info
.
var
,
(
sdev
?
sdev
->
prom_node
:
0
),
1
);
linebytes
=
prom_getintdefault
(
sdev
->
prom_node
,
"linebytes"
,
all
->
info
.
var
.
xres
);
}
#endif
all
->
par
.
regs
=
(
struct
bw2_regs
*
)
sbus_ioremap
(
resp
,
BWTWO_REGISTER_OFFSET
,
sizeof
(
struct
bw2_regs
),
"bw2 regs"
);
if
(
sdev
&&
!
prom_getbool
(
sdev
->
prom_node
,
"width"
))
bw2_do_default_mode
(
&
all
->
par
,
&
all
->
info
,
&
linebytes
);
all
->
par
.
fbsize
=
PAGE_ALIGN
(
linebytes
*
all
->
info
.
var
.
yres
);
all
->
info
.
node
=
NODEV
;
all
->
info
.
flags
=
FBINFO_FLAG_DEFAULT
;
all
->
info
.
fbops
=
&
bw2_ops
;
#if defined(CONFIG_SPARC32)
if
(
sdev
)
all
->
info
.
screen_base
=
(
char
*
)
prom_getintdefault
(
sdev
->
prom_node
,
"address"
,
0
);
#endif
if
(
!
all
->
info
.
screen_base
)
all
->
info
.
screen_base
=
(
char
*
)
sbus_ioremap
(
resp
,
0
,
all
->
par
.
fbsize
,
"bw2 ram"
);
all
->
info
.
currcon
=
-
1
;
all
->
info
.
par
=
&
all
->
par
;
bw2_blank
(
0
,
&
all
->
info
);
bw2_set_par
(
&
all
->
info
);
bw2_init_fix
(
&
all
->
info
,
linebytes
);
if
(
register_framebuffer
(
&
all
->
info
)
<
0
)
{
printk
(
KERN_ERR
"bw2: Could not register framebuffer.
\n
"
);
kfree
(
all
);
return
;
}
list_add
(
&
all
->
list
,
&
bw2_list
);
printk
(
"bw2: bwtwo at %lx:%lx
\n
"
,
(
long
)
(
sdev
?
sdev
->
reg_addrs
[
0
].
which_io
:
0
),
(
long
)
all
->
par
.
physbase
);
}
int
__init
bw2_init
(
void
)
{
struct
sbus_bus
*
sbus
;
struct
sbus_dev
*
sdev
;
#ifdef CONFIG_SUN4
bw2_init_one
(
NULL
);
#endif
for_all_sbusdev
(
sdev
,
sbus
)
{
if
(
!
strcmp
(
sdev
->
prom_name
,
"bwtwo"
))
bw2_init_one
(
sdev
);
}
return
0
;
}
void
__exit
bw2_exit
(
void
)
{
struct
list_head
*
pos
,
*
tmp
;
list_for_each_safe
(
pos
,
tmp
,
&
bw2_list
)
{
struct
all_info
*
all
=
list_entry
(
pos
,
typeof
(
*
all
),
list
);
unregister_framebuffer
(
&
all
->
info
);
kfree
(
all
);
}
}
int
__init
bw2_setup
(
char
*
arg
)
{
/* No cmdline options yet... */
return
0
;
}
#ifdef MODULE
module_init
(
bw2_init
);
module_exit
(
bw2_exit
);
#endif
MODULE_DESCRIPTION
(
"framebuffer driver for BWTWO chipsets"
);
MODULE_AUTHOR
(
"David S. Miller <davem@redhat.com>"
);
MODULE_LICENSE
(
"GPL"
);
drivers/video/bwtwofb.c
deleted
100644 → 0
View file @
41ae6422
/* $Id: bwtwofb.c,v 1.15 2001/09/19 00:04:33 davem Exp $
* bwtwofb.c: BWtwo frame buffer driver
*
* Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1998 Pavel Machek (pavel@ucw.cz)
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.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/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/selection.h>
#include <video/sbusfb.h>
#include <asm/io.h>
#if !defined(__sparc_v9__) && !defined(__mc68000__)
#include <asm/sun4paddr.h>
#endif
#include <video/fbcon-mfb.h>
/* OBio addresses for the bwtwo registers */
#define BWTWO_REGISTER_OFFSET 0x400000
struct
bw2_regs
{
struct
bt_regs
bt
;
volatile
u8
control
;
volatile
u8
status
;
volatile
u8
cursor_start
;
volatile
u8
cursor_end
;
volatile
u8
h_blank_start
;
volatile
u8
h_blank_end
;
volatile
u8
h_sync_start
;
volatile
u8
h_sync_end
;
volatile
u8
comp_sync_end
;
volatile
u8
v_blank_start_high
;
volatile
u8
v_blank_start_low
;
volatile
u8
v_blank_end
;
volatile
u8
v_sync_start
;
volatile
u8
v_sync_end
;
volatile
u8
xfer_holdoff_start
;
volatile
u8
xfer_holdoff_end
;
};
/* Status Register Constants */
#define BWTWO_SR_RES_MASK 0x70
#define BWTWO_SR_1600_1280 0x50
#define BWTWO_SR_1152_900_76_A 0x40
#define BWTWO_SR_1152_900_76_B 0x60
#define BWTWO_SR_ID_MASK 0x0f
#define BWTWO_SR_ID_MONO 0x02
#define BWTWO_SR_ID_MONO_ECL 0x03
#define BWTWO_SR_ID_MSYNC 0x04
#define BWTWO_SR_ID_NOCONN 0x0a
/* Control Register Constants */
#define BWTWO_CTL_ENABLE_INTS 0x80
#define BWTWO_CTL_ENABLE_VIDEO 0x40
#define BWTWO_CTL_ENABLE_TIMING 0x20
#define BWTWO_CTL_ENABLE_CURCMP 0x10
#define BWTWO_CTL_XTAL_MASK 0x0C
#define BWTWO_CTL_DIVISOR_MASK 0x03
/* Status Register Constants */
#define BWTWO_STAT_PENDING_INT 0x80
#define BWTWO_STAT_MSENSE_MASK 0x70
#define BWTWO_STAT_ID_MASK 0x0f
static
struct
sbus_mmap_map
bw2_mmap_map
[]
=
{
{
0
,
0
,
SBUS_MMAP_FBSIZE
(
1
)
},
{
0
,
0
,
0
}
};
static
int
bw2_blank
(
struct
fb_info_sbusfb
*
fb
)
{
unsigned
long
flags
;
u8
tmp
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
tmp
=
sbus_readb
(
&
fb
->
s
.
bw2
.
regs
->
control
);
tmp
&=
~
BWTWO_CTL_ENABLE_VIDEO
;
sbus_writeb
(
tmp
,
&
fb
->
s
.
bw2
.
regs
->
control
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
return
0
;
}
static
int
bw2_unblank
(
struct
fb_info_sbusfb
*
fb
)
{
unsigned
long
flags
;
u8
tmp
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
tmp
=
sbus_readb
(
&
fb
->
s
.
bw2
.
regs
->
control
);
tmp
|=
BWTWO_CTL_ENABLE_VIDEO
;
sbus_writeb
(
tmp
,
&
fb
->
s
.
bw2
.
regs
->
control
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
return
0
;
}
static
void
bw2_margins
(
struct
fb_info_sbusfb
*
fb
,
struct
display
*
p
,
int
x_margin
,
int
y_margin
)
{
fb
->
info
.
screen_base
+=
(
y_margin
-
fb
->
y_margin
)
*
p
->
fb_info
->
fix
.
line_length
+
((
x_margin
-
fb
->
x_margin
)
>>
3
);
}
static
u8
bw2regs_1600
[]
__initdata
=
{
0x14
,
0x8b
,
0x15
,
0x28
,
0x16
,
0x03
,
0x17
,
0x13
,
0x18
,
0x7b
,
0x19
,
0x05
,
0x1a
,
0x34
,
0x1b
,
0x2e
,
0x1c
,
0x00
,
0x1d
,
0x0a
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x21
,
0
};
static
u8
bw2regs_ecl
[]
__initdata
=
{
0x14
,
0x65
,
0x15
,
0x1e
,
0x16
,
0x04
,
0x17
,
0x0c
,
0x18
,
0x5e
,
0x19
,
0x03
,
0x1a
,
0xa7
,
0x1b
,
0x23
,
0x1c
,
0x00
,
0x1d
,
0x08
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x20
,
0
};
static
u8
bw2regs_analog
[]
__initdata
=
{
0x14
,
0xbb
,
0x15
,
0x2b
,
0x16
,
0x03
,
0x17
,
0x13
,
0x18
,
0xb0
,
0x19
,
0x03
,
0x1a
,
0xa6
,
0x1b
,
0x22
,
0x1c
,
0x01
,
0x1d
,
0x05
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x20
,
0
};
static
u8
bw2regs_76hz
[]
__initdata
=
{
0x14
,
0xb7
,
0x15
,
0x27
,
0x16
,
0x03
,
0x17
,
0x0f
,
0x18
,
0xae
,
0x19
,
0x03
,
0x1a
,
0xae
,
0x1b
,
0x2a
,
0x1c
,
0x01
,
0x1d
,
0x09
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x24
,
0
};
static
u8
bw2regs_66hz
[]
__initdata
=
{
0x14
,
0xbb
,
0x15
,
0x2b
,
0x16
,
0x04
,
0x17
,
0x14
,
0x18
,
0xae
,
0x19
,
0x03
,
0x1a
,
0xa8
,
0x1b
,
0x24
,
0x1c
,
0x01
,
0x1d
,
0x05
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x20
,
0
};
static
char
idstring
[
60
]
__initdata
=
{
0
};
char
__init
*
bwtwofb_init
(
struct
fb_info_sbusfb
*
fb
)
{
struct
fb_fix_screeninfo
*
fix
=
&
fb
->
info
.
fix
;
struct
display
*
disp
=
&
fb
->
disp
;
struct
fbtype
*
type
=
&
fb
->
type
;
#ifdef CONFIG_SUN4
unsigned
long
phys
=
sun4_bwtwo_physaddr
;
struct
resource
res
;
#else
unsigned
long
phys
=
fb
->
sbdp
->
reg_addrs
[
0
].
phys_addr
;
#endif
struct
resource
*
resp
;
unsigned
int
vaddr
;
#ifndef FBCON_HAS_MFB
return
NULL
;
#endif
#ifdef CONFIG_SUN4
res
.
start
=
phys
;
res
.
end
=
res
.
start
+
BWTWO_REGISTER_OFFSET
+
sizeof
(
struct
bw2_regs
)
-
1
;
res
.
flags
=
IORESOURCE_IO
|
(
fb
->
iospace
&
0xff
);
resp
=
&
res
;
#else
resp
=
&
fb
->
sbdp
->
resource
[
0
];
#endif
if
(
!
fb
->
s
.
bw2
.
regs
)
{
fb
->
s
.
bw2
.
regs
=
(
struct
bw2_regs
*
)
sbus_ioremap
(
resp
,
BWTWO_REGISTER_OFFSET
,
sizeof
(
struct
bw2_regs
),
"bw2 regs"
);
if
((
!
ARCH_SUN4
)
&&
(
!
prom_getbool
(
fb
->
prom_node
,
"width"
)))
{
/* Ugh, broken PROM didn't initialize us.
* Let's deal with this ourselves.
*/
u8
status
,
mon
;
u8
*
p
;
int
sizechange
=
0
;
status
=
sbus_readb
(
&
fb
->
s
.
bw2
.
regs
->
status
);
mon
=
status
&
BWTWO_SR_RES_MASK
;
switch
(
status
&
BWTWO_SR_ID_MASK
)
{
case
BWTWO_SR_ID_MONO_ECL
:
if
(
mon
==
BWTWO_SR_1600_1280
)
{
p
=
bw2regs_1600
;
fb
->
type
.
fb_width
=
1600
;
fb
->
type
.
fb_height
=
1280
;
sizechange
=
1
;
}
else
p
=
bw2regs_ecl
;
break
;
case
BWTWO_SR_ID_MONO
:
p
=
bw2regs_analog
;
break
;
case
BWTWO_SR_ID_MSYNC
:
if
(
mon
==
BWTWO_SR_1152_900_76_A
||
mon
==
BWTWO_SR_1152_900_76_B
)
p
=
bw2regs_76hz
;
else
p
=
bw2regs_66hz
;
break
;
case
BWTWO_SR_ID_NOCONN
:
return
NULL
;
default:
#ifndef CONFIG_FB_SUN3
prom_printf
(
"bw2: can't handle SR %02x
\n
"
,
status
);
prom_halt
();
#endif
return
NULL
;
/* fool gcc. */
}
for
(
;
*
p
;
p
+=
2
)
{
u8
*
regp
=
&
((
u8
*
)
fb
->
s
.
bw2
.
regs
)[
p
[
0
]];
sbus_writeb
(
p
[
1
],
regp
);
}
}
}
strcpy
(
fb
->
info
.
modename
,
"BWtwo"
);
strcpy
(
fix
->
id
,
"BWtwo"
);
fix
->
line_length
=
fb
->
info
.
var
.
xres_virtual
>>
3
;
fix
->
accel
=
FB_ACCEL_SUN_BWTWO
;
disp
->
scrollmode
=
SCROLL_YREDRAW
;
disp
->
inverse
=
1
;
if
(
!
fb
->
info
.
screen_base
)
{
fb
->
info
.
screen_base
=
(
char
*
)
sbus_ioremap
(
resp
,
0
,
type
->
fb_size
,
"bw2 ram"
);
}
fb
->
info
.
screen_base
+=
fix
->
line_length
*
fb
->
y_margin
+
(
fb
->
x_margin
>>
3
);
fb
->
dispsw
=
fbcon_mfb
;
fix
->
visual
=
FB_VISUAL_MONO01
;
#ifndef CONFIG_SUN4
fb
->
blank
=
bw2_blank
;
fb
->
unblank
=
bw2_unblank
;
prom_getproperty
(
fb
->
sbdp
->
prom_node
,
"address"
,
(
char
*
)
&
vaddr
,
sizeof
(
vaddr
));
fb
->
physbase
=
__get_phys
((
unsigned
long
)
vaddr
);
#endif
fb
->
margins
=
bw2_margins
;
fb
->
mmap_map
=
bw2_mmap_map
;
#ifdef __sparc_v9__
sprintf
(
idstring
,
"bwtwo at %016lx"
,
phys
);
#else
sprintf
(
idstring
,
"bwtwo at %x.%08lx"
,
fb
->
iospace
,
phys
);
#endif
return
idstring
;
}
MODULE_LICENSE
(
"GPL"
);
drivers/video/cg3.c
0 → 100644
View file @
57b55f79
/* cg3.c: CGTHREE frame buffer driver
*
* Copyright (C) 2003 David S. Miller (davem@redhat.com)
* Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*
* Driver layout based loosely on tgafb.c, see that file for credits.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/fb.h>
#include <linux/mm.h>
#include <asm/io.h>
#include <asm/sbus.h>
#include <asm/oplib.h>
#include <asm/fbio.h>
#include "sbuslib.h"
/*
* Local functions.
*/
static
int
cg3_check_var
(
struct
fb_var_screeninfo
*
,
struct
fb_info
*
);
static
int
cg3_set_par
(
struct
fb_info
*
);
static
int
cg3_setcolreg
(
unsigned
,
unsigned
,
unsigned
,
unsigned
,
unsigned
,
struct
fb_info
*
);
static
int
cg3_blank
(
int
,
struct
fb_info
*
);
static
int
cg3_mmap
(
struct
fb_info
*
,
struct
file
*
,
struct
vm_area_struct
*
);
/*
* Frame buffer operations
*/
static
struct
fb_ops
cg3_ops
=
{
.
owner
=
THIS_MODULE
,
.
fb_check_var
=
cg3_check_var
,
.
fb_set_par
=
cg3_set_par
,
.
fb_setcolreg
=
cg3_setcolreg
,
.
fb_blank
=
cg3_blank
,
.
fb_fillrect
=
cfb_fillrect
,
.
fb_copyarea
=
cfb_copyarea
,
.
fb_imageblit
=
cfb_imageblit
,
.
fb_mmap
=
cg3_mmap
,
.
fb_cursor
=
soft_cursor
,
};
/* Control Register Constants */
#define CG3_CR_ENABLE_INTS 0x80
#define CG3_CR_ENABLE_VIDEO 0x40
#define CG3_CR_ENABLE_TIMING 0x20
#define CG3_CR_ENABLE_CURCMP 0x10
#define CG3_CR_XTAL_MASK 0x0c
#define CG3_CR_DIVISOR_MASK 0x03
/* Status Register Constants */
#define CG3_SR_PENDING_INT 0x80
#define CG3_SR_RES_MASK 0x70
#define CG3_SR_1152_900_76_A 0x40
#define CG3_SR_1152_900_76_B 0x60
#define CG3_SR_ID_MASK 0x0f
#define CG3_SR_ID_COLOR 0x01
#define CG3_SR_ID_MONO 0x02
#define CG3_SR_ID_MONO_ECL 0x03
enum
cg3_type
{
CG3_AT_66HZ
=
0
,
CG3_AT_76HZ
,
CG3_RDI
};
struct
bt_regs
{
volatile
u32
addr
;
volatile
u32
color_map
;
volatile
u32
control
;
volatile
u32
cursor
;
};
struct
cg3_regs
{
struct
bt_regs
cmap
;
volatile
u8
control
;
volatile
u8
status
;
volatile
u8
cursor_start
;
volatile
u8
cursor_end
;
volatile
u8
h_blank_start
;
volatile
u8
h_blank_end
;
volatile
u8
h_sync_start
;
volatile
u8
h_sync_end
;
volatile
u8
comp_sync_end
;
volatile
u8
v_blank_start_high
;
volatile
u8
v_blank_start_low
;
volatile
u8
v_blank_end
;
volatile
u8
v_sync_start
;
volatile
u8
v_sync_end
;
volatile
u8
xfer_holdoff_start
;
volatile
u8
xfer_holdoff_end
;
};
/* Offset of interesting structures in the OBIO space */
#define CG3_REGS_OFFSET 0x400000UL
#define CG3_RAM_OFFSET 0x800000UL
struct
cg3_par
{
spinlock_t
lock
;
struct
cg3_regs
*
regs
;
u32
sw_cmap
[((
256
*
3
)
+
3
)
/
4
];
u32
flags
;
#define CG3_FLAG_BLANKED 0x00000001
#define CG3_FLAG_RDI 0x00000002
unsigned
long
physbase
;
unsigned
long
fbsize
;
struct
sbus_dev
*
sdev
;
struct
list_head
list
;
};
/**
* cg3_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
cg3_check_var
(
struct
fb_var_screeninfo
*
var
,
struct
fb_info
*
info
)
{
if
(
var
->
bits_per_pixel
!=
8
)
return
-
EINVAL
;
if
(
var
->
xres_virtual
!=
var
->
xres
||
var
->
yres_virtual
!=
var
->
yres
)
return
-
EINVAL
;
if
(
var
->
nonstd
)
return
-
EINVAL
;
if
((
var
->
vmode
&
FB_VMODE_MASK
)
!=
FB_VMODE_NONINTERLACED
)
return
-
EINVAL
;
if
(
var
->
xres
!=
info
->
var
.
xres
||
var
->
yres
!=
info
->
var
.
yres
)
return
-
EINVAL
;
return
0
;
}
/**
* cg3_set_par - Optional function. Alters the hardware state.
* @info: frame buffer structure that represents a single frame buffer
*/
static
int
cg3_set_par
(
struct
fb_info
*
info
)
{
return
0
;
}
/**
* cg3_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
*
* The cg3 palette is loaded with 4 color values at each time
* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on.
* We keep a sw copy of the hw cmap to assist us in this esoteric
* loading procedure.
*/
static
int
cg3_setcolreg
(
unsigned
regno
,
unsigned
red
,
unsigned
green
,
unsigned
blue
,
unsigned
transp
,
struct
fb_info
*
info
)
{
struct
cg3_par
*
par
=
(
struct
cg3_par
*
)
info
->
par
;
struct
bt_regs
*
bt
=
&
par
->
regs
->
cmap
;
unsigned
long
flags
;
u32
*
p32
;
u8
*
p8
;
int
count
;
if
(
regno
>=
256
)
return
1
;
red
>>=
8
;
green
>>=
8
;
blue
>>=
8
;
spin_lock_irqsave
(
&
par
->
lock
,
flags
);
p8
=
(
u8
*
)
par
->
sw_cmap
+
(
regno
*
3
);
p8
[
0
]
=
red
;
p8
[
1
]
=
green
;
p8
[
2
]
=
blue
;
#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))
/* (x/4)*3 */
#define D4M4(x) ((x)&~0x3)
/* (x/4)*4 */
count
=
3
;
p32
=
&
par
->
sw_cmap
[
D4M3
(
regno
)];
sbus_writel
(
D4M4
(
regno
),
&
bt
->
addr
);
while
(
count
--
)
sbus_writel
(
*
p32
++
,
&
bt
->
color_map
);
#undef D4M3
#undef D4M4
spin_unlock_irqrestore
(
&
par
->
lock
,
flags
);
return
0
;
}
/**
* cg3_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
cg3_blank
(
int
blank
,
struct
fb_info
*
info
)
{
struct
cg3_par
*
par
=
(
struct
cg3_par
*
)
info
->
par
;
struct
cg3_regs
*
regs
=
par
->
regs
;
unsigned
long
flags
;
u8
val
;
spin_lock_irqsave
(
&
par
->
lock
,
flags
);
switch
(
blank
)
{
case
0
:
/* Unblanking */
val
=
sbus_readl
(
&
regs
->
control
);
val
|=
CG3_CR_ENABLE_VIDEO
;
sbus_writel
(
val
,
&
regs
->
control
);
par
->
flags
&=
~
CG3_FLAG_BLANKED
;
break
;
case
1
:
/* Normal blanking */
case
2
:
/* VESA blank (vsync off) */
case
3
:
/* VESA blank (hsync off) */
case
4
:
/* Poweroff */
val
=
sbus_readl
(
&
regs
->
control
);
val
|=
CG3_CR_ENABLE_VIDEO
;
sbus_writel
(
val
,
&
regs
->
control
);
par
->
flags
|=
CG3_FLAG_BLANKED
;
break
;
}
spin_unlock_irqrestore
(
&
par
->
lock
,
flags
);
return
0
;
}
static
struct
sbus_mmap_map
cg3_mmap_map
[]
=
{
{
CG3_MMAP_OFFSET
,
CG3_RAM_OFFSET
,
SBUS_MMAP_FBSIZE
(
1
)
},
{
0
,
0
,
0
}
};
static
int
cg3_mmap
(
struct
fb_info
*
info
,
struct
file
*
file
,
struct
vm_area_struct
*
vma
)
{
struct
cg3_par
*
par
=
(
struct
cg3_par
*
)
info
->
par
;
return
sbusfb_mmap_helper
(
cg3_mmap_map
,
par
->
physbase
,
par
->
fbsize
,
par
->
sdev
->
reg_addrs
[
0
].
which_io
,
vma
);
}
/*
* Initialisation
*/
static
void
cg3_init_fix
(
struct
fb_info
*
info
,
int
linebytes
)
{
struct
cg3_par
*
par
=
(
struct
cg3_par
*
)
info
->
par
;
strncpy
(
info
->
fix
.
id
,
par
->
sdev
->
prom_name
,
sizeof
(
info
->
fix
.
id
)
-
1
);
info
->
fix
.
id
[
sizeof
(
info
->
fix
.
id
)
-
1
]
=
0
;
info
->
fix
.
type
=
FB_TYPE_PACKED_PIXELS
;
info
->
fix
.
visual
=
FB_VISUAL_PSEUDOCOLOR
;
info
->
fix
.
line_length
=
linebytes
;
info
->
fix
.
accel
=
FB_ACCEL_SUN_CGTHREE
;
}
static
void
cg3_rdi_maybe_fixup_var
(
struct
fb_var_screeninfo
*
var
,
struct
sbus_dev
*
sdev
)
{
char
buffer
[
40
];
char
*
p
;
int
ww
,
hh
;
*
buffer
=
0
;
prom_getstring
(
sdev
->
prom_node
,
"params"
,
buffer
,
sizeof
(
buffer
));
if
(
*
buffer
)
{
ww
=
simple_strtoul
(
buffer
,
&
p
,
10
);
if
(
ww
&&
*
p
==
'x'
)
{
hh
=
simple_strtoul
(
p
+
1
,
&
p
,
10
);
if
(
hh
&&
*
p
==
'-'
)
{
if
(
var
->
xres
!=
ww
||
var
->
yres
!=
hh
)
{
var
->
xres
=
var
->
xres_virtual
=
ww
;
var
->
yres
=
var
->
yres_virtual
=
hh
;
}
}
}
}
}
static
u8
cg3regvals_66hz
[]
__initdata
=
{
/* 1152 x 900, 66 Hz */
0x14
,
0xbb
,
0x15
,
0x2b
,
0x16
,
0x04
,
0x17
,
0x14
,
0x18
,
0xae
,
0x19
,
0x03
,
0x1a
,
0xa8
,
0x1b
,
0x24
,
0x1c
,
0x01
,
0x1d
,
0x05
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x20
,
0
};
static
u8
cg3regvals_76hz
[]
__initdata
=
{
/* 1152 x 900, 76 Hz */
0x14
,
0xb7
,
0x15
,
0x27
,
0x16
,
0x03
,
0x17
,
0x0f
,
0x18
,
0xae
,
0x19
,
0x03
,
0x1a
,
0xae
,
0x1b
,
0x2a
,
0x1c
,
0x01
,
0x1d
,
0x09
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x24
,
0
};
static
u8
cg3regvals_rdi
[]
__initdata
=
{
/* 640 x 480, cgRDI */
0x14
,
0x70
,
0x15
,
0x20
,
0x16
,
0x08
,
0x17
,
0x10
,
0x18
,
0x06
,
0x19
,
0x02
,
0x1a
,
0x31
,
0x1b
,
0x51
,
0x1c
,
0x06
,
0x1d
,
0x0c
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x22
,
0
};
static
u8
*
cg3_regvals
[]
__initdata
=
{
cg3regvals_66hz
,
cg3regvals_76hz
,
cg3regvals_rdi
};
static
u_char
cg3_dacvals
[]
__initdata
=
{
4
,
0xff
,
5
,
0x00
,
6
,
0x70
,
7
,
0x00
,
0
};
static
void
cg3_do_default_mode
(
struct
cg3_par
*
par
)
{
enum
cg3_type
type
;
u8
*
p
;
if
(
par
->
flags
&
CG3_FLAG_RDI
)
type
=
CG3_RDI
;
else
{
u8
status
=
sbus_readb
(
&
par
->
regs
->
status
),
mon
;
if
((
status
&
CG3_SR_ID_MASK
)
==
CG3_SR_ID_COLOR
)
{
mon
=
status
&
CG3_SR_RES_MASK
;
if
(
mon
==
CG3_SR_1152_900_76_A
||
mon
==
CG3_SR_1152_900_76_B
)
type
=
CG3_AT_76HZ
;
else
type
=
CG3_AT_66HZ
;
}
else
{
prom_printf
(
"cgthree: can't handle SR %02x
\n
"
,
status
);
prom_halt
();
return
;
}
}
for
(
p
=
cg3_regvals
[
type
];
*
p
;
p
+=
2
)
{
u8
*
regp
=
&
((
u8
*
)
par
->
regs
)[
p
[
0
]];
sbus_writeb
(
p
[
1
],
regp
);
}
for
(
p
=
cg3_dacvals
;
*
p
;
p
+=
2
)
{
volatile
u8
*
regp
;
regp
=
(
volatile
u8
*
)
&
par
->
regs
->
cmap
.
addr
;
sbus_writeb
(
p
[
0
],
regp
);
regp
=
(
volatile
u8
*
)
&
par
->
regs
->
cmap
.
control
;
sbus_writeb
(
p
[
1
],
regp
);
}
}
struct
all_info
{
struct
fb_info
info
;
struct
cg3_par
par
;
struct
list_head
list
;
};
static
LIST_HEAD
(
cg3_list
);
static
void
cg3_init_one
(
struct
sbus_dev
*
sdev
)
{
struct
all_info
*
all
;
int
linebytes
;
all
=
kmalloc
(
sizeof
(
*
all
),
GFP_KERNEL
);
if
(
!
all
)
{
printk
(
KERN_ERR
"cg3: Cannot allocate memory.
\n
"
);
return
;
}
memset
(
all
,
0
,
sizeof
(
*
all
));
INIT_LIST_HEAD
(
&
all
->
list
);
spin_lock_init
(
&
all
->
par
.
lock
);
all
->
par
.
sdev
=
sdev
;
all
->
par
.
physbase
=
sdev
->
reg_addrs
[
0
].
phys_addr
;
sbusfb_fill_var
(
&
all
->
info
.
var
,
sdev
->
prom_node
,
8
);
if
(
!
strcmp
(
sdev
->
prom_name
,
"cgRDI"
))
all
->
par
.
flags
|=
CG3_FLAG_RDI
;
if
(
all
->
par
.
flags
&
CG3_FLAG_RDI
)
cg3_rdi_maybe_fixup_var
(
&
all
->
info
.
var
,
sdev
);
linebytes
=
prom_getintdefault
(
sdev
->
prom_node
,
"linebytes"
,
all
->
info
.
var
.
xres
);
all
->
par
.
fbsize
=
PAGE_ALIGN
(
linebytes
*
all
->
info
.
var
.
yres
);
all
->
par
.
regs
=
(
struct
cg3_regs
*
)
sbus_ioremap
(
&
sdev
->
resource
[
0
],
CG3_REGS_OFFSET
,
sizeof
(
struct
cg3_regs
),
"cg3 regs"
);
all
->
info
.
node
=
NODEV
;
all
->
info
.
flags
=
FBINFO_FLAG_DEFAULT
;
all
->
info
.
fbops
=
&
cg3_ops
;
#ifdef CONFIG_SPARC32
all
->
info
.
screen_base
=
(
char
*
)
prom_getintdefault
(
sdev
->
prom_node
,
"address"
,
0
);
#endif
if
(
!
all
->
info
.
screen_base
)
all
->
info
.
screen_base
=
(
char
*
)
sbus_ioremap
(
&
sdev
->
resource
[
0
],
CG3_RAM_OFFSET
,
all
->
par
.
fbsize
,
"cg3 ram"
);
all
->
info
.
currcon
=
-
1
;
all
->
info
.
par
=
&
all
->
par
;
cg3_blank
(
0
,
&
all
->
info
);
if
(
!
prom_getbool
(
sdev
->
prom_node
,
"width"
))
cg3_do_default_mode
(
&
all
->
par
);
if
(
fb_alloc_cmap
(
&
all
->
info
.
cmap
,
256
,
0
))
{
printk
(
KERN_ERR
"cg3: Could not allocate color map.
\n
"
);
kfree
(
all
);
return
;
}
cg3_set_par
(
&
all
->
info
);
cg3_init_fix
(
&
all
->
info
,
linebytes
);
if
(
register_framebuffer
(
&
all
->
info
)
<
0
)
{
printk
(
KERN_ERR
"cg3: Could not register framebuffer.
\n
"
);
fb_dealloc_cmap
(
&
all
->
info
.
cmap
);
kfree
(
all
);
return
;
}
list_add
(
&
all
->
list
,
&
cg3_list
);
printk
(
"cg3: %s at %lx:%lx
\n
"
,
sdev
->
prom_name
,
(
long
)
sdev
->
reg_addrs
[
0
].
which_io
,
(
long
)
sdev
->
reg_addrs
[
0
].
phys_addr
);
}
int
__init
cg3_init
(
void
)
{
struct
sbus_bus
*
sbus
;
struct
sbus_dev
*
sdev
;
for_all_sbusdev
(
sdev
,
sbus
)
{
if
(
!
strcmp
(
sdev
->
prom_name
,
"cgthree"
)
||
!
strcmp
(
sdev
->
prom_name
,
"cgRDI"
))
cg3_init_one
(
sdev
);
}
return
0
;
}
void
__exit
cg3_exit
(
void
)
{
struct
list_head
*
pos
,
*
tmp
;
list_for_each_safe
(
pos
,
tmp
,
&
cg3_list
)
{
struct
all_info
*
all
=
list_entry
(
pos
,
typeof
(
*
all
),
list
);
unregister_framebuffer
(
&
all
->
info
);
fb_dealloc_cmap
(
&
all
->
info
.
cmap
);
kfree
(
all
);
}
}
int
__init
cg3_setup
(
char
*
arg
)
{
/* No cmdline options yet... */
return
0
;
}
#ifdef MODULE
module_init
(
cg3_init
);
module_exit
(
cg3_exit
);
#endif
MODULE_DESCRIPTION
(
"framebuffer driver for CGthree chipsets"
);
MODULE_AUTHOR
(
"David S. Miller <davem@redhat.com>"
);
MODULE_LICENSE
(
"GPL"
);
drivers/video/cg
sixfb
.c
→
drivers/video/cg
6
.c
View file @
57b55f79
/* $Id: cgsixfb.c,v 1.26 2001/10/16 05:44:44 davem Exp $
* cgsixfb.c: CGsix (GX,GXplus) frame buffer driver
/* cg6.c: CGSIX (GX, GXplus, TGX) frame buffer driver
*
* Copyright (C) 2003 David S. Miller (davem@redhat.com)
* Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
*
* Driver layout based loosely on tgafb.c, see that file for credits.
*/
#include <linux/module.h>
#include <linux/sched.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/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/selection.h>
#include <linux/fb.h>
#include <linux/mm.h>
#include <video/sbusfb.h>
#include <asm/io.h>
#include <asm/sbus.h>
#include <asm/oplib.h>
#include <asm/fbio.h>
#include "sbuslib.h"
/*
* Local functions.
*/
static
int
cg6_check_var
(
struct
fb_var_screeninfo
*
,
struct
fb_info
*
);
static
int
cg6_set_par
(
struct
fb_info
*
);
static
int
cg6_setcolreg
(
unsigned
,
unsigned
,
unsigned
,
unsigned
,
unsigned
,
struct
fb_info
*
);
static
int
cg6_blank
(
int
,
struct
fb_info
*
);
static
void
cg6_imageblit
(
struct
fb_info
*
,
struct
fb_image
*
);
static
void
cg6_fillrect
(
struct
fb_info
*
,
struct
fb_fillrect
*
);
static
int
cg6_sync
(
struct
fb_info
*
);
static
int
cg6_mmap
(
struct
fb_info
*
,
struct
file
*
,
struct
vm_area_struct
*
);
/*
* Frame buffer operations
*/
static
struct
fb_ops
cg6_ops
=
{
.
owner
=
THIS_MODULE
,
.
fb_check_var
=
cg6_check_var
,
.
fb_set_par
=
cg6_set_par
,
.
fb_setcolreg
=
cg6_setcolreg
,
.
fb_blank
=
cg6_blank
,
.
fb_fillrect
=
cg6_fillrect
,
.
fb_copyarea
=
cfb_copyarea
,
.
fb_imageblit
=
cg6_imageblit
,
.
fb_sync
=
cg6_sync
,
.
fb_mmap
=
cg6_mmap
,
.
fb_cursor
=
soft_cursor
,
};
/* Offset of interesting structures in the OBIO space */
/*
...
...
@@ -128,8 +162,6 @@
#define CG6_THC_MISC_INT (1 << 4)
#define CG6_THC_MISC_INIT 0x9f
MODULE_LICENSE
(
"GPL"
);
/* The contents are unknown */
struct
cg6_tec
{
volatile
int
tec_matrix
;
...
...
@@ -210,430 +242,385 @@ struct cg6_fbc {
volatile
u32
rectr
,
rectg
,
rectb
,
recta
;
};
static
struct
sbus_mmap_map
cg6_mmap_map
[]
=
{
{
CG6_FBC
,
CG6_FBC_OFFSET
,
PAGE_SIZE
},
{
CG6_TEC
,
CG6_TEC_OFFSET
,
PAGE_SIZE
},
{
CG6_BTREGS
,
CG6_BROOKTREE_OFFSET
,
PAGE_SIZE
},
{
CG6_FHC
,
CG6_FHC_OFFSET
,
PAGE_SIZE
},
{
CG6_THC
,
CG6_THC_OFFSET
,
PAGE_SIZE
},
{
CG6_ROM
,
CG6_ROM_OFFSET
,
0x10000
},
{
CG6_RAM
,
CG6_RAM_OFFSET
,
SBUS_MMAP_FBSIZE
(
1
)
},
{
CG6_DHC
,
CG6_DHC_OFFSET
,
0x40000
},
{
0
,
0
,
0
}
struct
bt_regs
{
volatile
u32
addr
;
volatile
u32
color_map
;
volatile
u32
control
;
volatile
u32
cursor
;
};
static
void
cg6_setup
(
struct
display
*
p
)
{
p
->
next_line
=
p
->
fb_info
->
var
.
xres_virtual
;
p
->
next_plane
=
0
;
}
struct
cg6_par
{
spinlock_t
lock
;
struct
bt_regs
*
bt
;
struct
cg6_fbc
*
fbc
;
struct
cg6_thc
*
thc
;
struct
cg6_tec
*
tec
;
volatile
u32
*
fhc
;
u32
flags
;
#define CG6_FLAG_BLANKED 0x00000001
unsigned
long
physbase
;
unsigned
long
fbsize
;
static
void
cg6_clear
(
struct
vc_data
*
conp
,
struct
display
*
p
,
int
sy
,
int
sx
,
int
height
,
int
width
)
struct
sbus_dev
*
sdev
;
struct
list_head
list
;
};
static
int
cg6_sync
(
struct
fb_info
*
info
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
p
->
fb_info
);
register
struct
cg6_fbc
*
fbc
=
fb
->
s
.
cg6
.
fbc
;
unsigned
long
flags
;
int
x
,
y
,
w
,
h
;
int
i
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
do
{
i
=
sbus_readl
(
&
fbc
->
s
);
}
while
(
i
&
0x10000000
);
sbus_writel
(
attr_bgcol_ec
(
p
,
conp
),
&
fbc
->
fg
);
sbus_writel
(
attr_bgcol_ec
(
p
,
conp
),
&
fbc
->
bg
);
sbus_writel
(
~
0
,
&
fbc
->
pixelm
);
sbus_writel
(
0xea80ff00
,
&
fbc
->
alu
);
sbus_writel
(
0
,
&
fbc
->
s
);
sbus_writel
(
0
,
&
fbc
->
clip
);
sbus_writel
(
~
0
,
&
fbc
->
pm
);
struct
cg6_par
*
par
=
(
struct
cg6_par
*
)
info
->
par
;
struct
cg6_fbc
*
fbc
=
par
->
fbc
;
int
limit
=
10000
;
if
(
fontheightlog
(
p
))
{
y
=
sy
<<
fontheightlog
(
p
);
h
=
height
<<
fontheightlog
(
p
);
}
else
{
y
=
sy
*
fontheight
(
p
);
h
=
height
*
fontheight
(
p
);
}
if
(
fontwidthlog
(
p
))
{
x
=
sx
<<
fontwidthlog
(
p
);
w
=
width
<<
fontwidthlog
(
p
);
}
else
{
x
=
sx
*
fontwidth
(
p
);
w
=
width
*
fontwidth
(
p
);
}
sbus_writel
(
y
+
fb
->
y_margin
,
&
fbc
->
arecty
);
sbus_writel
(
x
+
fb
->
x_margin
,
&
fbc
->
arectx
);
sbus_writel
(
y
+
fb
->
y_margin
+
h
,
&
fbc
->
arecty
);
sbus_writel
(
x
+
fb
->
x_margin
+
w
,
&
fbc
->
arectx
);
do
{
i
=
sbus_readl
(
&
fbc
->
draw
);
}
while
(
i
<
0
&&
(
i
&
0x20000000
));
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
if
(
!
(
sbus_readl
(
&
fbc
->
s
)
&
0x10000000
))
break
;
udelay
(
10
);
}
while
(
--
limit
>
0
);
return
0
;
}
static
void
cg6_fill
(
struct
fb_info_sbusfb
*
fb
,
struct
display
*
p
,
int
s
,
int
count
,
unsigned
short
*
boxes
)
/**
* cg6_fillrect - REQUIRED function. Can use generic routines if
* non acclerated hardware and packed pixel based.
* Draws a rectangle on the screen.
*
* @info: frame buffer structure that represents a single frame buffer
* @rect: structure defining the rectagle and operation.
*/
static
void
cg6_fillrect
(
struct
fb_info
*
info
,
struct
fb_fillrect
*
rect
)
{
int
i
;
register
struct
cg6_fbc
*
fbc
=
fb
->
s
.
cg6
.
fbc
;
struct
cg6_par
*
par
=
(
struct
cg6_par
*
)
info
->
par
;
struct
cg6_fbc
*
fbc
=
par
->
fbc
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
do
{
i
=
sbus_readl
(
&
fbc
->
s
);
}
while
(
i
&
0x10000000
);
sbus_writel
(
attr_bgcol
(
p
,
s
),
&
fbc
->
fg
);
sbus_writel
(
attr_bgcol
(
p
,
s
),
&
fbc
->
b
g
);
sbus_writel
(
~
0
,
&
fbc
->
pixelm
);
s32
val
;
/* XXX doesn't handle ROP_XOR */
spin_lock_irqsave
(
&
par
->
lock
,
flags
);
cg6_sync
(
info
);
sbus_writel
(
rect
->
color
,
&
fbc
->
f
g
);
sbus_writel
(
~
(
u32
)
0
,
&
fbc
->
pixelm
);
sbus_writel
(
0xea80ff00
,
&
fbc
->
alu
);
sbus_writel
(
0
,
&
fbc
->
s
);
sbus_writel
(
0
,
&
fbc
->
clip
);
sbus_writel
(
~
0
,
&
fbc
->
pm
);
while
(
count
--
>
0
)
{
sbus_writel
(
boxes
[
1
],
&
fbc
->
arecty
);
sbus_writel
(
boxes
[
0
],
&
fbc
->
arectx
);
sbus_writel
(
boxes
[
3
],
&
fbc
->
arecty
);
sbus_writel
(
boxes
[
2
],
&
fbc
->
arectx
);
boxes
+=
4
;
do
{
i
=
sbus_readl
(
&
fbc
->
draw
);
}
while
(
i
<
0
&&
(
i
&
0x20000000
));
}
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
sbus_writel
(
~
(
u32
)
0
,
&
fbc
->
pm
);
sbus_writel
(
rect
->
dy
,
&
fbc
->
arecty
);
sbus_writel
(
rect
->
dx
,
&
fbc
->
arectx
);
sbus_writel
(
rect
->
dy
+
rect
->
height
,
&
fbc
->
arecty
);
sbus_writel
(
rect
->
dx
+
rect
->
width
,
&
fbc
->
arectx
);
do
{
val
=
sbus_readl
(
&
fbc
->
draw
);
}
while
(
val
<
0
&&
(
val
&
0x20000000
));
spin_unlock_irqrestore
(
&
par
->
lock
,
flags
);
}
static
void
cg6_putc
(
struct
vc_data
*
conp
,
struct
display
*
p
,
int
c
,
int
yy
,
int
xx
)
/**
* cg6_imageblit - REQUIRED function. Can use generic routines if
* non acclerated hardware and packed pixel based.
* Copies a image from system memory to the screen.
*
* @info: frame buffer structure that represents a single frame buffer
* @image: structure defining the image.
*/
static
void
cg6_imageblit
(
struct
fb_info
*
info
,
struct
fb_image
*
image
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
p
->
fb_info
);
register
struct
cg6_fbc
*
fbc
=
fb
->
s
.
cg6
.
fbc
;
struct
cg6_par
*
par
=
(
struct
cg6_par
*
)
info
->
par
;
struct
cg6_fbc
*
fbc
=
par
->
fbc
;
u8
*
data
=
image
->
data
;
unsigned
long
flags
;
int
i
,
x
,
y
;
u8
*
fd
;
u32
x
,
y
;
int
i
,
width
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
if
(
fontheightlog
(
p
))
{
y
=
fb
->
y_margin
+
(
yy
<<
fontheightlog
(
p
));
i
=
((
c
&
p
->
charmask
)
<<
fontheightlog
(
p
));
}
else
{
y
=
fb
->
y_margin
+
(
yy
*
fontheight
(
p
));
i
=
(
c
&
p
->
charmask
)
*
fontheight
(
p
);
if
(
image
->
depth
>
1
)
{
cfb_imageblit
(
info
,
image
);
return
;
}
if
(
fontwidth
(
p
)
<=
8
)
fd
=
p
->
fontdata
+
i
;
else
fd
=
p
->
fontdata
+
(
i
<<
1
);
if
(
fontwidthlog
(
p
))
x
=
fb
->
x_margin
+
(
xx
<<
fontwidthlog
(
p
));
else
x
=
fb
->
x_margin
+
(
xx
*
fontwidth
(
p
));
do
{
i
=
sbus_readl
(
&
fbc
->
s
);
}
while
(
i
&
0x10000000
);
sbus_writel
(
attr_fgcol
(
p
,
c
),
&
fbc
->
fg
);
sbus_writel
(
attr_bgcol
(
p
,
c
),
&
fbc
->
bg
);
sbus_writel
(
0x140000
,
&
fbc
->
mode
);
sbus_writel
(
0xe880fc30
,
&
fbc
->
alu
);
sbus_writel
(
~
0
,
&
fbc
->
pixelm
);
sbus_writel
(
0
,
&
fbc
->
s
);
sbus_writel
(
0
,
&
fbc
->
clip
);
sbus_writel
(
0xff
,
&
fbc
->
pm
);
sbus_writel
(
0
,
&
fbc
->
incx
);
sbus_writel
(
1
,
&
fbc
->
incy
);
sbus_writel
(
x
,
&
fbc
->
x0
);
sbus_writel
(
x
+
fontwidth
(
p
)
-
1
,
&
fbc
->
x1
);
sbus_writel
(
y
,
&
fbc
->
y0
);
if
(
fontwidth
(
p
)
<=
8
)
{
for
(
i
=
0
;
i
<
fontheight
(
p
);
i
++
)
{
u32
val
=
*
fd
++
<<
24
;
sbus_writel
(
val
,
&
fbc
->
font
);
}
}
else
{
for
(
i
=
0
;
i
<
fontheight
(
p
);
i
++
)
{
u32
val
=
*
(
u16
*
)
fd
<<
16
;
sbus_writel
(
val
,
&
fbc
->
font
);
fd
+=
2
;
}
}
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
}
spin_lock_irqsave
(
&
par
->
lock
,
flags
);
static
void
cg6_putcs
(
struct
vc_data
*
conp
,
struct
display
*
p
,
const
unsigned
short
*
s
,
int
count
,
int
yy
,
int
xx
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
p
->
fb_info
);
register
struct
cg6_fbc
*
fbc
=
fb
->
s
.
cg6
.
fbc
;
unsigned
long
flags
;
int
i
,
x
,
y
;
u8
*
fd1
,
*
fd2
,
*
fd3
,
*
fd4
;
u16
c
;
cg6_sync
(
info
);
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
do
{
i
=
sbus_readl
(
&
fbc
->
s
);
}
while
(
i
&
0x10000000
);
c
=
scr_readw
(
s
);
sbus_writel
(
attr_fgcol
(
p
,
c
),
&
fbc
->
fg
);
sbus_writel
(
attr_bgcol
(
p
,
c
),
&
fbc
->
bg
);
sbus_writel
(
image
->
fg_color
,
&
fbc
->
fg
);
sbus_writel
(
image
->
bg_color
,
&
fbc
->
bg
);
sbus_writel
(
0x140000
,
&
fbc
->
mode
);
sbus_writel
(
0xe880fc30
,
&
fbc
->
alu
);
sbus_writel
(
~
0
,
&
fbc
->
pixelm
);
sbus_writel
(
~
(
u32
)
0
,
&
fbc
->
pixelm
);
sbus_writel
(
0
,
&
fbc
->
s
);
sbus_writel
(
0
,
&
fbc
->
clip
);
sbus_writel
(
0xff
,
&
fbc
->
pm
);
x
=
fb
->
x_margin
;
y
=
fb
->
y_margin
;
if
(
fontwidthlog
(
p
))
x
+=
(
xx
<<
fontwidthlog
(
p
));
else
x
+=
xx
*
fontwidth
(
p
);
if
(
fontheightlog
(
p
))
y
+=
(
yy
<<
fontheightlog
(
p
));
else
y
+=
(
yy
*
fontheight
(
p
));
if
(
fontwidth
(
p
)
<=
8
)
{
while
(
count
>=
4
)
{
count
-=
4
;
sbus_writel
(
0
,
&
fbc
->
incx
);
sbus_writel
(
1
,
&
fbc
->
incy
);
sbus_writel
(
x
,
&
fbc
->
x0
);
sbus_writel
((
x
+=
4
*
fontwidth
(
p
))
-
1
,
&
fbc
->
x1
);
sbus_writel
(
32
,
&
fbc
->
incx
);
sbus_writel
(
0
,
&
fbc
->
incy
);
x
=
image
->
dx
;
y
=
image
->
dy
;
for
(
i
=
0
;
i
<
image
->
height
;
i
++
)
{
width
=
image
->
width
;
while
(
width
>=
32
)
{
u32
val
;
sbus_writel
(
y
,
&
fbc
->
y0
);
if
(
fontheightlog
(
p
))
{
fd1
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
<<
fontheightlog
(
p
));
fd2
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
<<
fontheightlog
(
p
));
fd3
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
<<
fontheightlog
(
p
));
fd4
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
<<
fontheightlog
(
p
));
}
else
{
fd1
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
*
fontheight
(
p
));
fd2
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
*
fontheight
(
p
));
fd3
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
*
fontheight
(
p
));
fd4
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
*
fontheight
(
p
));
}
if
(
fontwidth
(
p
)
==
8
)
{
for
(
i
=
0
;
i
<
fontheight
(
p
);
i
++
)
{
u32
val
=
((
u32
)
*
fd4
++
)
|
((((
u32
)
*
fd3
++
)
|
((((
u32
)
*
fd2
++
)
|
(((
u32
)
*
fd1
++
)
<<
8
))
<<
8
))
<<
8
);
sbus_writel
(
val
,
&
fbc
->
font
);
}
}
else
{
for
(
i
=
0
;
i
<
fontheight
(
p
);
i
++
)
{
u32
val
=
(((
u32
)
*
fd4
++
)
|
((((
u32
)
*
fd3
++
)
|
((((
u32
)
*
fd2
++
)
|
(((
u32
)
*
fd1
++
)
<<
fontwidth
(
p
)))
<<
fontwidth
(
p
)))
<<
fontwidth
(
p
)))
<<
(
24
-
3
*
fontwidth
(
p
));
sbus_writel
(
val
,
&
fbc
->
font
);
}
}
}
}
else
{
while
(
count
>=
2
)
{
count
-=
2
;
sbus_writel
(
0
,
&
fbc
->
incx
);
sbus_writel
(
1
,
&
fbc
->
incy
);
sbus_writel
(
x
,
&
fbc
->
x0
);
sbus_writel
((
x
+=
2
*
fontwidth
(
p
))
-
1
,
&
fbc
->
x1
);
sbus_writel
(
x
+
32
-
1
,
&
fbc
->
x1
);
val
=
((
u32
)
data
[
0
]
<<
24
)
|
((
u32
)
data
[
1
]
<<
16
)
|
((
u32
)
data
[
2
]
<<
8
)
|
((
u32
)
data
[
3
]
<<
0
);
sbus_writel
(
val
,
&
fbc
->
font
);
data
+=
4
;
x
+=
32
;
width
-=
32
;
}
if
(
width
)
{
u32
val
;
sbus_writel
(
y
,
&
fbc
->
y0
);
if
(
fontheightlog
(
p
))
{
fd1
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
<<
(
fontheightlog
(
p
)
+
1
));
fd2
=
p
->
fontdata
+
((
scr_readw
(
s
++
)
&
p
->
charmask
)
<<
(
fontheightlog
(
p
)
+
1
));
sbus_writel
(
x
,
&
fbc
->
x0
);
sbus_writel
(
x
+
width
-
1
,
&
fbc
->
x1
);
if
(
width
<=
8
)
{
val
=
(
u32
)
data
[
0
]
<<
24
;
data
+=
1
;
}
else
if
(
width
<=
16
)
{
val
=
((
u32
)
data
[
0
]
<<
24
)
|
((
u32
)
data
[
1
]
<<
16
);
data
+=
2
;
}
else
{
fd1
=
p
->
fontdata
+
(((
scr_readw
(
s
++
)
&
p
->
charmask
)
*
fontheight
(
p
))
<<
1
);
fd2
=
p
->
fontdata
+
(((
scr_readw
(
s
++
)
&
p
->
charmask
)
*
fontheight
(
p
))
<<
1
);
}
for
(
i
=
0
;
i
<
fontheight
(
p
);
i
++
)
{
u32
val
=
((((
u32
)
*
(
u16
*
)
fd1
)
<<
fontwidth
(
p
))
|
((
u32
)
*
(
u16
*
)
fd2
))
<<
(
16
-
fontwidth
(
p
));
sbus_writel
(
val
,
&
fbc
->
font
);
fd1
+=
2
;
fd2
+=
2
;
}
}
}
while
(
count
)
{
count
--
;
sbus_writel
(
0
,
&
fbc
->
incx
);
sbus_writel
(
1
,
&
fbc
->
incy
);
sbus_writel
(
x
,
&
fbc
->
x0
);
sbus_writel
((
x
+=
fontwidth
(
p
))
-
1
,
&
fbc
->
x1
);
sbus_writel
(
y
,
&
fbc
->
y0
);
if
(
fontheightlog
(
p
))
i
=
((
scr_readw
(
s
++
)
&
p
->
charmask
)
<<
fontheightlog
(
p
));
else
i
=
((
scr_readw
(
s
++
)
&
p
->
charmask
)
*
fontheight
(
p
));
if
(
fontwidth
(
p
)
<=
8
)
{
fd1
=
p
->
fontdata
+
i
;
for
(
i
=
0
;
i
<
fontheight
(
p
);
i
++
)
{
u32
val
=
*
fd1
++
<<
24
;
sbus_writel
(
val
,
&
fbc
->
font
);
}
}
else
{
fd1
=
p
->
fontdata
+
(
i
<<
1
);
for
(
i
=
0
;
i
<
fontheight
(
p
);
i
++
)
{
u32
val
=
*
(
u16
*
)
fd1
<<
16
;
sbus_writel
(
val
,
&
fbc
->
font
);
fd1
+=
2
;
val
=
((
u32
)
data
[
0
]
<<
24
)
|
((
u32
)
data
[
1
]
<<
16
)
|
((
u32
)
data
[
2
]
<<
8
);
data
+=
3
;
}
sbus_writel
(
val
,
&
fbc
->
font
);
}
y
+=
1
;
x
=
image
->
dx
;
}
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
par
->
lock
,
flags
);
}
static
void
cg6_revc
(
struct
display
*
p
,
int
xx
,
int
yy
)
/**
* cg6_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
cg6_check_var
(
struct
fb_var_screeninfo
*
var
,
struct
fb_info
*
info
)
{
/* Not used if hw cursor */
if
(
var
->
bits_per_pixel
!=
8
)
return
-
EINVAL
;
if
(
var
->
xres_virtual
!=
var
->
xres
||
var
->
yres_virtual
!=
var
->
yres
)
return
-
EINVAL
;
if
(
var
->
nonstd
)
return
-
EINVAL
;
if
((
var
->
vmode
&
FB_VMODE_MASK
)
!=
FB_VMODE_NONINTERLACED
)
return
-
EINVAL
;
if
(
var
->
xres
!=
info
->
var
.
xres
||
var
->
yres
!=
info
->
var
.
yres
)
return
-
EINVAL
;
return
0
;
}
static
void
cg6_loadcmap
(
struct
fb_info_sbusfb
*
fb
,
struct
display
*
p
,
int
index
,
int
count
)
/**
* cg6_set_par - Optional function. Alters the hardware state.
* @info: frame buffer structure that represents a single frame buffer
*/
static
int
cg6_set_par
(
struct
fb_info
*
info
)
{
struct
bt_regs
*
bt
=
fb
->
s
.
cg6
.
bt
;
unsigned
long
flags
;
int
i
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
sbus_writel
(
index
<<
24
,
&
bt
->
addr
);
for
(
i
=
index
;
count
--
;
i
++
){
sbus_writel
(
fb
->
color_map
CM
(
i
,
0
)
<<
24
,
&
bt
->
color_map
);
sbus_writel
(
fb
->
color_map
CM
(
i
,
1
)
<<
24
,
&
bt
->
color_map
);
sbus_writel
(
fb
->
color_map
CM
(
i
,
2
)
<<
24
,
&
bt
->
color_map
);
}
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
return
0
;
}
static
void
cg6_restore_palette
(
struct
fb_info_sbusfb
*
fb
)
/**
* cg6_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
cg6_setcolreg
(
unsigned
regno
,
unsigned
red
,
unsigned
green
,
unsigned
blue
,
unsigned
transp
,
struct
fb_info
*
info
)
{
struct
bt_regs
*
bt
=
fb
->
s
.
cg6
.
bt
;
struct
cg6_par
*
par
=
(
struct
cg6_par
*
)
info
->
par
;
struct
bt_regs
*
bt
=
par
->
bt
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
sbus_writel
(
0
,
&
bt
->
addr
);
sbus_writel
(
0xffffffff
,
&
bt
->
color_map
);
sbus_writel
(
0xffffffff
,
&
bt
->
color_map
);
sbus_writel
(
0xffffffff
,
&
bt
->
color_map
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
}
static
struct
display_switch
cg6_dispsw
__initdata
=
{
.
setup
=
cg6_setup
,
.
bmove
=
fbcon_redraw_bmove
,
.
clear
=
cg6_clear
,
.
putc
=
cg6_putc
,
.
putcs
=
cg6_putcs
,
.
revc
=
cg6_revc
,
.
fontwidthmask
=
FONTWIDTHRANGE
(
1
,
16
)
/* Allow fontwidths up to 16 */
};
if
(
regno
>=
256
)
return
1
;
static
void
cg6_setcursormap
(
struct
fb_info_sbusfb
*
fb
,
u8
*
red
,
u8
*
green
,
u8
*
blue
)
{
struct
bt_regs
*
bt
=
fb
->
s
.
cg6
.
bt
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
sbus_writel
(
1
<<
24
,
&
bt
->
addr
);
sbus_writel
(
red
[
0
]
<<
24
,
&
bt
->
cursor
);
sbus_writel
(
green
[
0
]
<<
24
,
&
bt
->
cursor
);
sbus_writel
(
blue
[
0
]
<<
24
,
&
bt
->
cursor
);
sbus_writel
(
3
<<
24
,
&
bt
->
addr
);
sbus_writel
(
red
[
1
]
<<
24
,
&
bt
->
cursor
);
sbus_writel
(
green
[
1
]
<<
24
,
&
bt
->
cursor
);
sbus_writel
(
blue
[
1
]
<<
24
,
&
bt
->
cursor
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
red
>>=
8
;
green
>>=
8
;
blue
>>=
8
;
spin_lock_irqsave
(
&
par
->
lock
,
flags
);
sbus_writel
((
u32
)
regno
<<
24
,
&
bt
->
addr
);
sbus_writel
((
u32
)
red
<<
24
,
&
bt
->
color_map
);
sbus_writel
((
u32
)
green
<<
24
,
&
bt
->
color_map
);
sbus_writel
((
u32
)
blue
<<
24
,
&
bt
->
color_map
);
spin_unlock_irqrestore
(
&
par
->
lock
,
flags
);
return
0
;
}
/* Set cursor shape */
static
void
cg6_setcurshape
(
struct
fb_info_sbusfb
*
fb
)
/**
* cg6_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
cg6_blank
(
int
blank
,
struct
fb_info
*
info
)
{
struct
cg6_thc
*
thc
=
fb
->
s
.
cg6
.
thc
;
struct
cg6_par
*
par
=
(
struct
cg6_par
*
)
info
->
par
;
struct
cg6_thc
*
thc
=
par
->
thc
;
unsigned
long
flags
;
int
i
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
for
(
i
=
0
;
i
<
32
;
i
++
)
{
sbus_writel
(
fb
->
cursor
.
bits
[
0
][
i
],
&
thc
->
thc_cursmask
[
i
]);
sbus_writel
(
fb
->
cursor
.
bits
[
1
][
i
],
&
thc
->
thc_cursbits
[
i
]);
u32
val
;
spin_lock_irqsave
(
&
par
->
lock
,
flags
);
switch
(
blank
)
{
case
0
:
/* Unblanking */
val
=
sbus_readl
(
&
thc
->
thc_misc
);
val
|=
CG6_THC_MISC_VIDEO
;
sbus_writel
(
val
,
&
thc
->
thc_misc
);
par
->
flags
&=
~
CG6_FLAG_BLANKED
;
break
;
case
1
:
/* Normal blanking */
case
2
:
/* VESA blank (vsync off) */
case
3
:
/* VESA blank (hsync off) */
case
4
:
/* Poweroff */
val
=
sbus_readl
(
&
thc
->
thc_misc
);
val
&=
~
CG6_THC_MISC_VIDEO
;
sbus_writel
(
val
,
&
thc
->
thc_misc
);
par
->
flags
|=
CG6_FLAG_BLANKED
;
break
;
}
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
par
->
lock
,
flags
);
return
0
;
}
/* Load cursor information */
static
void
cg6_setcursor
(
struct
fb_info_sbusfb
*
fb
)
static
struct
sbus_mmap_map
cg6_mmap_map
[]
=
{
{
CG6_FBC
,
CG6_FBC_OFFSET
,
PAGE_SIZE
},
{
CG6_TEC
,
CG6_TEC_OFFSET
,
PAGE_SIZE
},
{
CG6_BTREGS
,
CG6_BROOKTREE_OFFSET
,
PAGE_SIZE
},
{
CG6_FHC
,
CG6_FHC_OFFSET
,
PAGE_SIZE
},
{
CG6_THC
,
CG6_THC_OFFSET
,
PAGE_SIZE
},
{
CG6_ROM
,
CG6_ROM_OFFSET
,
0x10000
},
{
CG6_RAM
,
CG6_RAM_OFFSET
,
SBUS_MMAP_FBSIZE
(
1
)
},
{
CG6_DHC
,
CG6_DHC_OFFSET
,
0x40000
},
{
0
,
0
,
0
}
};
static
int
cg6_mmap
(
struct
fb_info
*
info
,
struct
file
*
file
,
struct
vm_area_struct
*
vma
)
{
unsigned
int
v
;
unsigned
long
flags
;
struct
cg_cursor
*
c
=
&
fb
->
cursor
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
if
(
c
->
enable
)
v
=
((
c
->
cpos
.
fbx
-
c
->
chot
.
fbx
)
<<
16
)
|
((
c
->
cpos
.
fby
-
c
->
chot
.
fby
)
&
0xffff
);
else
/* Magic constant to turn off the cursor */
v
=
((
65536
-
32
)
<<
16
)
|
(
65536
-
32
);
sbus_writel
(
v
,
&
fb
->
s
.
cg6
.
thc
->
thc_cursxy
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
struct
cg6_par
*
par
=
(
struct
cg6_par
*
)
info
->
par
;
return
sbusfb_mmap_helper
(
cg6_mmap_map
,
par
->
physbase
,
par
->
fbsize
,
par
->
sdev
->
reg_addrs
[
0
].
which_io
,
vma
);
}
static
int
cg6_blank
(
struct
fb_info_sbusfb
*
fb
)
/*
* Initialisation
*/
static
void
cg6_init_fix
(
struct
fb_info
*
info
,
int
linebytes
)
{
unsigned
long
flags
;
u32
tmp
;
struct
cg6_par
*
par
=
(
struct
cg6_par
*
)
info
->
par
;
const
char
*
cg6_cpu_name
,
*
cg6_card_name
;
u32
conf
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
tmp
=
sbus_readl
(
&
fb
->
s
.
cg6
.
thc
->
thc_misc
);
tmp
&=
~
CG6_THC_MISC_VIDEO
;
sbus_writel
(
tmp
,
&
fb
->
s
.
cg6
.
thc
->
thc_misc
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
return
0
;
conf
=
sbus_readl
(
par
->
fhc
);
switch
(
conf
&
CG6_FHC_CPU_MASK
)
{
case
CG6_FHC_CPU_SPARC
:
cg6_cpu_name
=
"sparc"
;
break
;
case
CG6_FHC_CPU_68020
:
cg6_cpu_name
=
"68020"
;
break
;
default:
cg6_cpu_name
=
"i386"
;
break
;
};
if
(((
conf
>>
CG6_FHC_REV_SHIFT
)
&
CG6_FHC_REV_MASK
)
>=
11
)
{
if
(
par
->
fbsize
<=
0x100000
)
{
cg6_card_name
=
"TGX"
;
}
else
{
cg6_card_name
=
"TGX+"
;
}
}
else
{
if
(
par
->
fbsize
<=
0x100000
)
{
cg6_card_name
=
"GX"
;
}
else
{
cg6_card_name
=
"GX+"
;
}
}
sprintf
(
info
->
fix
.
id
,
"%s %s"
,
cg6_card_name
,
cg6_cpu_name
);
info
->
fix
.
id
[
sizeof
(
info
->
fix
.
id
)
-
1
]
=
0
;
info
->
fix
.
type
=
FB_TYPE_PACKED_PIXELS
;
info
->
fix
.
visual
=
FB_VISUAL_PSEUDOCOLOR
;
info
->
fix
.
line_length
=
linebytes
;
info
->
fix
.
accel
=
FB_ACCEL_SUN_CGSIX
;
}
static
int
cg6_unblank
(
struct
fb_info_sbusfb
*
fb
)
/* Initialize Brooktree DAC */
static
void
cg6_bt_init
(
struct
cg6_par
*
par
)
{
unsigned
long
flags
;
u32
tmp
;
struct
bt_regs
*
bt
=
par
->
bt
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
tmp
=
sbus_readl
(
&
fb
->
s
.
cg6
.
thc
->
thc_misc
);
tmp
|=
CG6_THC_MISC_VIDEO
;
sbus_writel
(
tmp
,
&
fb
->
s
.
cg6
.
thc
->
thc_misc
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
return
0
;
sbus_writel
(
0x04
<<
24
,
&
bt
->
addr
);
/* color planes */
sbus_writel
(
0xff
<<
24
,
&
bt
->
control
);
sbus_writel
(
0x05
<<
24
,
&
bt
->
addr
);
sbus_writel
(
0x00
<<
24
,
&
bt
->
control
);
sbus_writel
(
0x06
<<
24
,
&
bt
->
addr
);
/* overlay plane */
sbus_writel
(
0x73
<<
24
,
&
bt
->
control
);
sbus_writel
(
0x07
<<
24
,
&
bt
->
addr
);
sbus_writel
(
0x00
<<
24
,
&
bt
->
control
);
}
static
void
cg6_
reset
(
struct
fb_info_sbusfb
*
fb
)
static
void
cg6_
chip_init
(
struct
fb_info
*
info
)
{
unsigned
int
rev
,
conf
;
struct
cg6_tec
*
tec
=
fb
->
s
.
cg6
.
tec
;
struct
cg6_fbc
*
fbc
=
fb
->
s
.
cg6
.
fbc
;
unsigned
long
flags
;
u32
mode
,
tmp
;
struct
cg6_par
*
par
=
(
struct
cg6_par
*
)
info
->
par
;
struct
cg6_tec
*
tec
=
par
->
tec
;
struct
cg6_fbc
*
fbc
=
par
->
fbc
;
u32
rev
,
conf
,
mode
,
tmp
;
int
i
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
/* Turn off stuff in the Transform Engine. */
sbus_writel
(
0
,
&
tec
->
tec_matrix
);
sbus_writel
(
0
,
&
tec
->
tec_clip
);
sbus_writel
(
0
,
&
tec
->
tec_vdc
);
/* Take care of bugs in old revisions. */
rev
=
(
sbus_readl
(
fb
->
s
.
cg6
.
fhc
)
>>
CG6_FHC_REV_SHIFT
)
&
CG6_FHC_REV_MASK
;
rev
=
(
sbus_readl
(
par
->
fhc
)
>>
CG6_FHC_REV_SHIFT
)
&
CG6_FHC_REV_MASK
;
if
(
rev
<
5
)
{
conf
=
(
sbus_readl
(
fb
->
s
.
cg6
.
fhc
)
&
CG6_FHC_RES_MASK
)
|
conf
=
(
sbus_readl
(
par
->
fhc
)
&
CG6_FHC_RES_MASK
)
|
CG6_FHC_CPU_68020
|
CG6_FHC_TEST
|
(
11
<<
CG6_FHC_TEST_X_SHIFT
)
|
(
11
<<
CG6_FHC_TEST_Y_SHIFT
);
if
(
rev
<
2
)
conf
|=
CG6_FHC_DST_DISABLE
;
sbus_writel
(
conf
,
fb
->
s
.
cg6
.
fhc
);
sbus_writel
(
conf
,
par
->
fhc
);
}
/* Set things in the FBC. Bad things appear to happen if we do
...
...
@@ -658,167 +645,149 @@ static void cg6_reset (struct fb_info_sbusfb *fb)
sbus_writel
(
0
,
&
fbc
->
offy
);
sbus_writel
(
0
,
&
fbc
->
clipminx
);
sbus_writel
(
0
,
&
fbc
->
clipminy
);
sbus_writel
(
fb
->
type
.
fb_width
-
1
,
&
fbc
->
clipmaxx
);
sbus_writel
(
fb
->
type
.
fb_height
-
1
,
&
fbc
->
clipmaxy
);
/* Enable cursor in Brooktree DAC. */
sbus_writel
(
0x06
<<
24
,
&
fb
->
s
.
cg6
.
bt
->
addr
);
tmp
=
sbus_readl
(
&
fb
->
s
.
cg6
.
bt
->
control
);
tmp
|=
0x03
<<
24
;
sbus_writel
(
tmp
,
&
fb
->
s
.
cg6
.
bt
->
control
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
sbus_writel
(
info
->
var
.
xres
-
1
,
&
fbc
->
clipmaxx
);
sbus_writel
(
info
->
var
.
yres
-
1
,
&
fbc
->
clipmaxy
);
/* Disable cursor in Brooktree DAC. */
sbus_writel
(
0x06
<<
24
,
&
par
->
bt
->
addr
);
tmp
=
sbus_readl
(
&
par
->
bt
->
control
);
tmp
&=
~
(
0x03
<<
24
);
sbus_writel
(
tmp
,
&
par
->
bt
->
control
);
}
static
void
cg6_margins
(
struct
fb_info_sbusfb
*
fb
,
struct
display
*
p
,
int
x_margin
,
int
y_margin
)
{
fb
->
info
.
screen_base
+=
(
y_margin
-
fb
->
y_margin
)
*
fb
->
info
.
fix
.
line_length
+
(
x_margin
-
fb
->
x_margin
);
}
struct
all_info
{
struct
fb_info
info
;
struct
cg6_par
par
;
struct
list_head
list
;
};
static
LIST_HEAD
(
cg6_list
);
static
int
__init
cg6_rasterimg
(
struct
fb_info
*
info
,
int
start
)
static
void
cg6_init_one
(
struct
sbus_dev
*
sdev
)
{
struct
fb_info_sbusfb
*
fb
=
sbusfbinfo
(
info
);
register
struct
cg6_fbc
*
fbc
=
fb
->
s
.
cg6
.
fbc
;
int
i
;
do
{
i
=
sbus_readl
(
&
fbc
->
s
);
}
while
(
i
&
0x10000000
);
return
0
;
}
struct
all_info
*
all
;
int
linebytes
;
static
char
idstring
[
70
]
__initdata
=
{
0
};
char
__init
*
cgsixfb_init
(
struct
fb_info_sbusfb
*
fb
)
{
struct
fb_fix_screeninfo
*
fix
=
&
fb
->
info
.
fix
;
struct
fb_var_screeninfo
*
var
=
&
fb
->
info
.
var
;
struct
display
*
disp
=
&
fb
->
disp
;
struct
fbtype
*
type
=
&
fb
->
type
;
struct
sbus_dev
*
sdev
=
fb
->
sbdp
;
unsigned
long
phys
=
sdev
->
reg_addrs
[
0
].
phys_addr
;
u32
conf
;
char
*
p
;
char
*
cardtype
;
struct
bt_regs
*
bt
;
struct
fb_ops
*
fbops
;
fbops
=
kmalloc
(
sizeof
(
*
fbops
),
GFP_KERNEL
);
if
(
fbops
==
NULL
)
return
NULL
;
*
fbops
=
*
fb
->
info
.
fbops
;
fbops
->
fb_rasterimg
=
cg6_rasterimg
;
fb
->
info
.
fbops
=
fbops
;
if
(
prom_getbool
(
fb
->
prom_node
,
"dblbuf"
))
{
type
->
fb_size
*=
4
;
fix
->
smem_len
*=
4
;
all
=
kmalloc
(
sizeof
(
*
all
),
GFP_KERNEL
);
if
(
!
all
)
{
printk
(
KERN_ERR
"cg6: Cannot allocate memory.
\n
"
);
return
;
}
memset
(
all
,
0
,
sizeof
(
*
all
));
fix
->
line_length
=
fb
->
info
.
var
.
xres_virtual
;
fix
->
accel
=
FB_ACCEL_SUN_CGSIX
;
var
->
accel_flags
=
FB_ACCELF_TEXT
;
disp
->
scrollmode
=
SCROLL_YREDRAW
;
if
(
!
fb
->
info
.
screen_base
)
{
fb
->
info
.
screen_base
=
(
char
*
)
sbus_ioremap
(
&
sdev
->
resource
[
0
],
CG6_RAM_OFFSET
,
type
->
fb_size
,
"cgsix ram"
);
}
fb
->
info
.
screen_base
+=
fix
->
line_length
*
fb
->
y_margin
+
fb
->
x_margin
;
fb
->
s
.
cg6
.
fbc
=
(
struct
cg6_fbc
*
)
INIT_LIST_HEAD
(
&
all
->
list
);
spin_lock_init
(
&
all
->
par
.
lock
);
all
->
par
.
sdev
=
sdev
;
all
->
par
.
physbase
=
sdev
->
reg_addrs
[
0
].
phys_addr
;
sbusfb_fill_var
(
&
all
->
info
.
var
,
sdev
->
prom_node
,
8
);
linebytes
=
prom_getintdefault
(
sdev
->
prom_node
,
"linebytes"
,
all
->
info
.
var
.
xres
);
all
->
par
.
fbsize
=
PAGE_ALIGN
(
linebytes
*
all
->
info
.
var
.
yres
);
if
(
prom_getbool
(
sdev
->
prom_node
,
"dblbuf"
))
all
->
par
.
fbsize
*=
4
;
all
->
par
.
fbc
=
(
struct
cg6_fbc
*
)
sbus_ioremap
(
&
sdev
->
resource
[
0
],
CG6_FBC_OFFSET
,
4096
,
"cgsix fbc"
);
fb
->
s
.
cg6
.
tec
=
(
struct
cg6_tec
*
)
all
->
par
.
tec
=
(
struct
cg6_tec
*
)
sbus_ioremap
(
&
sdev
->
resource
[
0
],
CG6_TEC_OFFSET
,
sizeof
(
struct
cg6_tec
),
"cgsix tec"
);
fb
->
s
.
cg6
.
thc
=
(
struct
cg6_thc
*
)
all
->
par
.
thc
=
(
struct
cg6_thc
*
)
sbus_ioremap
(
&
sdev
->
resource
[
0
],
CG6_THC_OFFSET
,
sizeof
(
struct
cg6_thc
),
"cgsix thc"
);
fb
->
s
.
cg6
.
bt
=
bt
=
(
struct
bt_regs
*
)
all
->
par
.
bt
=
(
struct
bt_regs
*
)
sbus_ioremap
(
&
sdev
->
resource
[
0
],
CG6_BROOKTREE_OFFSET
,
sizeof
(
struct
bt_regs
),
"cgsix dac"
);
fb
->
s
.
cg6
.
fhc
=
(
u32
*
)
all
->
par
.
fhc
=
(
u32
*
)
sbus_ioremap
(
&
sdev
->
resource
[
0
],
CG6_FHC_OFFSET
,
sizeof
(
u32
),
"cgsix fhc"
);
#if 0
prom_printf("CG6: RES[%016lx:%016lx:%016lx]\n",
sdev->resource[0].start,
sdev->resource[0].end,
sdev->resource[0].flags);
prom_printf("CG6: fbc(%p) tec(%p) thc(%p) bt(%p) fhc(%p)\n",
fb->s.cg6.fbc,
fb->s.cg6.tec,
fb->s.cg6.thc,
fb->s.cg6.bt,
fb->s.cg6.fhc);
prom_halt();
all
->
info
.
node
=
NODEV
;
all
->
info
.
flags
=
FBINFO_FLAG_DEFAULT
;
all
->
info
.
fbops
=
&
cg6_ops
;
#ifdef CONFIG_SPARC32
all
->
info
.
screen_base
=
(
char
*
)
prom_getintdefault
(
sdev
->
prom_node
,
"address"
,
0
);
#endif
fb
->
dispsw
=
cg6_dispsw
;
fb
->
margins
=
cg6_margins
;
fb
->
loadcmap
=
cg6_loadcmap
;
fb
->
setcursor
=
cg6_setcursor
;
fb
->
setcursormap
=
cg6_setcursormap
;
fb
->
setcurshape
=
cg6_setcurshape
;
fb
->
restore_palette
=
cg6_restore_palette
;
fb
->
fill
=
cg6_fill
;
fb
->
blank
=
cg6_blank
;
fb
->
unblank
=
cg6_unblank
;
fb
->
reset
=
cg6_reset
;
fb
->
physbase
=
phys
;
fb
->
mmap_map
=
cg6_mmap_map
;
/* Initialize Brooktree DAC */
sbus_writel
(
0x04
<<
24
,
&
bt
->
addr
);
/* color planes */
sbus_writel
(
0xff
<<
24
,
&
bt
->
control
);
sbus_writel
(
0x05
<<
24
,
&
bt
->
addr
);
sbus_writel
(
0x00
<<
24
,
&
bt
->
control
);
sbus_writel
(
0x06
<<
24
,
&
bt
->
addr
);
/* overlay plane */
sbus_writel
(
0x73
<<
24
,
&
bt
->
control
);
sbus_writel
(
0x07
<<
24
,
&
bt
->
addr
);
sbus_writel
(
0x00
<<
24
,
&
bt
->
control
);
conf
=
sbus_readl
(
fb
->
s
.
cg6
.
fhc
);
switch
(
conf
&
CG6_FHC_CPU_MASK
)
{
case
CG6_FHC_CPU_SPARC
:
p
=
"sparc"
;
break
;
case
CG6_FHC_CPU_68020
:
p
=
"68020"
;
break
;
default:
p
=
"i386"
;
break
;
if
(
!
all
->
info
.
screen_base
)
all
->
info
.
screen_base
=
(
char
*
)
sbus_ioremap
(
&
sdev
->
resource
[
0
],
CG6_RAM_OFFSET
,
all
->
par
.
fbsize
,
"cgsix ram"
);
all
->
info
.
currcon
=
-
1
;
all
->
info
.
par
=
&
all
->
par
;
all
->
info
.
var
.
accel_flags
=
FB_ACCELF_TEXT
;
cg6_bt_init
(
&
all
->
par
);
cg6_chip_init
(
&
all
->
info
);
cg6_blank
(
0
,
&
all
->
info
);
if
(
fb_alloc_cmap
(
&
all
->
info
.
cmap
,
256
,
0
))
{
printk
(
KERN_ERR
"cg6: Could not allocate color map.
\n
"
);
kfree
(
all
);
return
;
}
if
(((
conf
>>
CG6_FHC_REV_SHIFT
)
&
CG6_FHC_REV_MASK
)
>=
11
)
{
if
(
fix
->
smem_len
<=
0x100000
)
{
cardtype
=
"TGX"
;
}
else
{
cardtype
=
"TGX+"
;
}
}
else
{
if
(
fix
->
smem_len
<=
0x100000
)
{
cardtype
=
"GX"
;
}
else
{
cardtype
=
"GX+"
;
}
cg6_set_par
(
&
all
->
info
);
cg6_init_fix
(
&
all
->
info
,
linebytes
);
if
(
register_framebuffer
(
&
all
->
info
)
<
0
)
{
printk
(
KERN_ERR
"cg6: Could not register framebuffer.
\n
"
);
fb_dealloc_cmap
(
&
all
->
info
.
cmap
);
kfree
(
all
);
return
;
}
sprintf
(
idstring
,
#ifdef __sparc_v9__
"cgsix at %016lx TEC Rev %x CPU %s Rev %x [%s]"
,
phys
,
#else
"cgsix at %x.%08lx TEC Rev %x CPU %s Rev %x [%s]"
,
fb
->
iospace
,
phys
,
#endif
((
sbus_readl
(
&
fb
->
s
.
cg6
.
thc
->
thc_misc
)
>>
CG6_THC_MISC_REV_SHIFT
)
&
CG6_THC_MISC_REV_MASK
),
p
,
(
conf
>>
CG6_FHC_REV_SHIFT
)
&
CG6_FHC_REV_MASK
,
cardtype
);
sprintf
(
fb
->
info
.
modename
,
"CGsix [%s]"
,
cardtype
);
sprintf
(
fix
->
id
,
"CGsix [%s]"
,
cardtype
);
cg6_reset
(
fb
);
return
idstring
;
list_add
(
&
all
->
list
,
&
cg6_list
);
printk
(
"cg6: CGsix [%s] at %lx:%lx
\n
"
,
all
->
info
.
fix
.
id
,
(
long
)
sdev
->
reg_addrs
[
0
].
which_io
,
(
long
)
sdev
->
reg_addrs
[
0
].
phys_addr
);
}
int
__init
cg6_init
(
void
)
{
struct
sbus_bus
*
sbus
;
struct
sbus_dev
*
sdev
;
for_all_sbusdev
(
sdev
,
sbus
)
{
if
(
!
strcmp
(
sdev
->
prom_name
,
"cgsix"
)
||
!
strcmp
(
sdev
->
prom_name
,
"cgthree+"
))
cg6_init_one
(
sdev
);
}
return
0
;
}
void
__exit
cg6_exit
(
void
)
{
struct
list_head
*
pos
,
*
tmp
;
list_for_each_safe
(
pos
,
tmp
,
&
cg6_list
)
{
struct
all_info
*
all
=
list_entry
(
pos
,
typeof
(
*
all
),
list
);
unregister_framebuffer
(
&
all
->
info
);
fb_dealloc_cmap
(
&
all
->
info
.
cmap
);
kfree
(
all
);
}
}
int
__init
cg6_setup
(
char
*
arg
)
{
/* No cmdline options yet... */
return
0
;
}
#ifdef MODULE
module_init
(
cg6_init
);
module_exit
(
cg6_exit
);
#endif
MODULE_DESCRIPTION
(
"framebuffer driver for CGsix chipsets"
);
MODULE_AUTHOR
(
"David S. Miller <davem@redhat.com>"
);
MODULE_LICENSE
(
"GPL"
);
drivers/video/cgthreefb.c
deleted
100644 → 0
View file @
41ae6422
/* $Id: cgthreefb.c,v 1.11 2001/09/19 00:04:33 davem Exp $
* cgthreefb.c: CGthree frame buffer driver
*
* Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*/
#include <linux/module.h>
#include <linux/sched.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/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/selection.h>
#include <video/sbusfb.h>
#include <asm/io.h>
#include <video/fbcon-cfb8.h>
/* Control Register Constants */
#define CG3_CR_ENABLE_INTS 0x80
#define CG3_CR_ENABLE_VIDEO 0x40
#define CG3_CR_ENABLE_TIMING 0x20
#define CG3_CR_ENABLE_CURCMP 0x10
#define CG3_CR_XTAL_MASK 0x0c
#define CG3_CR_DIVISOR_MASK 0x03
/* Status Register Constants */
#define CG3_SR_PENDING_INT 0x80
#define CG3_SR_RES_MASK 0x70
#define CG3_SR_1152_900_76_A 0x40
#define CG3_SR_1152_900_76_B 0x60
#define CG3_SR_ID_MASK 0x0f
#define CG3_SR_ID_COLOR 0x01
#define CG3_SR_ID_MONO 0x02
#define CG3_SR_ID_MONO_ECL 0x03
MODULE_LICENSE
(
"GPL"
);
enum
cg3_type
{
CG3_AT_66HZ
=
0
,
CG3_AT_76HZ
,
CG3_RDI
};
struct
cg3_regs
{
struct
bt_regs
cmap
;
volatile
u8
control
;
volatile
u8
status
;
volatile
u8
cursor_start
;
volatile
u8
cursor_end
;
volatile
u8
h_blank_start
;
volatile
u8
h_blank_end
;
volatile
u8
h_sync_start
;
volatile
u8
h_sync_end
;
volatile
u8
comp_sync_end
;
volatile
u8
v_blank_start_high
;
volatile
u8
v_blank_start_low
;
volatile
u8
v_blank_end
;
volatile
u8
v_sync_start
;
volatile
u8
v_sync_end
;
volatile
u8
xfer_holdoff_start
;
volatile
u8
xfer_holdoff_end
;
};
/* Offset of interesting structures in the OBIO space */
#define CG3_REGS_OFFSET 0x400000UL
#define CG3_RAM_OFFSET 0x800000UL
static
struct
sbus_mmap_map
cg3_mmap_map
[]
=
{
{
CG3_MMAP_OFFSET
,
CG3_RAM_OFFSET
,
SBUS_MMAP_FBSIZE
(
1
)
},
{
0
,
0
,
0
}
};
/* The cg3 palette is loaded with 4 color values at each time */
/* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */
#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))
/* (x/4)*3 */
#define D4M4(x) ((x)&~0x3)
/* (x/4)*4 */
static
void
cg3_loadcmap
(
struct
fb_info_sbusfb
*
fb
,
struct
display
*
p
,
int
index
,
int
count
)
{
struct
bt_regs
*
bt
=
&
fb
->
s
.
cg3
.
regs
->
cmap
;
unsigned
long
flags
;
u32
*
i
;
volatile
u8
*
regp
;
int
steps
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
i
=
(((
u32
*
)
fb
->
color_map
)
+
D4M3
(
index
));
steps
=
D4M3
(
index
+
count
-
1
)
-
D4M3
(
index
)
+
3
;
regp
=
(
volatile
u8
*
)
&
bt
->
addr
;
sbus_writeb
(
D4M4
(
index
),
regp
);
while
(
steps
--
)
{
u32
val
=
*
i
++
;
sbus_writel
(
val
,
&
bt
->
color_map
);
}
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
}
static
int
cg3_blank
(
struct
fb_info_sbusfb
*
fb
)
{
unsigned
long
flags
;
u8
tmp
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
tmp
=
sbus_readb
(
&
fb
->
s
.
cg3
.
regs
->
control
);
tmp
&=
~
CG3_CR_ENABLE_VIDEO
;
sbus_writeb
(
tmp
,
&
fb
->
s
.
cg3
.
regs
->
control
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
return
0
;
}
static
int
cg3_unblank
(
struct
fb_info_sbusfb
*
fb
)
{
unsigned
long
flags
;
u8
tmp
;
spin_lock_irqsave
(
&
fb
->
lock
,
flags
);
tmp
=
sbus_readb
(
&
fb
->
s
.
cg3
.
regs
->
control
);
tmp
|=
CG3_CR_ENABLE_VIDEO
;
sbus_writeb
(
tmp
,
&
fb
->
s
.
cg3
.
regs
->
control
);
spin_unlock_irqrestore
(
&
fb
->
lock
,
flags
);
return
0
;
}
static
void
cg3_margins
(
struct
fb_info_sbusfb
*
fb
,
struct
display
*
p
,
int
x_margin
,
int
y_margin
)
{
fb
->
info
.
screen_base
+=
(
y_margin
-
fb
->
y_margin
)
*
fb
->
info
.
fix
.
line_length
+
(
x_margin
-
fb
->
x_margin
);
}
static
u8
cg3regvals_66hz
[]
__initdata
=
{
/* 1152 x 900, 66 Hz */
0x14
,
0xbb
,
0x15
,
0x2b
,
0x16
,
0x04
,
0x17
,
0x14
,
0x18
,
0xae
,
0x19
,
0x03
,
0x1a
,
0xa8
,
0x1b
,
0x24
,
0x1c
,
0x01
,
0x1d
,
0x05
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x20
,
0
};
static
u8
cg3regvals_76hz
[]
__initdata
=
{
/* 1152 x 900, 76 Hz */
0x14
,
0xb7
,
0x15
,
0x27
,
0x16
,
0x03
,
0x17
,
0x0f
,
0x18
,
0xae
,
0x19
,
0x03
,
0x1a
,
0xae
,
0x1b
,
0x2a
,
0x1c
,
0x01
,
0x1d
,
0x09
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x24
,
0
};
static
u8
cg3regvals_rdi
[]
__initdata
=
{
/* 640 x 480, cgRDI */
0x14
,
0x70
,
0x15
,
0x20
,
0x16
,
0x08
,
0x17
,
0x10
,
0x18
,
0x06
,
0x19
,
0x02
,
0x1a
,
0x31
,
0x1b
,
0x51
,
0x1c
,
0x06
,
0x1d
,
0x0c
,
0x1e
,
0xff
,
0x1f
,
0x01
,
0x10
,
0x22
,
0
};
static
u8
*
cg3_regvals
[]
__initdata
=
{
cg3regvals_66hz
,
cg3regvals_76hz
,
cg3regvals_rdi
};
static
u_char
cg3_dacvals
[]
__initdata
=
{
4
,
0xff
,
5
,
0x00
,
6
,
0x70
,
7
,
0x00
,
0
};
static
char
idstring
[
60
]
__initdata
=
{
0
};
char
__init
*
cgthreefb_init
(
struct
fb_info_sbusfb
*
fb
)
{
struct
fb_fix_screeninfo
*
fix
=
&
fb
->
info
.
fix
;
struct
display
*
disp
=
&
fb
->
disp
;
struct
fbtype
*
type
=
&
fb
->
type
;
struct
sbus_dev
*
sdev
=
fb
->
sbdp
;
unsigned
long
phys
=
sdev
->
reg_addrs
[
0
].
phys_addr
;
int
cgRDI
=
strstr
(
fb
->
sbdp
->
prom_name
,
"cgRDI"
)
!=
NULL
;
#ifndef FBCON_HAS_CFB8
return
NULL
;
#endif
if
(
!
fb
->
s
.
cg3
.
regs
)
{
fb
->
s
.
cg3
.
regs
=
(
struct
cg3_regs
*
)
sbus_ioremap
(
&
sdev
->
resource
[
0
],
CG3_REGS_OFFSET
,
sizeof
(
struct
cg3_regs
),
"cg3 regs"
);
if
(
cgRDI
)
{
char
buffer
[
40
];
char
*
p
;
int
ww
,
hh
;
*
buffer
=
0
;
prom_getstring
(
fb
->
prom_node
,
"params"
,
buffer
,
sizeof
(
buffer
));
if
(
*
buffer
)
{
ww
=
simple_strtoul
(
buffer
,
&
p
,
10
);
if
(
ww
&&
*
p
==
'x'
)
{
hh
=
simple_strtoul
(
p
+
1
,
&
p
,
10
);
if
(
hh
&&
*
p
==
'-'
)
{
if
(
type
->
fb_width
!=
ww
||
type
->
fb_height
!=
hh
)
{
type
->
fb_width
=
ww
;
type
->
fb_height
=
hh
;
return
SBUSFBINIT_SIZECHANGE
;
}
}
}
}
}
}
strcpy
(
fb
->
info
.
modename
,
"CGthree"
);
strcpy
(
fix
->
id
,
"CGthree"
);
fix
->
line_length
=
fb
->
info
.
var
.
xres_virtual
;
fix
->
accel
=
FB_ACCEL_SUN_CGTHREE
;
disp
->
scrollmode
=
SCROLL_YREDRAW
;
if
(
!
fb
->
info
.
screen_base
)
{
fb
->
info
.
screen_base
=
(
char
*
)
sbus_ioremap
(
&
sdev
->
resource
[
0
],
CG3_RAM_OFFSET
,
type
->
fb_size
,
"cg3 ram"
);
}
fb
->
info
.
screen_base
+=
fix
->
line_length
*
fb
->
y_margin
+
fb
->
x_margin
;
fb
->
dispsw
=
fbcon_cfb8
;
fb
->
margins
=
cg3_margins
;
fb
->
loadcmap
=
cg3_loadcmap
;
fb
->
blank
=
cg3_blank
;
fb
->
unblank
=
cg3_unblank
;
fb
->
physbase
=
phys
;
fb
->
mmap_map
=
cg3_mmap_map
;
#ifdef __sparc_v9__
sprintf
(
idstring
,
"%s at %016lx"
,
cgRDI
?
"cgRDI"
:
"cgthree"
,
phys
);
#else
sprintf
(
idstring
,
"%s at %x.%08lx"
,
cgRDI
?
"cgRDI"
:
"cgthree"
,
fb
->
iospace
,
phys
);
#endif
if
(
!
prom_getbool
(
fb
->
prom_node
,
"width"
))
{
/* Ugh, broken PROM didn't initialize us.
* Let's deal with this ourselves.
*/
enum
cg3_type
type
;
u8
*
p
;
if
(
cgRDI
)
type
=
CG3_RDI
;
else
{
u8
status
=
sbus_readb
(
&
fb
->
s
.
cg3
.
regs
->
status
),
mon
;
if
((
status
&
CG3_SR_ID_MASK
)
==
CG3_SR_ID_COLOR
)
{
mon
=
status
&
CG3_SR_RES_MASK
;
if
(
mon
==
CG3_SR_1152_900_76_A
||
mon
==
CG3_SR_1152_900_76_B
)
type
=
CG3_AT_76HZ
;
else
type
=
CG3_AT_66HZ
;
}
else
{
prom_printf
(
"cgthree: can't handle SR %02x
\n
"
,
status
);
prom_halt
();
return
NULL
;
/* fool gcc. */
}
}
for
(
p
=
cg3_regvals
[
type
];
*
p
;
p
+=
2
)
{
u8
*
regp
=
&
((
u8
*
)
fb
->
s
.
cg3
.
regs
)[
p
[
0
]];
sbus_writeb
(
p
[
1
],
regp
);
}
for
(
p
=
cg3_dacvals
;
*
p
;
p
+=
2
)
{
volatile
u8
*
regp
;
regp
=
(
volatile
u8
*
)
&
fb
->
s
.
cg3
.
regs
->
cmap
.
addr
;
sbus_writeb
(
p
[
0
],
regp
);
regp
=
(
volatile
u8
*
)
&
fb
->
s
.
cg3
.
regs
->
cmap
.
control
;
sbus_writeb
(
p
[
1
],
regp
);
}
}
return
idstring
;
}
drivers/video/fbmem.c
View file @
57b55f79
...
...
@@ -146,6 +146,12 @@ extern int i810fb_init(void);
extern
int
i810fb_setup
(
char
*
);
extern
int
ffb_init
(
void
);
extern
int
ffb_setup
(
char
*
);
extern
int
cg6_init
(
void
);
extern
int
cg6_setup
(
char
*
);
extern
int
cg3_init
(
void
);
extern
int
cg3_setup
(
char
*
);
extern
int
bw2_init
(
void
);
extern
int
bw2_setup
(
char
*
);
static
struct
{
const
char
*
name
;
...
...
@@ -240,6 +246,15 @@ static struct {
#ifdef CONFIG_FB_FFB
{
"ffb"
,
ffb_init
,
ffb_setup
},
#endif
#ifdef CONFIG_FB_CG6
{
"cg6"
,
cg6_init
,
cg6_setup
},
#endif
#ifdef CONFIG_FB_CG3
{
"cg3"
,
cg3_init
,
cg3_setup
},
#endif
#ifdef CONFIG_FB_BW2
{
"bw2"
,
bw2_init
,
bw2_setup
},
#endif
/*
* Generic drivers that are used as fallbacks
...
...
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