Commit 8d7c2813 authored by James Simmons's avatar James Simmons

Updates for the STI fbdev and console driver.

parent 0e2e212c
......@@ -295,27 +295,21 @@ config FB_VGA16
vga16fb.o.
config FB_STI
bool "Generic STI frame buffer device support"
bool "HP STI frame buffer device support"
depends on FB && PARISC
default y
---help---
STI refers to the HP "Standard Text Interface" which is a set of
BIOS routines contained in a ROM chip in HP PA-RISC based machines.
Enabling this option will implement the linux framebuffer device and
an fbcon color text console using calls to the STI BIOS routines.
The HP framebuffer device is usually planar, uses a strange memory
layout, and changing the plane mask to create colored pixels
requires a call to the STI routines, so do not expect /dev/fb to
actually be useful. However, it is the best we have as far as
graphics on the HP chipsets due to lack of hardware level
documentation for the various on-board HP chipsets used in these
systems. It is sufficient for basic text console functions,
including fonts.
You should probably enable this option, unless you are having
trouble getting video when booting the kernel (make sure it isn't
just that you are running the console on the serial port, though).
Really old HP boxes may not have STI, and must use the PDC BIOS
console or the IODC BIOS.
Enabling this option will implement the linux framebuffer device
using calls to the STI BIOS routines for initialisation.
If you enable this option, you will get a planar framebuffer device
/dev/fb which will work on the most common HP graphic cards of the
NGLE family, including the artist chips (in the 7xx and Bxxx series),
HCRX, HCRX24, CRX, CRX24 and VisEG series.
It is safe to enable this option, so you should probably say "Y".
config FB_MAC
bool "Generic Macintosh display support"
......
......@@ -62,7 +62,7 @@ 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_STI) += stifb.o console/sticore.o
obj-$(CONFIG_FB_STI) += stifb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_MAXINE) += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
......
......@@ -66,8 +66,9 @@ config SGI_NEWPORT_CONSOLE
# bool 'IODC console' CONFIG_IODC_CONSOLE
config STI_CONSOLE
bool "STI console"
bool "STI text console"
depends on PARISC
default y
help
The STI console is the builtin display/keyboard on HP-PARISC
machines. Say Y here to build support for it into your kernel.
......
......@@ -45,9 +45,7 @@ obj-$(CONFIG_VGA_CONSOLE) += vgacon.o
obj-$(CONFIG_MDA_CONSOLE) += mdacon.o
obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o font.o
# Generic Low Level Drivers
obj-$(CONFIG_FBCON_STI) += fbcon-sti.o
obj-$(CONFIG_FB_STI) += sticore.o
# Files generated that shall be removed upon make clean
clean-files := promcon_tbl.c
......
/*
* linux/drivers/video/fbcon-sti.c -- Low level frame buffer
* operations for generic HP video boards using STI (standard
* text interface) firmware
*
* Based on linux/drivers/video/fbcon-artist.c
* Created 5 Apr 1997 by Geert Uytterhoeven
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details. */
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
#include <linux/fb.h>
#include <linux/delay.h>
#include <asm/gsc.h> /* for gsc_read/write */
#include <asm/types.h>
#include <video/fbcon.h>
#include <video/fbcon-mfb.h>
#include "../sticore.h"
static inline u32
ram2log(void * addr)
{
return (unsigned long) addr;
}
/* All those functions need better names. */
static void
memcpy_fromhp_tohp(void *dest, void *src, int count)
{
unsigned long d = ram2log(dest);
unsigned long s = ram2log(src);
count += 3;
count &= ~3; /* XXX */
while(count) {
count --;
gsc_writel(~gsc_readl(s), d);
d += 32*4;
s += 32*4;
}
}
static void
memset_tohp(void *dest, u32 word, int count)
{
unsigned long d = ram2log(dest);
count += 3;
count &= ~3;
while(count) {
count--;
gsc_writel(word, d);
d += 32;
}
}
static u8
readb_hp(void *src)
{
unsigned long s = ram2log(src);
return ~gsc_readb(s);
}
static void
writeb_hp(u8 b, void *dst)
{
unsigned long d = ram2log(dst);
if((d&0xf0000000) != 0xf0000000) {
printk("writeb_hp %02x %p (%08lx) (%p)\n",
b, dst, d, __builtin_return_address(0));
return;
}
gsc_writeb(b, d);
}
static void
fbcon_sti_setup(struct display *p)
{
/* in kernel 2.5 the value of sadly line_length disapeared */
if (p->var.xres_virtual /*line_length*/)
p->next_line = p->var.xres_virtual>>3;
else
p->next_line = 2048; /* default STI value */
p->next_plane = 0;
}
static void
fbcon_sti_bmove(struct display *p, int sy, int sx,
int dy, int dx,
int height, int width)
{
#if 0 /* Unfortunately, still broken */
sti_bmove(default_sti /* FIXME */, sy, sx, dy, dx, height, width);
#else
u8 *src, *dest;
u_int rows;
if (sx == 0 && dx == 0 && width == p->next_line) {
src = p->fb_info->screen_base+sy*fontheight(p)*width;
dest = p->fb_info->screen_base+dy*fontheight(p)*width;
memcpy_fromhp_tohp(dest, src, height*fontheight(p)*width);
} else if (dy <= sy) {
src = p->fb_info->screen_base+sy*fontheight(p)*p->next_line+sx;
dest = p->fb_info->screen_base+dy*fontheight(p)*p->next_line+dx;
for (rows = height*fontheight(p); rows--;) {
memcpy_fromhp_tohp(dest, src, width);
src += p->next_line;
dest += p->next_line;
}
} else {
src = p->fb_info->screen_base+((sy+height)*fontheight(p)-1)*p->next_line+sx;
dest = p->fb_info->screen_base+((dy+height)*fontheight(p)-1)*p->next_line+dx;
for (rows = height*fontheight(p); rows--;) {
memcpy_fromhp_tohp(dest, src, width);
src -= p->next_line;
dest -= p->next_line;
}
}
#endif
}
static void
fbcon_sti_clear(struct vc_data *conp,
struct display *p, int sy, int sx,
int height, int width)
{
u8 *dest;
u_int rows;
int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
dest = p->fb_info->screen_base+sy*fontheight(p)*p->next_line+sx;
if (sx == 0 && width == p->next_line) {
if (inverse)
memset_tohp(dest, ~0, height*fontheight(p)*width);
else
memset_tohp(dest, 0, height*fontheight(p)*width);
} else
for (rows = height*fontheight(p); rows--; dest += p->next_line)
if (inverse)
memset_tohp(dest, 0xffffffff, width);
else
memset_tohp(dest, 0x00000000, width);
}
static void fbcon_sti_putc(struct vc_data *conp,
struct display *p, int c,
int yy, int xx)
{
u8 *dest, *cdat;
u_int rows, bold, revs, underl;
u8 d;
dest = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx;
cdat = p->fontdata+(c&p->charmask)*fontheight(p);
bold = attr_bold(p,c);
revs = attr_reverse(p,c);
underl = attr_underline(p,c);
for (rows = fontheight(p); rows--; dest += p->next_line) {
d = *cdat++;
if (underl && !rows)
d = 0xff;
else if (bold)
d |= d>>1;
if (revs)
d = ~d;
writeb_hp (d, dest);
}
}
static void fbcon_sti_putcs(struct vc_data *conp,
struct display *p,
const unsigned short *s,
int count, int yy, int xx)
{
u8 *dest, *dest0, *cdat;
u_int rows, bold, revs, underl;
u8 d;
u16 c;
if(((unsigned)xx > 200) || ((unsigned) yy > 200)) {
printk("refusing to putcs %p %p %p %d %d %d (%p)\n",
conp, p, s, count, yy, xx, __builtin_return_address(0));
return;
}
dest0 = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx;
if(((u32)dest0&0xf0000000)!=0xf0000000) {
printk("refusing to putcs %p %p %p %d %d %d (%p) %p = %p + %d * %d * %ld + %d\n",
conp, p, s, count, yy, xx, __builtin_return_address(0),
dest0, p->fb_info->screen_base, yy, fontheight(p), p->next_line,
xx);
return;
}
c = scr_readw(s);
bold = attr_bold(p, c);
revs = attr_reverse(p, c);
underl = attr_underline(p, c);
while (count--) {
c = scr_readw(s++) & p->charmask;
dest = dest0++;
cdat = p->fontdata+c*fontheight(p);
for (rows = fontheight(p); rows--; dest += p->next_line) {
d = *cdat++;
if (0 && underl && !rows)
d = 0xff;
else if (0 && bold)
d |= d>>1;
if (revs)
d = ~d;
writeb_hp (d, dest);
}
}
}
static void fbcon_sti_revc(struct display *p,
int xx, int yy)
{
u8 *dest, d;
u_int rows;
dest = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx;
for (rows = fontheight(p); rows--; dest += p->next_line) {
d = readb_hp(dest);
writeb_hp (~d, dest);
}
}
static void
fbcon_sti_clear_margins(struct vc_data *conp,
struct display *p,
int bottom_only)
{
u8 *dest;
int height, bottom;
int inverse = conp ? attr_reverse(p,conp->vc_video_erase_char) : 0;
/* XXX Need to handle right margin? */
height = p->var.yres - conp->vc_rows * fontheight(p);
if (!height)
return;
bottom = conp->vc_rows + p->yscroll;
if (bottom >= p->vrows)
bottom -= p->vrows;
dest = p->fb_info->screen_base + bottom * fontheight(p) * p->next_line;
if (inverse)
memset_tohp(dest, 0xffffffff, height * p->next_line);
else
memset_tohp(dest, 0x00000000, height * p->next_line);
}
/*
* `switch' for the low level operations
*/
struct display_switch fbcon_sti = {
.setup = fbcon_sti_setup,
.bmove = fbcon_sti_bmove,
.clear = fbcon_sti_clear,
.putc = fbcon_sti_putc,
.putcs = fbcon_sti_putcs,
.revc = fbcon_sti_revc,
.clear_margins =fbcon_sti_clear_margins,
.fontwidthmask =FONTWIDTH(8)
};
MODULE_LICENSE("GPL");
#define STI_REGION_MAX 8
#define STI_DEV_NAME_LENGTH 32
struct sti_rom_font {
u16 first_char;
u16 last_char;
u8 width;
u8 height;
u8 font_type;
u8 bytes_per_char;
u32 next_font;
u8 underline_height;
u8 underline_pos;
u8 res008[2];
};
struct sti_rom {
u8 type[4];
u8 res004;
u8 num_mons;
u8 revno[2];
u8 graphics_id[8];
u32 font_start;
u32 statesize;
u32 last_addr;
u32 region_list;
u16 reentsize;
u16 maxtime;
u32 mon_tbl_addr;
u32 user_data_addr;
u32 sti_mem_req;
u32 user_data_size;
u16 power;
u8 bus_support;
u8 ext_bus_support;
u8 alt_code_type;
u8 ext_dd_struct[3];
u32 cfb_addr;
u32 init_graph;
u32 state_mgmt;
u32 font_unpmv;
u32 block_move;
u32 self_test;
u32 excep_hdlr;
u32 inq_conf;
u32 set_cm_entry;
u32 dma_ctrl;
u8 res040[7 * 4];
u32 init_graph_m68k;
u32 flow_ctrl;
u32 user_timing;
u32 process_mgr;
u32 sti_util;
u32 end_addr;
u32 res0b8;
u32 res0bc;
};
struct sti_cooked_font {
struct sti_rom_font *raw;
struct sti_cooked_font *next_font;
};
struct sti_cooked_rom {
struct sti_rom *raw;
struct sti_cooked_font *font_start;
u32 *region_list;
};
struct sti_glob_cfg_ext {
u8 curr_mon;
u8 friendly_boot;
s16 power;
s32 freq_ref;
s32 *sti_mem_addr;
s32 *future_ptr;
};
struct sti_glob_cfg {
s32 text_planes;
s16 onscreen_x;
s16 onscreen_y;
s16 offscreen_x;
s16 offscreen_y;
s16 total_x;
s16 total_y;
u32 region_ptrs[STI_REGION_MAX];
s32 reent_lvl;
s32 *save_addr;
struct sti_glob_cfg_ext *ext_ptr;
};
struct sti_init_flags {
u32 wait : 1;
u32 reset : 1;
u32 text : 1;
u32 nontext : 1;
u32 clear : 1;
u32 cmap_blk : 1;
u32 enable_be_timer : 1;
u32 enable_be_int : 1;
u32 no_chg_tx : 1;
u32 no_chg_ntx : 1;
u32 no_chg_bet : 1;
u32 no_chg_bei : 1;
u32 init_cmap_tx : 1;
u32 cmt_chg : 1;
u32 retain_ie : 1;
u32 pad : 17;
s32 *future_ptr;
};
struct sti_init_inptr_ext {
u8 config_mon_type;
u8 pad[1];
u16 inflight_data;
s32 *future_ptr;
};
struct sti_init_inptr {
s32 text_planes;
struct sti_init_inptr_ext *ext_ptr;
};
struct sti_init_outptr {
s32 errno;
s32 text_planes;
s32 *future_ptr;
};
struct sti_conf_flags {
u32 wait : 1;
u32 pad : 31;
s32 *future_ptr;
};
struct sti_conf_inptr {
s32 *future_ptr;
};
struct sti_conf_outptr_ext {
u32 crt_config[3];
u32 crt_hdw[3];
s32 *future_ptr;
};
struct sti_conf_outptr {
s32 errno;
s16 onscreen_x;
s16 onscreen_y;
s16 offscreen_x;
s16 offscreen_y;
s16 total_x;
s16 total_y;
s32 bits_per_pixel;
s32 bits_used;
s32 planes;
u8 dev_name[STI_DEV_NAME_LENGTH];
u32 attributes;
struct sti_conf_outptr_ext *ext_ptr;
};
struct sti_font_inptr {
u32 font_start_addr;
s16 index;
u8 fg_color;
u8 bg_color;
s16 dest_x;
s16 dest_y;
s32 *future_ptr;
};
struct sti_font_flags {
u32 wait : 1;
u32 non_text : 1;
u32 pad : 30;
s32 *future_ptr;
};
struct sti_font_outptr {
s32 errno;
s32 *future_ptr;
};
struct sti_blkmv_flags {
u32 wait : 1;
u32 color : 1;
u32 clear : 1;
u32 non_text : 1;
u32 pad : 28;
s32 *future_ptr;
};
struct sti_blkmv_inptr {
u8 fg_color;
u8 bg_color;
s16 src_x;
s16 src_y;
s16 dest_x;
s16 dest_y;
s16 width;
s16 height;
s32 *future_ptr;
};
struct sti_blkmv_outptr {
s32 errno;
s32 *future_ptr;
};
struct sti_struct {
spinlock_t lock;
struct sti_cooked_rom *rom;
unsigned long font_unpmv;
unsigned long block_move;
unsigned long init_graph;
unsigned long inq_conf;
struct sti_glob_cfg *glob_cfg;
struct sti_rom_font *font;
s32 text_planes;
char **mon_strings;
u32 *regions;
u8 *pci_regions;
};
#define STI_CALL(func, flags, inptr, outptr, glob_cfg) \
({ \
real32_call( func, (unsigned long)STI_PTR(flags), \
STI_PTR(inptr), STI_PTR(outptr), \
glob_cfg); \
})
/* The latency of the STI functions cannot really be reduced by setting
* this to 0; STI doesn't seem to be designed to allow calling a different
* function (or the same function with different arguments) after a
* function exited with 1 as return value.
*
* As all of the functions below could be called from interrupt context,
* we have to spin_lock_irqsave around the do { ret = bla(); } while(ret==1)
* block. Really bad latency there.
*
* Probably the best solution to all this is have the generic code manage
* the screen buffer and a kernel thread to call STI occasionally.
*
* Luckily, the frame buffer guys have the same problem so we can just wait
* for them to fix it and steal their solution. prumpf
*
* Actually, another long-term viable solution is to completely do STI
* support in userspace - that way we avoid the potential license issues
* of using proprietary fonts, too. */
#define STI_WAIT 1
#define STI_PTR(p) ( (typeof(p)) virt_to_phys(p))
#define PTR_STI(p) ( (typeof(p)) phys_to_virt((unsigned long)p) )
#define sti_onscreen_x(sti) (PTR_STI(sti->glob_cfg)->onscreen_x)
#define sti_onscreen_y(sti) (PTR_STI(sti->glob_cfg)->onscreen_y)
#define sti_font_x(sti) (PTR_STI(sti->font)->width)
#define sti_font_y(sti) (PTR_STI(sti->font)->height)
extern struct sti_struct * sti_init_roms(void);
void sti_init_graph(struct sti_struct *sti);
void sti_inq_conf(struct sti_struct *sti);
void sti_putc(struct sti_struct *sti, int c, int y, int x);
void sti_set(struct sti_struct *sti, int src_y, int src_x,
int height, int width, u8 color);
void sti_clear(struct sti_struct *sti, int src_y, int src_x,
int height, int width);
void sti_bmove(struct sti_struct *sti, int src_y, int src_x,
int dst_y, int dst_x, int height, int width);
/* XXX: this probably should not be here, but we rely on STI being
initialized early and independently of stifb at the moment, so
there's no other way for stifb to find it. */
extern struct sti_struct default_sti;
/*
* linux/drivers/video/sticon.c - console driver using HP's STI firmware
* linux/drivers/video/console/sticon.c - console driver using HP's STI firmware
*
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
* Copyright (C) 2002 Helge Deller <deller@gmx.de>
*
* Based on linux/drivers/video/vgacon.c and linux/drivers/video/fbcon.c,
* which were
......@@ -31,18 +32,7 @@
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
/*
* TODO:
* - call STI in virtual mode rather than in real mode
* - support for PCI-only STI ROMs (which don't have a traditional region
* list)
* - safe detection (i.e. verify there is a graphics device at a given
* address first, not just read a random device's io space)
* - support for multiple STI devices in one machine
* - support for byte-mode STI ROMs
* - support for just using STI to switch to a colour fb (stifb ?)
* - try to make it work on m68k hp workstations ;)
*
*/
#include <linux/init.h>
......@@ -51,92 +41,193 @@
#include <linux/console.h>
#include <linux/errno.h>
#include <linux/vt_kern.h>
#include <linux/kd.h>
#include <linux/selection.h>
#include <asm/io.h>
#include "sti.h"
#include "../sticore.h"
/* switching to graphics mode */
#define BLANK 0
static int vga_is_gfx;
/* Software scrollback */
static unsigned long softback_buf, softback_curr;
static unsigned long softback_in;
static unsigned long /* softback_top, */ softback_end;
static int softback_lines;
/* STICON */
static const char * __init
sticon_startup(void)
/* software cursor */
static int cursor_drawn;
#define CURSOR_DRAW_DELAY (1)
#define DEFAULT_CURSOR_BLINK_RATE (20)
static int vbl_cursor_cnt;
static inline void cursor_undrawn(void)
{
return "STI console";
vbl_cursor_cnt = 0;
cursor_drawn = 0;
}
static int
sticon_set_palette(struct vc_data *c, unsigned char *table)
static const char *__init sticon_startup(void)
{
return -EINVAL;
return "STI console";
}
static int
sticon_font_op(struct vc_data *c, struct console_font_op *op)
static int sticon_set_palette(struct vc_data *c, unsigned char *table)
{
return -ENOSYS;
return -EINVAL;
}
static int sticon_font_op(struct vc_data *c, struct console_font_op *op)
{
return -ENOSYS;
}
static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos)
{
sti_putc(&default_sti, c, ypos, xpos);
int unit = conp->vc_num;
int redraw_cursor = 0;
if (vga_is_gfx || console_blanked)
return;
if (vt_cons[unit]->vc_mode != KD_TEXT)
return;
#if 0
if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) {
cursor_undrawn();
redraw_cursor = 1;
}
#endif
sti_putc(default_sti, c, ypos, xpos);
if (redraw_cursor)
vbl_cursor_cnt = CURSOR_DRAW_DELAY;
}
static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
int count, int ypos, int xpos)
int count, int ypos, int xpos)
{
while(count--) {
sti_putc(&default_sti, scr_readw(s++), ypos, xpos++);
}
int unit = conp->vc_num;
int redraw_cursor = 0;
if (vga_is_gfx || console_blanked)
return;
if (vt_cons[unit]->vc_mode != KD_TEXT)
return;
#if 0
if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) &&
(p->cursor_x < (xpos + count))) {
cursor_undrawn();
redraw_cursor = 1;
}
#endif
while (count--) {
sti_putc(default_sti, scr_readw(s++), ypos, xpos++);
}
if (redraw_cursor)
vbl_cursor_cnt = CURSOR_DRAW_DELAY;
}
static void sticon_cursor(struct vc_data *conp, int mode)
{
unsigned short car1;
car1 = conp->vc_screenbuf[conp->vc_x + conp->vc_y * conp->vc_cols];
switch (mode) {
case CM_ERASE:
sti_putc(default_sti, car1, conp->vc_y, conp->vc_x);
break;
case CM_MOVE:
case CM_DRAW:
switch (conp->vc_cursor_type & 0x0f) {
case CUR_UNDERLINE:
case CUR_LOWER_THIRD:
case CUR_LOWER_HALF:
case CUR_TWO_THIRDS:
case CUR_BLOCK:
sti_putc(default_sti, (car1 & 255) + (0 << 8) + (7 << 11),
conp->vc_y, conp->vc_x);
break;
}
break;
}
}
static int sticon_scroll(struct vc_data *conp, int t, int b, int dir,
int count)
static int
sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
{
struct sti_struct *sti = &default_sti;
if(console_blanked)
return 0;
sticon_cursor(conp, CM_ERASE);
struct sti_struct *sti = default_sti;
switch(dir) {
case SM_UP:
sti_bmove(sti, t+count, 0, t, 0, b-t-count, conp->vc_cols);
sti_clear(sti, b-count, 0, count, conp->vc_cols);
if (vga_is_gfx)
return 0;
break;
sticon_cursor(conp, CM_ERASE);
case SM_DOWN:
sti_bmove(sti, t, 0, t+count, 0, b-t-count, conp->vc_cols);
sti_clear(sti, t, 0, count, conp->vc_cols);
switch (dir) {
case SM_UP:
sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols);
sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char);
break;
break;
}
case SM_DOWN:
sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols);
sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char);
break;
}
return 0;
return 0;
}
static void sticon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
int height, int width)
static void
sticon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
int height, int width)
{
sti_bmove(&default_sti, sy, sx, dy, dx, height, width);
if (!width || !height)
return;
#if 0
if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
(sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
(dx <= p->cursor_x) && (p->cursor_x < dx+width)))
sticon_cursor(p, CM_ERASE /*|CM_SOFTBACK*/);
#endif
sti_bmove(default_sti, sy, sx, dy, dx, height, width);
}
static void sticon_init(struct vc_data *c, int init)
{
struct sti_struct *sti = &default_sti;
int vc_cols, vc_rows;
sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0);
c->vc_can_do_color = 1;
vc_cols = PTR_STI(sti->glob_cfg)->onscreen_x / sti_font_x(sti);
vc_rows = PTR_STI(sti->glob_cfg)->onscreen_y / sti_font_y(sti);
vc_resize(c->vc_num, vc_cols, vc_rows);
struct sti_struct *sti = default_sti;
int vc_cols, vc_rows;
sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0);
vc_cols = sti_onscreen_x(sti) / sti->font_width;
vc_rows = sti_onscreen_y(sti) / sti->font_height;
c->vc_can_do_color = 1;
if (init) {
c->vc_cols = vc_cols;
c->vc_rows = vc_rows;
} else {
/* vc_rows = (c->vc_rows > vc_rows) ? vc_rows : c->vc_rows; */
/* vc_cols = (c->vc_cols > vc_cols) ? vc_cols : c->vc_cols; */
vc_resize(c->vc_num, vc_cols, vc_rows);
/* vc_resize_con(vc_rows, vc_cols, c->vc_num); */
}
}
static void sticon_deinit(struct vc_data *c)
......@@ -144,71 +235,170 @@ static void sticon_deinit(struct vc_data *c)
}
static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
int width)
int width)
{
sti_clear(&default_sti, sy, sx, height, width);
if (!height || !width)
return;
sti_clear(default_sti, sy, sx, height, width, conp->vc_video_erase_char);
}
static int sticon_switch(struct vc_data *conp)
{
return 0;
return 1; /* needs refreshing */
}
static int sticon_blank(struct vc_data *conp, int blank)
static int sticon_set_origin(struct vc_data *conp)
{
return 0;
return 0;
}
static int sticon_blank(struct vc_data *c, int blank)
{
switch (blank) {
case 0: /* unblank */
vga_is_gfx = 0;
/* Tell console.c that it has to restore the screen itself */
return 1;
case 1: /* normal blanking */
default: /* VESA blanking */
if (vga_is_gfx)
return 0;
sticon_set_origin(c);
sti_clear(default_sti, 0,0, c->vc_rows, c->vc_cols, BLANK);
return 1;
case -1: /* Entering graphic mode */
sti_clear(default_sti, 0,0, c->vc_rows, c->vc_cols, BLANK);
vga_is_gfx = 1;
return 1;
}
return 1; /* console needs to restore screen itself */
}
static int sticon_scrolldelta(struct vc_data *conp, int lines)
{
return 0;
return 0;
}
static int sticon_set_origin(struct vc_data *conp)
static u16 *sticon_screen_pos(struct vc_data *conp, int offset)
{
return 0;
int line;
unsigned long p;
if (conp->vc_num != fg_console || !softback_lines)
return (u16 *)(conp->vc_origin + offset);
line = offset / conp->vc_size_row;
if (line >= softback_lines)
return (u16 *)(conp->vc_origin + offset - softback_lines * conp->vc_size_row);
p = softback_curr + offset;
if (p >= softback_end)
p += softback_buf - softback_end;
return (u16 *)p;
}
static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens, u8 blink, u8 underline, u8 reverse)
static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos,
int *px, int *py)
{
u8 attr = ((color & 0x70) >> 1) | ((color & 7));
int x, y;
unsigned long ret;
if (pos >= conp->vc_origin && pos < conp->vc_scr_end) {
unsigned long offset = (pos - conp->vc_origin) / 2;
x = offset % conp->vc_cols;
y = offset / conp->vc_cols;
if (conp->vc_num == fg_console)
y += softback_lines;
ret = pos + (conp->vc_cols - x) * 2;
} else if (conp->vc_num == fg_console && softback_lines) {
unsigned long offset = pos - softback_curr;
if (pos < softback_curr)
offset += softback_end - softback_buf;
offset /= 2;
x = offset % conp->vc_cols;
y = offset / conp->vc_cols;
ret = pos + (conp->vc_cols - x) * 2;
if (ret == softback_end)
ret = softback_buf;
if (ret == softback_in)
ret = conp->vc_origin;
} else {
/* Should not happen */
x = y = 0;
ret = conp->vc_origin;
}
if (px) *px = x;
if (py) *py = y;
return ret;
}
if(reverse) {
color = ((color>>3)&0x7) | ((color &0x7)<<3);
}
static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens,
u8 blink, u8 underline, u8 reverse)
{
u8 attr = ((color & 0x70) >> 1) | ((color & 7));
if (reverse) {
color = ((color >> 3) & 0x7) | ((color & 0x7) << 3);
}
return attr;
return attr;
}
void sticon_invert_region(struct vc_data *conp, u16 *p, int count)
{
int col = 1; /* vga_can_do_color; */
while (count--) {
u16 a = scr_readw(p);
if (col)
a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
else
a = ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
scr_writew(a, p++);
}
}
void sticon_save_screen(struct vc_data *conp)
{
}
struct consw sti_con = {
.con_startup = sticon_startup,
.con_init = sticon_init,
.con_deinit = sticon_deinit,
.con_clear = sticon_clear,
.con_putc = sticon_putc,
.con_putcs = sticon_putcs,
.con_cursor = sticon_cursor,
.con_scroll = sticon_scroll,
.con_bmove = sticon_bmove,
.con_switch = sticon_switch,
.con_blank = sticon_blank,
.con_font_op = sticon_font_op,
.con_set_palette = sticon_set_palette,
.con_scrolldelta = sticon_scrolldelta,
.con_set_origin = sticon_set_origin,
.con_build_attr = sticon_build_attr,
con_startup: sticon_startup,
con_init: sticon_init,
con_deinit: sticon_deinit,
con_clear: sticon_clear,
con_putc: sticon_putc,
con_putcs: sticon_putcs,
con_cursor: sticon_cursor,
con_scroll: sticon_scroll,
con_bmove: sticon_bmove,
con_switch: sticon_switch,
con_blank: sticon_blank,
con_font_op: sticon_font_op,
con_set_palette: sticon_set_palette,
con_scrolldelta: sticon_scrolldelta,
con_set_origin: sticon_set_origin,
con_save_screen: sticon_save_screen,
con_build_attr: sticon_build_attr,
con_invert_region: sticon_invert_region,
con_screen_pos: sticon_screen_pos,
con_getxy: sticon_getxy,
};
static int __init sti_init(void)
int __init sticonsole_init(void)
{
printk("searching for word mode STI ROMs\n");
if (sti_init_roms()) {
pdc_console_die();
take_over_console(&sti_con, 0, MAX_NR_CONSOLES-1, 1);
return 0;
} else
return -ENODEV;
if (sti_init_roms()) {
if (conswitchp == &dummy_con) {
printk(KERN_INFO "sticon: Initializing STI text console.\n");
take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1, 1);
}
return 0;
} else
return -ENODEV;
}
module_init(sti_init)
module_init(sticonsole_init);
/*
* linux/drivers/video/console/sticore.c -
* core code for console driver using HP's STI firmware
*
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
* Portions Copyright (C) 2001-2002 Helge Deller <deller@gmx.de>
* Portions Copyright (C) 2001-2002 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
*
* TODO:
* - call STI in virtual mode rather than in real mode
* - screen blanking with state_mgmt() in text mode STI ?
* - try to make it work on m68k hp workstations ;)
* - clean up the cache flushing functions
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/pci.h>
#include "font.h"
#include <asm/uaccess.h>
#include <asm/pgalloc.h>
#include <asm/io.h>
#include <asm/hardware.h>
#include "sti.h"
#include "../sticore.h"
struct sti_struct default_sti = {
SPIN_LOCK_UNLOCKED,
};
#define STI_DRIVERVERSION "0.9"
struct sti_struct *default_sti;
static int num_sti_roms; /* # of STI ROMS found */
static struct sti_struct *sti_roms[MAX_STI_ROMS]; /* ptr to each sti_struct */
static struct sti_font_flags default_font_flags = {
STI_WAIT, 0, 0, NULL
};
/* The colour indices used by STI are
* 0 - Black
......@@ -31,31 +49,36 @@ static struct sti_font_flags default_font_flags = {
* So we have the same colours as VGA (basically one bit each for R, G, B),
* but have to translate them, anyway. */
static u8 col_trans[8] = {
static const u8 col_trans[8] = {
0, 6, 4, 5,
2, 7, 3, 1
};
#define c_fg(sti, c) col_trans[((c>> 8) & 7)]
#define c_bg(sti, c) col_trans[((c>>11) & 7)]
#define c_index(sti, c) (c&0xff)
static struct sti_init_flags default_init_flags = {
STI_WAIT, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, NULL
#define c_index(sti, c) ((c) & 0xff)
static const struct sti_init_flags default_init_flags = {
.wait = STI_WAIT,
.reset = 1,
.text = 1,
.nontext = 1,
.no_chg_bet = 1,
.no_chg_bei = 1,
.init_cmap_tx = 1,
};
void
int
sti_init_graph(struct sti_struct *sti)
{
struct sti_init_inptr_ext inptr_ext = {
0, { 0 }, 0, NULL
};
struct sti_init_inptr_ext inptr_ext = { 0, };
struct sti_init_inptr inptr = {
3, STI_PTR(&inptr_ext)
3, /* # of text planes (3 is maximum for STI) */
STI_PTR(&inptr_ext)
};
struct sti_init_outptr outptr = { 0 };
struct sti_init_outptr outptr = { 0, };
unsigned long flags;
s32 ret;
int ret;
spin_lock_irqsave(&sti->lock, flags);
......@@ -64,42 +87,50 @@ sti_init_graph(struct sti_struct *sti)
spin_unlock_irqrestore(&sti->lock, flags);
if (ret < 0) {
printk(KERN_ERR "STI init_graph failed (ret %d, errno %d)\n",ret,outptr.errno);
return -1;
}
sti->text_planes = outptr.text_planes;
return 0;
}
static struct sti_conf_flags default_conf_flags = {
STI_WAIT, 0, NULL
};
static const struct sti_conf_flags default_conf_flags = {
wait: STI_WAIT,
};
void
sti_inq_conf(struct sti_struct *sti)
{
struct sti_conf_inptr inptr = { NULL };
struct sti_conf_outptr_ext outptr_ext = { .future_ptr = NULL };
struct sti_conf_outptr outptr = {
.ext_ptr = STI_PTR(&outptr_ext)
};
struct sti_conf_inptr inptr = { 0 };
unsigned long flags;
s32 ret;
sti->outptr.ext_ptr = STI_PTR(&sti->outptr_ext);
do {
spin_lock_irqsave(&sti->lock, flags);
ret = STI_CALL(sti->inq_conf, &default_conf_flags,
&inptr, &outptr, sti->glob_cfg);
&inptr, &sti->outptr, sti->glob_cfg);
spin_unlock_irqrestore(&sti->lock, flags);
} while(ret == 1);
} while (ret == 1);
}
static const struct sti_font_flags default_font_flags = {
wait: STI_WAIT,
non_text: 0,
};
void
sti_putc(struct sti_struct *sti, int c, int y, int x)
{
struct sti_font_inptr inptr = {
(u32) sti->font, c_index(sti, c), c_fg(sti, c), c_bg(sti, c),
x * sti_font_x(sti), y * sti_font_y(sti), NULL
};
struct sti_font_outptr outptr = {
0, NULL
STI_PTR(sti->font->raw),
c_index(sti, c), c_fg(sti, c), c_bg(sti, c),
x * sti->font_width, y * sti->font_height, 0
};
struct sti_font_outptr outptr = { 0, };
s32 ret;
unsigned long flags;
......@@ -108,11 +139,13 @@ sti_putc(struct sti_struct *sti, int c, int y, int x)
ret = STI_CALL(sti->font_unpmv, &default_font_flags,
&inptr, &outptr, sti->glob_cfg);
spin_unlock_irqrestore(&sti->lock, flags);
} while(ret == 1);
} while (ret == 1);
}
static struct sti_blkmv_flags clear_blkmv_flags = {
STI_WAIT, 1, 1, 0, 0, NULL
static const struct sti_blkmv_flags clear_blkmv_flags = {
.wait = STI_WAIT,
.color = 1,
.clear = 1,
};
void
......@@ -124,10 +157,10 @@ sti_set(struct sti_struct *sti, int src_y, int src_x,
src_x, src_y ,
src_x, src_y ,
width, height,
NULL
0
};
struct sti_blkmv_outptr outptr = { 0, NULL };
s32 ret = 0;
struct sti_blkmv_outptr outptr = { 0, };
s32 ret;
unsigned long flags;
do {
......@@ -135,22 +168,22 @@ sti_set(struct sti_struct *sti, int src_y, int src_x,
ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
&inptr, &outptr, sti->glob_cfg);
spin_unlock_irqrestore(&sti->lock, flags);
} while(ret == 1);
} while (ret == 1);
}
void
sti_clear(struct sti_struct *sti, int src_y, int src_x,
int height, int width)
int height, int width, int c)
{
struct sti_blkmv_inptr inptr = {
0, 0,
src_x * sti_font_x(sti), src_y * sti_font_y(sti),
src_x * sti_font_x(sti), src_y * sti_font_y(sti),
width * sti_font_x(sti), height* sti_font_y(sti),
NULL
c_fg(sti, c), c_bg(sti, c),
src_x * sti->font_width, src_y * sti->font_height,
src_x * sti->font_width, src_y * sti->font_height,
width * sti->font_width, height* sti->font_height,
0
};
struct sti_blkmv_outptr outptr = { 0, NULL };
s32 ret = 0;
struct sti_blkmv_outptr outptr = { 0, };
s32 ret;
unsigned long flags;
do {
......@@ -158,11 +191,11 @@ sti_clear(struct sti_struct *sti, int src_y, int src_x,
ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
&inptr, &outptr, sti->glob_cfg);
spin_unlock_irqrestore(&sti->lock, flags);
} while(ret == 1);
} while (ret == 1);
}
static struct sti_blkmv_flags default_blkmv_flags = {
STI_WAIT, 0, 0, 0, 0, NULL
static const struct sti_blkmv_flags default_blkmv_flags = {
.wait = STI_WAIT,
};
void
......@@ -171,13 +204,13 @@ sti_bmove(struct sti_struct *sti, int src_y, int src_x,
{
struct sti_blkmv_inptr inptr = {
0, 0,
src_x * sti_font_x(sti), src_y * sti_font_y(sti),
dst_x * sti_font_x(sti), dst_y * sti_font_y(sti),
width * sti_font_x(sti), height* sti_font_y(sti),
NULL
src_x * sti->font_width, src_y * sti->font_height,
dst_x * sti->font_width, dst_y * sti->font_height,
width * sti->font_width, height* sti->font_height,
0
};
struct sti_blkmv_outptr outptr = { 0, NULL };
s32 ret = 0;
struct sti_blkmv_outptr outptr = { 0, };
s32 ret;
unsigned long flags;
do {
......@@ -185,170 +218,128 @@ sti_bmove(struct sti_struct *sti, int src_y, int src_x,
ret = STI_CALL(sti->block_move, &default_blkmv_flags,
&inptr, &outptr, sti->glob_cfg);
spin_unlock_irqrestore(&sti->lock, flags);
} while(ret == 1);
} while (ret == 1);
}
static void __init
sti_rom_copy(unsigned long base, unsigned long offset,
unsigned long count, void *dest)
void __init
sti_rom_copy(unsigned long base, unsigned long count, void *dest)
{
void *savedest = dest;
int savecount = count;
unsigned long dest_len = count;
unsigned long dest_start = (unsigned long) dest;
while(count >= 4) {
/* this still needs to be revisited (see arch/parisc/mm/init.c:246) ! */
while (count >= 4) {
count -= 4;
*(u32 *)dest = gsc_readl(base + offset);
offset += 4;
*(u32 *)dest = __raw_readl(base);
base += 4;
dest += 4;
}
while(count) {
while (count) {
count--;
*(u8 *)dest = gsc_readb(base + offset);
offset++;
*(u8 *)dest = __raw_readb(base);
base++;
dest++;
}
flush_kernel_dcache_range((unsigned long)dest, count);
flush_icache_range((unsigned long)dest, dest + count);
}
static void dump_sti_rom(struct sti_rom *rom)
{
printk("STI word mode ROM type %d\n", rom->type[3]);
printk(" supports %d monitors\n", rom->num_mons);
printk(" conforms to STI ROM spec revision %d.%02x\n",
rom->revno[0] >> 4, rom->revno[0] & 0x0f);
printk(" graphics id %02x%02x%02x%02x%02x%02x%02x%02x\n",
rom->graphics_id[0],
rom->graphics_id[1],
rom->graphics_id[2],
rom->graphics_id[3],
rom->graphics_id[4],
rom->graphics_id[5],
rom->graphics_id[6],
rom->graphics_id[7]);
printk(" font start %08x\n", rom->font_start);
printk(" region list %08x\n", rom->region_list);
printk(" init_graph %08x\n", rom->init_graph);
printk(" alternate code type %d\n", rom->alt_code_type);
sti_flush(dest_start, dest_len); /* XXX */
}
static void __init sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
struct sti_rom *raw_rom)
{
struct sti_rom_font *raw_font;
struct sti_cooked_font *cooked_font;
struct sti_rom_font *font_start;
cooked_font =
kmalloc(sizeof *cooked_font, GFP_KERNEL);
if(!cooked_font)
return;
cooked_rom->font_start = cooked_font;
raw_font = ((void *)raw_rom) + (raw_rom->font_start);
font_start = raw_font;
cooked_font->raw = raw_font;
static char default_sti_path[21];
while(raw_font->next_font) {
raw_font = ((void *)font_start) + (raw_font->next_font);
cooked_font->next_font =
kmalloc(sizeof *cooked_font, GFP_KERNEL);
if(!cooked_font->next_font)
return;
static int __init
sti_setup(char *str)
{
if (str)
strncpy (default_sti_path, str, sizeof (default_sti_path));
return 0;
}
cooked_font = cooked_font->next_font;
/* Assuming the machine has multiple STI consoles (=graphic cards) which
* all get detected by sticon, the user may define with the linux kernel
* parameter sti=<x> which of them will be the initial boot-console.
* <x> is a number between 0 and MAX_STI_ROMS, with 0 as the default
* STI screen.
*/
__setup("sti=", sti_setup);
cooked_font->raw = raw_font;
}
cooked_font->next_font = NULL;
}
static int font_index, font_height, font_width;
static char __initdata *font_name[MAX_STI_ROMS] = { "VGA8x16", };
static int __initdata font_index[MAX_STI_ROMS],
font_height[MAX_STI_ROMS],
font_width[MAX_STI_ROMS];
static int __init sti_font_setup(char *str)
{
char *x;
int i = 0;
/* we accept sti_font=10x20, sti_font=10*20 or sti_font=7 style
* command lines. */
if((x = strchr(str, 'x')) || (x = strchr(str, '*'))) {
font_height = simple_strtoul(str, NULL, 0);
font_width = simple_strtoul(x+1, NULL, 0);
} else {
font_index = simple_strtoul(str, NULL, 0);
}
return 0;
}
/* we accept sti_font=VGA8x16, sti_font=10x20, sti_font=10*20
* or sti_font=7 style command lines. */
while (i<MAX_STI_ROMS && str && *str) {
if (*str>='0' && *str<='9') {
if ((x = strchr(str, 'x')) || (x = strchr(str, '*'))) {
font_height[i] = simple_strtoul(str, NULL, 0);
font_width[i] = simple_strtoul(x+1, NULL, 0);
} else {
font_index[i] = simple_strtoul(str, NULL, 0);
}
} else {
font_name[i] = str; /* fb font name */
}
__setup("sti_font=", sti_font_setup);
if ((x = strchr(str, ',')))
*x++ = 0;
str = x;
static int __init sti_search_font(struct sti_cooked_rom *rom,
int height, int width)
{
struct sti_cooked_font *font;
int i = 0;
for(font = rom->font_start; font; font = font->next_font, i++) {
if((font->raw->width == width) && (font->raw->height == height))
return i;
i++;
}
return 0;
}
static struct sti_cooked_font * __init
sti_select_font(struct sti_cooked_rom *rom)
{
struct sti_cooked_font *font;
int i;
if(font_width && font_height)
font_index = sti_search_font(rom, font_height, font_width);
/* The optional linux kernel parameter "sti_font" defines which font
* should be used by the sticon driver to draw characters to the screen.
* Possible values are:
* - sti_font=<fb_fontname>:
* <fb_fontname> is the name of one of the linux-kernel built-in
* framebuffer font names (e.g. VGA8x16, SUN22x18).
* This is only available if the fonts have been statically compiled
* in with e.g. the CONFIG_FONT_8x16 or CONFIG_FONT_SUN12x22 options.
* - sti_font=<number>
* most STI ROMs have built-in HP specific fonts, which can be selected
* by giving the desired number to the sticon driver.
* NOTE: This number is machine and STI ROM dependend.
* - sti_font=<height>x<width> (e.g. sti_font=16x8)
* <height> and <width> gives hints to the height and width of the
* font which the user wants. The sticon driver will try to use
* a font with this height and width, but if no suitable font is
* found, sticon will use the default 8x8 font.
*/
__setup("sti_font=", sti_font_setup);
for(font = rom->font_start, i = font_index;
font && (i > 0);
font = font->next_font, i--);
if(font)
return font;
else
return rom->font_start;
}
static void __init
sti_dump_globcfg_ext(struct sti_glob_cfg_ext *cfg)
{
printk( "monitor %d\n"
"in friendly mode: %d\n"
"power consumption %d watts\n"
"freq ref %d\n"
"sti_mem_addr %p\n",
cfg->curr_mon,
cfg->friendly_boot,
cfg->power,
cfg->freq_ref,
cfg->sti_mem_addr);
}
void __init
sti_dump_globcfg(struct sti_glob_cfg *glob_cfg)
sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request)
{
printk( "%d text planes\n"
struct sti_glob_cfg_ext *cfg;
DPRINTK((KERN_INFO
"%d text planes\n"
"%4d x %4d screen resolution\n"
"%4d x %4d offscreen\n"
"%4d x %4d layout\n"
"regions at %08x %08x %08x %08x\n"
"regions at %08x %08x %08x %08x\n"
"reent_lvl %d\n"
"save_addr %p\n",
"save_addr %08x\n",
glob_cfg->text_planes,
glob_cfg->onscreen_x, glob_cfg->onscreen_y,
glob_cfg->offscreen_x, glob_cfg->offscreen_y,
......@@ -358,105 +349,420 @@ sti_dump_globcfg(struct sti_glob_cfg *glob_cfg)
glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
glob_cfg->reent_lvl,
glob_cfg->save_addr);
sti_dump_globcfg_ext(PTR_STI(glob_cfg->ext_ptr));
glob_cfg->save_addr));
/* dump extended cfg */
cfg = PTR_STI(glob_cfg->ext_ptr);
DPRINTK(( KERN_INFO
"monitor %d\n"
"in friendly mode: %d\n"
"power consumption %d watts\n"
"freq ref %d\n"
"sti_mem_addr %08x (size=%d bytes)\n",
cfg->curr_mon,
cfg->friendly_boot,
cfg->power,
cfg->freq_ref,
cfg->sti_mem_addr, sti_mem_request));
}
static void __init
sti_init_glob_cfg(struct sti_struct *sti, unsigned long hpa,
unsigned long rom_address)
void __init
sti_dump_outptr(struct sti_struct *sti)
{
DPRINTK((KERN_INFO
"%d bits per pixel\n"
"%d used bits\n"
"%d planes\n"
"attributes %08x\n",
sti->outptr.bits_per_pixel,
sti->outptr.bits_used,
sti->outptr.planes,
sti->outptr.attributes));
}
int __init
sti_init_glob_cfg(struct sti_struct *sti,
unsigned long rom_address, unsigned long hpa)
{
struct sti_glob_cfg *glob_cfg;
struct sti_glob_cfg_ext *glob_cfg_ext;
void *save_addr;
void *sti_mem_addr;
const int save_addr_size = 1024; /* XXX */
int i;
if (!sti->sti_mem_request)
sti->sti_mem_request = 256; /* STI default */
glob_cfg = kmalloc(sizeof *sti->glob_cfg, GFP_KERNEL);
glob_cfg_ext = kmalloc(sizeof *glob_cfg_ext, GFP_KERNEL);
save_addr = kmalloc(1024 /*XXX*/, GFP_KERNEL);
sti_mem_addr = kmalloc(1024, GFP_KERNEL);
glob_cfg = kmalloc(sizeof(*sti->glob_cfg), GFP_KERNEL);
glob_cfg_ext = kmalloc(sizeof(*glob_cfg_ext), GFP_KERNEL);
save_addr = kmalloc(save_addr_size, GFP_KERNEL);
sti_mem_addr = kmalloc(sti->sti_mem_request, GFP_KERNEL);
if((!glob_cfg) || (!glob_cfg_ext) || (!save_addr) || (!sti_mem_addr))
return;
if (!(glob_cfg && glob_cfg_ext && save_addr && sti_mem_addr))
return -ENOMEM;
memset(glob_cfg, 0, sizeof *glob_cfg);
memset(glob_cfg_ext, 0, sizeof *glob_cfg_ext);
memset(save_addr, 0, 1024);
memset(sti_mem_addr, 0, 1024);
memset(glob_cfg, 0, sizeof(*glob_cfg));
memset(glob_cfg_ext, 0, sizeof(*glob_cfg_ext));
memset(save_addr, 0, save_addr_size);
memset(sti_mem_addr, 0, sti->sti_mem_request);
glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext);
glob_cfg->save_addr = STI_PTR(save_addr);
glob_cfg->region_ptrs[0] = ((sti->regions[0]>>18)<<12) + rom_address;
glob_cfg->region_ptrs[1] = ((sti->regions[1]>>18)<<12) + hpa;
glob_cfg->region_ptrs[2] = ((sti->regions[2]>>18)<<12) + hpa;
glob_cfg->region_ptrs[3] = ((sti->regions[3]>>18)<<12) + hpa;
glob_cfg->region_ptrs[4] = ((sti->regions[4]>>18)<<12) + hpa;
glob_cfg->region_ptrs[5] = ((sti->regions[5]>>18)<<12) + hpa;
glob_cfg->region_ptrs[6] = ((sti->regions[6]>>18)<<12) + hpa;
glob_cfg->region_ptrs[7] = ((sti->regions[7]>>18)<<12) + hpa;
for (i=0; i<8; i++) {
unsigned long newhpa, len;
if (sti->pd) {
unsigned char offs = sti->rm_entry[i];
if (offs == 0)
continue;
if (offs != PCI_ROM_ADDRESS &&
(offs < PCI_BASE_ADDRESS_0 ||
offs > PCI_BASE_ADDRESS_5)) {
printk (KERN_WARNING
"STI pci region maping for region %d (%02x) can't be mapped\n",
i,sti->rm_entry[i]);
continue;
}
newhpa = pci_resource_start (sti->pd, (offs - PCI_BASE_ADDRESS_0) / 4);
} else
newhpa = (i == 0) ? rom_address : hpa;
sti->regions_phys[i] =
REGION_OFFSET_TO_PHYS(sti->regions[i], newhpa);
/* remap virtually */
/* FIXME: add BTLB support if btlb==1 */
len = sti->regions[i].region_desc.length * 4096;
if (len)
glob_cfg->region_ptrs[i] = (unsigned long) (
sti->regions[i].region_desc.cache ?
ioremap(sti->regions_phys[i], len) :
ioremap_nocache(sti->regions_phys[i], len) );
DPRINTK(("region #%d: phys %08lx, virt %08x, len=%lukB, "
"btlb=%d, sysonly=%d, cache=%d, last=%d\n",
i, sti->regions_phys[i], glob_cfg->region_ptrs[i],
len/1024,
sti->regions[i].region_desc.btlb,
sti->regions[i].region_desc.sys_only,
sti->regions[i].region_desc.cache,
sti->regions[i].region_desc.last));
/* last entry reached ? */
if (sti->regions[i].region_desc.last)
break;
}
if (++i<8 && sti->regions[i].region)
printk(KERN_WARNING "%s: *future ptr (0x%8x) not yet supported !\n",
__FILE__, sti->regions[i].region);
glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr);
sti->glob_cfg = STI_PTR(glob_cfg);
sti->glob_cfg = glob_cfg;
return 0;
}
/* address is a pointer to a word mode or pci rom */
static struct sti_struct * __init
sti_read_rom(unsigned long address)
#ifdef CONFIG_FB
struct sti_cooked_font * __init
sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name )
{
struct sti_struct *ret = NULL;
struct sti_cooked_rom *cooked = NULL;
struct sti_rom *raw = NULL;
unsigned long size;
struct font_desc *fbfont;
unsigned int size, bpc;
void *dest;
struct sti_rom_font *nf;
struct sti_cooked_font *cooked_font;
if (!fbfont_name || !strlen(fbfont_name))
return NULL;
fbfont = find_font(fbfont_name);
if (!fbfont)
fbfont = get_default_font(1024,768);
if (!fbfont)
return NULL;
DPRINTK((KERN_DEBUG "selected %dx%d fb-font %s\n",
fbfont->width, fbfont->height, fbfont->name));
bpc = ((fbfont->width+7)/8) * fbfont->height;
size = bpc * 256;
size += sizeof(struct sti_rom_font);
nf = kmalloc(size, GFP_KERNEL);
if (!nf)
return NULL;
memset(nf, 0, size);
nf->first_char = 0;
nf->last_char = 255;
nf->width = fbfont->width;
nf->height = fbfont->height;
nf->font_type = STI_FONT_HPROMAN8;
nf->bytes_per_char = bpc;
nf->next_font = 0;
nf->underline_height = 1;
nf->underline_pos = fbfont->height - nf->underline_height;
dest = nf;
dest += sizeof(struct sti_rom_font);
memcpy(dest, fbfont->data, bpc*256);
cooked_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL);
if (!cooked_font) {
kfree(nf);
return NULL;
}
cooked_font->raw = nf;
cooked_font->next_font = NULL;
ret = &default_sti;
cooked_rom->font_start = cooked_font;
if(!ret)
goto out_err;
return cooked_font;
}
#else
struct sti_cooked_font * __init
sti_select_fbfont(struct sti_cooked_rom *cooked_rom, char *fbfont_name)
{
return NULL;
}
#endif
cooked = kmalloc(sizeof *cooked, GFP_KERNEL);
raw = kmalloc(sizeof *raw, GFP_KERNEL);
struct sti_cooked_font * __init
sti_select_font(struct sti_cooked_rom *rom,
int (*search_font_fnc) (struct sti_cooked_rom *,int,int) )
{
struct sti_cooked_font *font;
int i;
int index = num_sti_roms;
/* check for framebuffer-font first */
if ((font = sti_select_fbfont(rom, font_name[index])))
return font;
if (font_width[index] && font_height[index])
font_index[index] = search_font_fnc(rom,
font_height[index], font_width[index]);
for (font = rom->font_start, i = font_index[index];
font && (i > 0);
font = font->next_font, i--);
if (font)
return font;
else
return rom->font_start;
}
static void __init
sti_dump_rom(struct sti_rom *rom)
{
printk(KERN_INFO "STI id %04x-%04x, conforms to spec rev. %d.%02x\n",
rom->graphics_id[0],
rom->graphics_id[1],
rom->revno[0] >> 4,
rom->revno[0] & 0x0f);
DPRINTK((" supports %d monitors\n", rom->num_mons));
DPRINTK((" font start %08x\n", rom->font_start));
DPRINTK((" region list %08x\n", rom->region_list));
DPRINTK((" init_graph %08x\n", rom->init_graph));
DPRINTK((" bus support %02x\n", rom->bus_support));
DPRINTK((" ext bus support %02x\n", rom->ext_bus_support));
DPRINTK((" alternate code type %d\n", rom->alt_code_type));
}
static int __init
sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
struct sti_rom *raw_rom)
{
struct sti_rom_font *raw_font, *font_start;
struct sti_cooked_font *cooked_font;
if(!(raw && cooked))
goto out_err;
cooked_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL);
if (!cooked_font)
return 0;
/* reallocate raw */
sti_rom_copy(address, 0, sizeof *raw, raw);
cooked_rom->font_start = cooked_font;
dump_sti_rom(raw);
raw_font = ((void *)raw_rom) + (raw_rom->font_start);
size = raw->last_addr;
/* kfree(raw); */
raw = kmalloc(size, GFP_KERNEL);
if(!raw)
goto out_err;
sti_rom_copy(address, 0, size, raw);
font_start = raw_font;
cooked_font->raw = raw_font;
sti_cook_fonts(cooked, raw);
#if 0
sti_cook_regions(cooked, raw);
sti_cook_functions(cooked, raw);
#endif
while (raw_font->next_font) {
raw_font = ((void *)font_start) + (raw_font->next_font);
cooked_font->next_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL);
if (!cooked_font->next_font)
return 1;
cooked_font = cooked_font->next_font;
cooked_font->raw = raw_font;
}
cooked_font->next_font = NULL;
return 1;
}
static int __init
sti_search_font(struct sti_cooked_rom *rom, int height, int width)
{
struct sti_cooked_font *font;
int i = 0;
for(font = rom->font_start; font; font = font->next_font, i++) {
if((font->raw->width == width) && (font->raw->height == height))
return i;
}
return 0;
}
#define BMODE_RELOCATE(offset) offset = (offset) / 4;
#define BMODE_LAST_ADDR_OFFS 0x50
static void * __init
sti_bmode_font_raw(struct sti_cooked_font *f)
{
unsigned char *n, *p, *q;
int size = f->raw->bytes_per_char*256+sizeof(struct sti_rom_font);
n = kmalloc (4*size, GFP_KERNEL);
if (!n)
return NULL;
memset (n, 0, 4*size);
p = n + 3;
q = (unsigned char *)f->raw;
while (size--) {
*p = *q++;
p+=4;
}
return n + 3;
}
if(raw->region_list) {
ret->regions = kmalloc(32, GFP_KERNEL); /* FIXME */
static void __init
sti_bmode_rom_copy(unsigned long base, unsigned long count, void *dest)
{
unsigned long dest_len = count;
unsigned long dest_start = (unsigned long) dest;
memcpy(ret->regions, ((void *)raw)+raw->region_list, 32);
while (count) {
count--;
*(u8 *)dest = __raw_readl(base);
base += 4;
dest++;
}
sti_flush(dest_start, dest_len); /* XXX */
}
address = virt_to_phys(raw);
struct sti_rom * __init
sti_get_bmode_rom (unsigned long address)
{
struct sti_rom *raw;
u32 size;
struct sti_rom_font *raw_font, *font_start;
sti_bmode_rom_copy(address + BMODE_LAST_ADDR_OFFS, sizeof(size), &size);
size = (size+3) / 4;
raw = kmalloc(size, GFP_KERNEL);
if (raw) {
sti_bmode_rom_copy(address, size, raw);
memmove (&raw->res004, &raw->type[0], 0x3c);
raw->type[3] = raw->res004;
BMODE_RELOCATE (raw->region_list);
BMODE_RELOCATE (raw->font_start);
BMODE_RELOCATE (raw->init_graph);
BMODE_RELOCATE (raw->state_mgmt);
BMODE_RELOCATE (raw->font_unpmv);
BMODE_RELOCATE (raw->block_move);
BMODE_RELOCATE (raw->inq_conf);
raw_font = ((void *)raw) + raw->font_start;
font_start = raw_font;
while (raw_font->next_font) {
BMODE_RELOCATE (raw_font->next_font);
raw_font = ((void *)font_start) + raw_font->next_font;
}
}
return raw;
}
ret->font_unpmv = address+(raw->font_unpmv & 0x03ffffff);
ret->block_move = address+(raw->block_move & 0x03ffffff);
ret->init_graph = address+(raw->init_graph & 0x03ffffff);
ret->inq_conf = address+(raw->inq_conf & 0x03ffffff);
struct sti_rom * __init
sti_get_wmode_rom (unsigned long address)
{
struct sti_rom *raw;
unsigned long size;
/* read the ROM size directly from the struct in ROM */
size = __raw_readl(address + offsetof(struct sti_rom,last_addr));
ret->rom = cooked;
ret->rom->raw = raw;
raw = kmalloc(size, GFP_KERNEL);
if(raw)
sti_rom_copy(address, size, raw);
ret->font = (struct sti_rom_font *) virt_to_phys(sti_select_font(ret->rom)->raw);
return raw;
}
return ret;
int __init
sti_read_rom(int wordmode, struct sti_struct *sti, unsigned long address)
{
struct sti_cooked_rom *cooked;
struct sti_rom *raw = NULL;
cooked = kmalloc(sizeof *cooked, GFP_KERNEL);
if (!cooked)
goto out_err;
if (wordmode)
raw = sti_get_wmode_rom (address);
else
raw = sti_get_bmode_rom (address);
if (!raw)
goto out_err;
if (!sti_cook_fonts(cooked, raw)) {
printk(KERN_ERR "No font found for STI at %08lx\n", address);
goto out_err;
}
if (raw->region_list)
memcpy(sti->regions, ((void *)raw)+raw->region_list, sizeof(sti->regions));
address = (unsigned long) STI_PTR(raw);
sti->font_unpmv = address + (raw->font_unpmv & 0x03ffffff);
sti->block_move = address + (raw->block_move & 0x03ffffff);
sti->init_graph = address + (raw->init_graph & 0x03ffffff);
sti->inq_conf = address + (raw->inq_conf & 0x03ffffff);
sti->rom = cooked;
sti->rom->raw = raw;
sti->font = sti_select_font(sti->rom, sti_search_font);
sti->font_width = sti->font->raw->width;
sti->font_height = sti->font->raw->height;
if (!wordmode)
sti->font->raw = sti_bmode_font_raw(sti->font);
sti->sti_mem_request = raw->sti_mem_req;
sti->graphics_id[0] = raw->graphics_id[0];
sti->graphics_id[1] = raw->graphics_id[1];
sti_dump_rom(raw);
return 1;
out_err:
if(raw)
......@@ -464,138 +770,290 @@ sti_read_rom(unsigned long address)
if(cooked)
kfree(cooked);
return NULL;
return 0;
}
static struct sti_struct * __init
sti_try_rom(unsigned long address, unsigned long hpa)
sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd)
{
struct sti_struct *sti = NULL;
u16 sig;
struct sti_struct *sti;
int ok;
u32 sig;
if (num_sti_roms >= MAX_STI_ROMS) {
printk(KERN_WARNING "maximum number of STI ROMS reached !\n");
return NULL;
}
sti = kmalloc(sizeof(*sti), GFP_KERNEL);
if (!sti) {
printk(KERN_ERR "Not enough memory !\n");
return NULL;
}
memset(sti, 0, sizeof(*sti));
sti->lock = SPIN_LOCK_UNLOCKED;
test_rom:
/* if we can't read the ROM, bail out early. Not being able
* to read the hpa is okay, for romless sti */
if(pdc_add_valid((void*)address))
return NULL;
printk("found potential STI ROM at %08lx\n", address);
sig = le16_to_cpu(gsc_readw(address));
if (pdc_add_valid(address))
goto out_err;
if((sig==0x55aa) || (sig==0xaa55)) {
address += le32_to_cpu(gsc_readl(address+8));
printk("sig %04x, PCI STI ROM at %08lx\n",
sig, address);
sig = __raw_readl(address);
/* check for a PCI ROM structure */
if ((le32_to_cpu(sig)==0xaa55)) {
unsigned int i, rm_offset;
u32 *rm;
i = __raw_readl(address+0x04);
if (i != 1) {
/* The ROM could have multiple architecture
* dependent images (e.g. i386, parisc,...) */
printk(KERN_WARNING
"PCI ROM is not a STI ROM type image (0x%8x)\n", i);
goto out_err;
}
sti->pd = pd;
i = __raw_readl(address+0x0c);
DPRINTK(("PCI ROM size (from header) = %d kB\n",
le16_to_cpu(i>>16)*512/1024));
rm_offset = le16_to_cpu(i & 0xffff);
if (rm_offset) {
/* read 16 bytes from the pci region mapper array */
rm = (u32*) &sti->rm_entry;
*rm++ = __raw_readl(address+rm_offset+0x00);
*rm++ = __raw_readl(address+rm_offset+0x04);
*rm++ = __raw_readl(address+rm_offset+0x08);
*rm++ = __raw_readl(address+rm_offset+0x0c);
DPRINTK(("PCI region Mapper offset = %08x: ",
rm_offset));
for (i=0; i<16; i++)
DPRINTK(("%02x ", sti->rm_entry[i]));
DPRINTK(("\n"));
}
address += le32_to_cpu(__raw_readl(address+8));
DPRINTK(("sig %04x, PCI STI ROM at %08lx\n", sig, address));
goto test_rom;
}
if((sig&0xff) == 0x01) {
printk("STI byte mode ROM at %08lx, ignored\n",
address);
sti = NULL;
ok = 0;
if ((sig & 0xff) == 0x01) {
printk(KERN_INFO "STI byte mode ROM at %08lx, hpa at %08lx\n",
address, hpa);
ok = sti_read_rom(0, sti, address);
}
if(sig == 0x0303) {
printk("STI word mode ROM at %08lx\n",
address);
sti = sti_read_rom(address);
if ((sig & 0xffff) == 0x0303) {
printk(KERN_INFO "STI word mode ROM at %08lx, hpa at %08lx\n",
address, hpa);
ok = sti_read_rom(1, sti, address);
}
if (!sti)
return NULL;
if (!ok)
goto out_err;
/* this is hacked. We need a better way to find out the HPA for
* romless STI (eg search for the graphics devices we know about
* by sversion) */
if (!pdc_add_valid((void *)0xf5000000)) printk("f4000000 g\n");
if (!pdc_add_valid((void *)0xf7000000)) printk("f6000000 g\n");
if (!pdc_add_valid((void *)0xf9000000)) printk("f8000000 g\n");
if (!pdc_add_valid((void *)0xfb000000)) printk("fa000000 g\n");
sti_init_glob_cfg(sti, hpa, address);
if (sti_init_glob_cfg(sti, address, hpa))
goto out_err; /* not enough memory */
/* disable STI PCI ROM. ROM and card RAM overlap and
* leaving it enabled would force HPMCs
*/
if (sti->pd) {
unsigned long rom_base;
rom_base = pci_resource_start(sti->pd, PCI_ROM_RESOURCE);
pci_write_config_dword(sti->pd, PCI_ROM_ADDRESS, rom_base & ~PCI_ROM_ADDRESS_ENABLE);
DPRINTK((KERN_DEBUG "STI PCI ROM disabled\n"));
}
sti_init_graph(sti);
if (sti_init_graph(sti))
goto out_err;
sti_inq_conf(sti);
sti_dump_globcfg(PTR_STI(sti->glob_cfg));
sti_dump_globcfg(sti->glob_cfg, sti->sti_mem_request);
sti_dump_outptr(sti);
printk(KERN_INFO "STI device: %s\n", sti->outptr.dev_name );
sti_roms[num_sti_roms] = sti;
num_sti_roms++;
return sti;
out_err:
kfree(sti);
return NULL;
}
static unsigned long sti_address;
static unsigned long sti_hpa;
static void __init sticore_check_for_default_sti (struct sti_struct *sti, char *path)
{
if (strcmp (path, default_sti_path) == 0)
default_sti = sti;
}
/* XXX: should build a list of STI ROMs */
struct sti_struct * __init
sti_init_roms(void)
/*
* on newer systems PDC gives the address of the ROM
* in the additional address field addr[1] while on
* older Systems the PDC stores it in page0->proc_sti
*/
static int __init sticore_pa_init(struct parisc_device *dev)
{
struct sti_struct *tmp = NULL, *sti = NULL;
unsigned long rom = 0;
char pa_path[21];
struct sti_struct *sti = NULL;
if(dev->num_addrs) {
rom = dev->addr[0];
}
if (!rom) {
rom = dev->hpa;
DPRINTK((KERN_DEBUG "Trying STI ROM at %08lx, hpa at %08lx\n", rom, dev->hpa));
sti = sti_try_rom_generic(rom, dev->hpa, NULL);
rom = PAGE0->proc_sti;
}
if (!sti) {
DPRINTK((KERN_DEBUG "Trying STI ROM at %08lx, hpa at %08lx\n", rom, dev->hpa));
sti = sti_try_rom_generic(rom, dev->hpa, NULL);
}
if (!sti)
return 1;
print_pa_hwpath(dev, pa_path);
sticore_check_for_default_sti (sti, pa_path);
return 0;
}
/* handle the command line */
if (sti_address && sti_hpa) {
return sti_try_rom(sti_address, sti_hpa);
static int __devinit sticore_pci_init(struct pci_dev *pd,
const struct pci_device_id *ent)
{
#ifdef CONFIG_PCI
unsigned long fb_base, rom_base;
unsigned int fb_len, rom_len;
struct sti_struct *sti;
pci_enable_device(pd);
fb_base = pci_resource_start(pd, 0);
fb_len = pci_resource_len(pd, 0);
rom_base = pci_resource_start(pd, PCI_ROM_RESOURCE);
rom_len = pci_resource_len(pd, PCI_ROM_RESOURCE);
if (rom_base) {
pci_write_config_dword(pd, PCI_ROM_ADDRESS, rom_base | PCI_ROM_ADDRESS_ENABLE);
DPRINTK((KERN_DEBUG "STI PCI ROM enabled at 0x%08lx\n", rom_base));
}
/* 712, 715, some other boxes don't have a separate STI ROM,
* but use part of the regular flash */
if (PAGE0->proc_sti) {
printk("STI ROM from PDC at %08x\n", PAGE0->proc_sti);
if (!pdc_add_valid((void *)0xf9000000))
sti = sti_try_rom(PAGE0->proc_sti, 0xf8000000);
else if (!pdc_add_valid((void *)0xf5000000))
sti = sti_try_rom(PAGE0->proc_sti, 0xf4000000);
else if (!pdc_add_valid((void *)0xf7000000))
sti = sti_try_rom(PAGE0->proc_sti, 0xf6000000);
else if (!pdc_add_valid((void *)0xfb000000))
sti = sti_try_rom(PAGE0->proc_sti, 0xfa000000);
printk(KERN_INFO "STI PCI graphic ROM found at %08lx (%u kB), fb at %08lx (%u MB)\n",
rom_base, rom_len/1024, fb_base, fb_len/1024/1024);
DPRINTK((KERN_DEBUG "Trying PCI STI ROM at %08lx, PCI hpa at %08lx\n",
rom_base, fb_base));
sti = sti_try_rom_generic(rom_base, fb_base, pd);
if (sti) {
char pa_path[30];
print_pci_hwpath(pd, pa_path);
sticore_check_for_default_sti(sti, pa_path);
}
if (!sti) {
printk(KERN_WARNING "Unable to handle STI device '%s'\n",
pd->dev.name);
return -ENODEV;
}
#endif /* CONFIG_PCI */
return 0;
}
/* standard locations for GSC graphic devices */
if (!pdc_add_valid((void *)0xf4000000))
tmp = sti_try_rom(0xf4000000, 0xf4000000);
sti = tmp ? tmp : sti;
if (!pdc_add_valid((void *)0xf6000000))
tmp = sti_try_rom(0xf6000000, 0xf6000000);
sti = tmp ? tmp : sti;
if (!pdc_add_valid((void *)0xf8000000))
tmp = sti_try_rom(0xf8000000, 0xf8000000);
sti = tmp ? tmp : sti;
if (!pdc_add_valid((void *)0xfa000000))
tmp = sti_try_rom(0xfa000000, 0xfa000000);
sti = tmp ? tmp : sti;
return sti;
static void __devexit sticore_pci_remove(struct pci_dev *pd)
{
BUG();
}
static int __init
sti_setup(char *str)
#define PCI_DEVICE_ID_VISUALIZE_EG 0x1005
#define PCI_DEVICE_ID_VISUALIZE_FX 0x1008
#define PCI_DEVICE_ID_VISUALIZE_FX_NEW 0x108b
static struct pci_device_id sti_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_VISUALIZE_EG, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_VISUALIZE_FX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_VISUALIZE_FX_NEW, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, sti_pci_tbl);
static struct pci_driver pci_sti_driver = {
.name = "sti (pci)",
.id_table = sti_pci_tbl,
.probe = sticore_pci_init,
.remove = sticore_pci_remove,
};
static struct parisc_device_id sti_pa_tbl[] = {
{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00077 },
{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00085 },
{ 0, }
};
struct parisc_driver pa_sti_driver = {
.name = "sti (native)",
.id_table = sti_pa_tbl,
.probe = sticore_pa_init,
};
struct sti_struct * __init sti_init_roms(void)
{
char *end;
static int initialized;
if(strcmp(str, "pdc") == 0) {
sti_address = PAGE0->proc_sti;
if (initialized)
goto out;
return 1;
} else {
sti_address = simple_strtoul(str, &end, 16);
printk(KERN_INFO "STI GSC/PCI graphics driver version %s\n",
STI_DRIVERVERSION);
if((end == str) || (sti_address < 0xf0000000)) {
sti_address = 0;
return 0;
}
/* Register drivers for native & PCI cards */
register_parisc_driver(&pa_sti_driver);
pci_module_init (&pci_sti_driver);
sti_hpa = sti_address;
/* if we didn't find the given default sti, take the first one */
if (!default_sti)
default_sti = sti_roms[0];
return 1;
out:
/* return default STI if available */
if (num_sti_roms && default_sti && default_sti->init_graph) {
initialized = 1;
return default_sti;
}
return 0;
return NULL;
}
__setup("sti=", sti_setup);
MODULE_LICENSE("GPL");
/*
* index = 0 gives default sti
* index > 0 gives other stis in detection order
*/
struct sti_struct * __init sti_get_rom(int index)
{
int i;
if (index == 0)
return default_sti;
i = -1;
while (index > 0) {
i++;
if (i > num_sti_roms)
return NULL;
if (sti_roms[i] == default_sti)
continue;
index--;
}
return sti_roms[i];
}
......@@ -11,6 +11,9 @@
#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/module.h>
#ifdef CONFIG_PCI
#include <linux/pci.h>
#endif
/*
* EDID parser
......@@ -19,37 +22,37 @@
* John Fremlin <vii@users.sourceforge.net> and Ani Joshi <ajoshi@unixbox.com>
*/
#define EDID_LENGTH 0x80
#define EDID_HEADER 0x00
#define EDID_HEADER_END 0x07
#define EDID_LENGTH 0x80
#define EDID_HEADER 0x00
#define EDID_HEADER_END 0x07
#define ID_MANUFACTURER_NAME 0x08
#define ID_MANUFACTURER_NAME_END 0x09
#define ID_MODEL 0x0a
#define ID_MANUFACTURER_NAME 0x08
#define ID_MANUFACTURER_NAME_END 0x09
#define ID_MODEL 0x0a
#define ID_SERIAL_NUMBER 0x0c
#define ID_SERIAL_NUMBER 0x0c
#define MANUFACTURE_WEEK 0x10
#define MANUFACTURE_YEAR 0x11
#define MANUFACTURE_WEEK 0x10
#define MANUFACTURE_YEAR 0x11
#define EDID_STRUCT_VERSION 0x12
#define EDID_STRUCT_REVISION 0x13
#define EDID_STRUCT_VERSION 0x12
#define EDID_STRUCT_REVISION 0x13
#define DPMS_FLAGS 0x18
#define ESTABLISHED_TIMING_1 0x23
#define ESTABLISHED_TIMING_2 0x24
#define MANUFACTURERS_TIMINGS 0x25
#define DPMS_FLAGS 0x18
#define ESTABLISHED_TIMING_1 0x23
#define ESTABLISHED_TIMING_2 0x24
#define MANUFACTURERS_TIMINGS 0x25
#define DETAILED_TIMING_DESCRIPTIONS_START 0x36
#define DETAILED_TIMING_DESCRIPTION_SIZE 18
#define NO_DETAILED_TIMING_DESCRIPTIONS 4
#define DETAILED_TIMING_DESCRIPTIONS_START 0x36
#define DETAILED_TIMING_DESCRIPTION_SIZE 18
#define NO_DETAILED_TIMING_DESCRIPTIONS 4
#define DETAILED_TIMING_DESCRIPTION_1 0x36
#define DETAILED_TIMING_DESCRIPTION_2 0x48
#define DETAILED_TIMING_DESCRIPTION_3 0x5a
#define DETAILED_TIMING_DESCRIPTION_4 0x6c
#define DETAILED_TIMING_DESCRIPTION_1 0x36
#define DETAILED_TIMING_DESCRIPTION_2 0x48
#define DETAILED_TIMING_DESCRIPTION_3 0x5a
#define DETAILED_TIMING_DESCRIPTION_4 0x6c
#define DESCRIPTOR_DATA 5
#define DESCRIPTOR_DATA 5
#define UPPER_NIBBLE( x ) \
(((128|64|32|16) & (x)) >> 4)
......@@ -65,7 +68,7 @@
#define PIXEL_CLOCK_LO (unsigned)block[ 0 ]
#define PIXEL_CLOCK_HI (unsigned)block[ 1 ]
#define PIXEL_CLOCK (COMBINE_HI_8LO( PIXEL_CLOCK_HI,PIXEL_CLOCK_LO )*1000
#define PIXEL_CLOCK (COMBINE_HI_8LO( PIXEL_CLOCK_HI,PIXEL_CLOCK_LO )*1000)
#define H_ACTIVE_LO (unsigned)block[ 2 ]
#define H_BLANKING_LO (unsigned)block[ 3 ]
#define H_ACTIVE_HI UPPER_NIBBLE( (unsigned)block[ 4 ] )
......@@ -223,8 +226,8 @@ static void parse_timing_block(unsigned char *block,
int parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
{
unsigned char *block, *vendor, *monitor = NULL;
int i;
unsigned char *block, *vendor, *monitor;
if (!(edid_checksum(edid)))
return 0;
......@@ -257,10 +260,12 @@ int parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
return 1;
}
#ifdef CONFIG_PCI
char *get_EDID(struct pci_dev *pdev)
{
#ifdef CONFIG_ALL_PPC
static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", NULL };
static char *propnames[] =
{ "DFP,EDID", "LCD,EDID", "EDID", "EDID1", NULL };
unsigned char *pedid = NULL;
struct device_node *dp;
int i;
......@@ -268,7 +273,10 @@ char *get_EDID(struct pci_dev *pdev)
dp = pci_device_to_OF_node(pdev);
while (dp != NULL) {
for (i = 0; propnames[i] != NULL; ++i) {
pedid = (unsigned char *) get_property(dp, propnames[i], NULL);
pedid =
(unsigned char *) get_property(dp,
propnames[i],
NULL);
if (pedid != NULL)
return pedid;
}
......@@ -278,7 +286,10 @@ char *get_EDID(struct pci_dev *pdev)
#else
return NULL;
#endif
}
}
#endif
EXPORT_SYMBOL(parse_edid);
#ifdef CONFIG_PCI
EXPORT_SYMBOL(get_EDID);
#endif
......@@ -41,9 +41,6 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/resource.h>
#include <linux/selection.h>
#include <linux/console.h>
#include <linux/vt_kern.h>
#include <linux/unistd.h>
#include <asm/io.h>
......
/*
* linux/drivers/video/riva/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver
*
* Maintained by Ani Joshi <ajoshi@shell.unixbox.com>
*
* Copyright 1999-2000 Jeff Garzik
*
* Contributors:
*
* Ani Joshi: Lots of debugging and cleanup work, really helped
* get the driver going
*
* Ferenc Bakonyi: Bug fixes, cleanup, modularization
*
* Jindrich Makovicka: Accel code help, hw cursor, mtrr
*
* Paul Richards: Bug fixes and updates.
*
* Initial template from skeletonfb.c, created 28 Dec 1997 by Geert Uytterhoeven
* Includes riva_hw.c from nVidia, see copyright below.
* KGI code provided the basis for state storage, init, and mode switching.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*
* Known bugs and issues:
* restoring text mode fails
* doublescan modes are broken
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/pci.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
#include "rivafb.h"
#include "nvreg.h"
#ifndef CONFIG_PCI /* sanity check */
#error This driver requires PCI support.
#endif
/* version number of this driver */
#define RIVAFB_VERSION "0.9.4"
/* ------------------------------------------------------------------------- *
*
* various helpful macros and constants
*
* ------------------------------------------------------------------------- */
#undef RIVAFBDEBUG
#ifdef RIVAFBDEBUG
#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#else
#define DPRINTK(fmt, args...)
#endif
#ifndef RIVA_NDEBUG
#define assert(expr) \
if(!(expr)) { \
printk( "Assertion failed! %s,%s,%s,line=%d\n",\
#expr,__FILE__,__FUNCTION__,__LINE__); \
BUG(); \
}
#else
#define assert(expr)
#endif
#define PFX "rivafb: "
/* macro that allows you to set overflow bits */
#define SetBitField(value,from,to) SetBF(to,GetBF(value,from))
#define SetBit(n) (1<<(n))
#define Set8Bits(value) ((value)&0xff)
/* HW cursor parameters */
#define MAX_CURS 32
/* ------------------------------------------------------------------------- *
*
* prototypes
*
* ------------------------------------------------------------------------- */
static int rivafb_blank(int blank, struct fb_info *info);
extern inline void wait_for_idle(struct riva_par *par);
/* ------------------------------------------------------------------------- *
*
* card identification
*
* ------------------------------------------------------------------------- */
enum riva_chips {
CH_RIVA_128 = 0,
CH_RIVA_TNT,
CH_RIVA_TNT2,
CH_RIVA_UTNT2,
CH_RIVA_VTNT2,
CH_RIVA_UVTNT2,
CH_RIVA_ITNT2,
CH_GEFORCE_SDR,
CH_GEFORCE_DDR,
CH_QUADRO,
CH_GEFORCE2_MX,
CH_GEFORCE2_MX2,
CH_GEFORCE2_GO,
CH_QUADRO2_MXR,
CH_GEFORCE2_GTS,
CH_GEFORCE2_GTS2,
CH_GEFORCE2_ULTRA,
CH_QUADRO2_PRO,
CH_GEFORCE4_MX_460,
CH_GEFORCE4_MX_440,
CH_GEFORCE4_MX_420,
CH_GEFORCE4_440_GO,
CH_GEFORCE4_420_GO,
CH_GEFORCE4_420_GO_M32,
CH_QUADRO4_500XGL,
CH_GEFORCE4_440_GO_M64,
CH_QUADRO4_200,
CH_QUADRO4_550XGL,
CH_QUADRO4_500_GOGL,
CH_IGEFORCE2,
CH_GEFORCE3,
CH_GEFORCE3_1,
CH_GEFORCE3_2,
CH_QUADRO_DDC,
CH_GEFORCE4_TI_4600,
CH_GEFORCE4_TI_4400,
CH_GEFORCE4_TI_4200,
CH_QUADRO4_900XGL,
CH_QUADRO4_750XGL,
CH_QUADRO4_700XGL
};
/* directly indexed by riva_chips enum, above */
static struct riva_chip_info {
const char *name;
unsigned arch_rev;
} riva_chip_info[] __devinitdata = {
{ "RIVA-128", NV_ARCH_03 },
{ "RIVA-TNT", NV_ARCH_04 },
{ "RIVA-TNT2", NV_ARCH_04 },
{ "RIVA-UTNT2", NV_ARCH_04 },
{ "RIVA-VTNT2", NV_ARCH_04 },
{ "RIVA-UVTNT2", NV_ARCH_04 },
{ "RIVA-ITNT2", NV_ARCH_04 },
{ "GeForce-SDR", NV_ARCH_10},
{ "GeForce-DDR", NV_ARCH_10},
{ "Quadro", NV_ARCH_10},
{ "GeForce2-MX", NV_ARCH_10},
{ "GeForce2-MX", NV_ARCH_10},
{ "GeForce2-GO", NV_ARCH_10},
{ "Quadro2-MXR", NV_ARCH_10},
{ "GeForce2-GTS", NV_ARCH_10},
{ "GeForce2-GTS", NV_ARCH_10},
{ "GeForce2-ULTRA", NV_ARCH_10},
{ "Quadro2-PRO", NV_ARCH_10},
{ "GeForce4-MX-460", NV_ARCH_20 },
{ "GeForce4-MX-440", NV_ARCH_20 },
{ "GeForce4-MX-420", NV_ARCH_20 },
{ "GeForce4-440-GO", NV_ARCH_20 },
{ "GeForce4-420-GO", NV_ARCH_20 },
{ "GeForce4-420-GO-M32", NV_ARCH_20 },
{ "Quadro4-500-XGL", NV_ARCH_20 },
{ "GeForce4-440-GO-M64", NV_ARCH_20 },
{ "Quadro4-200", NV_ARCH_20 },
{ "Quadro4-550-XGL", NV_ARCH_20 },
{ "Quadro4-500-GOGL", NV_ARCH_20 },
{ "GeForce2", NV_ARCH_20 },
{ "GeForce3", NV_ARCH_20 },
{ "GeForce3 Ti 200", NV_ARCH_20 },
{ "GeForce3 Ti 500", NV_ARCH_20 },
{ "Quadro DDC", NV_ARCH_20 },
{ "GeForce4 Ti 4600", NV_ARCH_20 },
{ "GeForce4 Ti 4400", NV_ARCH_20 },
{ "GeForce4 Ti 4200", NV_ARCH_20 },
{ "Quadro4-900-XGL", NV_ARCH_20 },
{ "Quadro4-750-XGL", NV_ARCH_20 },
{ "Quadro4-700-XGL", NV_ARCH_20 }
};
static struct pci_device_id rivafb_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_128 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_TNT },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_TNT2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_UTNT2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_VTNT2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_VTNT2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_ITNT2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE_SDR },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE_DDR },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_MX },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_MX2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GO },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_MXR },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_ULTRA },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_PRO },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_MX_460 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_MX_440 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_MX_420 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_440_GO },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_420_GO },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_420_GO_M32 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_500XGL },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_440_GO_M64 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_200 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_550XGL },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_500_GOGL },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_IGEFORCE2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_1 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO_DDC },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4600 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4400 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE4_TI_4200 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_900XGL },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_750XGL },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO4_700XGL },
{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl);
/* ------------------------------------------------------------------------- *
*
* global variables
*
* ------------------------------------------------------------------------- */
/* command line data, set in rivafb_setup() */
static u32 pseudo_palette[17];
#ifdef CONFIG_MTRR
static char nomtrr __initdata = 0;
#endif
#ifndef MODULE
static char *mode_option __initdata = NULL;
#endif
static struct fb_fix_screeninfo rivafb_fix = {
id: "nVidia",
type: FB_TYPE_PACKED_PIXELS,
xpanstep: 1,
ypanstep: 1,
};
static struct fb_var_screeninfo rivafb_default_var = {
xres: 640,
yres: 480,
xres_virtual: 640,
yres_virtual: 480,
xoffset: 0,
yoffset: 0,
bits_per_pixel: 8,
grayscale: 0,
red: {0, 6, 0},
green: {0, 6, 0},
blue: {0, 6, 0},
transp: {0, 0, 0},
nonstd: 0,
activate: 0,
height: -1,
width: -1,
accel_flags: FB_ACCELF_TEXT,
pixclock: 39721,
left_margin: 40,
right_margin: 24,
upper_margin: 32,
lower_margin: 11,
hsync_len: 96,
vsync_len: 2,
sync: 0,
vmode: FB_VMODE_NONINTERLACED
};
/* from GGI */
static const struct riva_regs reg_template = {
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ATTR */
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x41, 0x01, 0x0F, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* CRT */
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, /* 0x10 */
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, /* 0x40 */
},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, /* GRA */
0xFF},
{0x03, 0x01, 0x0F, 0x00, 0x0E}, /* SEQ */
0xEB /* MISC */
};
/* ------------------------------------------------------------------------- *
*
* MMIO access macros
*
* ------------------------------------------------------------------------- */
static inline void CRTCout(struct riva_par *par, unsigned char index,
unsigned char val)
{
VGA_WR08(par->riva.PCIO, 0x3d4, index);
VGA_WR08(par->riva.PCIO, 0x3d5, val);
}
static inline unsigned char CRTCin(struct riva_par *par,
unsigned char index)
{
VGA_WR08(par->riva.PCIO, 0x3d4, index);
return (VGA_RD08(par->riva.PCIO, 0x3d5));
}
static inline void GRAout(struct riva_par *par, unsigned char index,
unsigned char val)
{
VGA_WR08(par->riva.PVIO, 0x3ce, index);
VGA_WR08(par->riva.PVIO, 0x3cf, val);
}
static inline unsigned char GRAin(struct riva_par *par,
unsigned char index)
{
VGA_WR08(par->riva.PVIO, 0x3ce, index);
return (VGA_RD08(par->riva.PVIO, 0x3cf));
}
static inline void SEQout(struct riva_par *par, unsigned char index,
unsigned char val)
{
VGA_WR08(par->riva.PVIO, 0x3c4, index);
VGA_WR08(par->riva.PVIO, 0x3c5, val);
}
static inline unsigned char SEQin(struct riva_par *par,
unsigned char index)
{
VGA_WR08(par->riva.PVIO, 0x3c4, index);
return (VGA_RD08(par->riva.PVIO, 0x3c5));
}
static inline void ATTRout(struct riva_par *par, unsigned char index,
unsigned char val)
{
VGA_WR08(par->riva.PCIO, 0x3c0, index);
VGA_WR08(par->riva.PCIO, 0x3c0, val);
}
static inline unsigned char ATTRin(struct riva_par *par,
unsigned char index)
{
VGA_WR08(par->riva.PCIO, 0x3c0, index);
return (VGA_RD08(par->riva.PCIO, 0x3c1));
}
static inline void MISCout(struct riva_par *par, unsigned char val)
{
VGA_WR08(par->riva.PVIO, 0x3c2, val);
}
static inline unsigned char MISCin(struct riva_par *par)
{
return (VGA_RD08(par->riva.PVIO, 0x3cc));
}
/* ------------------------------------------------------------------------- *
*
* cursor stuff
*
* ------------------------------------------------------------------------- */
/**
* rivafb_load_cursor_image - load cursor image to hardware
* @data: address to monochrome bitmap (1 = foreground color, 0 = background)
* @mask: address to mask (1 = write image pixel, 0 = do not write pixel)
* @par: pointer to private data
* @w: width of cursor image in pixels
* @h: height of cursor image in scanlines
* @bg: background color (ARGB1555) - alpha bit determines opacity
* @fg: foreground color (ARGB1555)
*
* DESCRIPTiON:
* Loads cursor image based on a monochrome source and mask bitmap. The
* mask bit determines if the image pixel is to be written to the framebuffer
* or not. The imaage bits determines the color of the pixel, 0 for
* background, 1 for foreground. Only the affected region (as determined
* by @w and @h parameters) will be updated.
*
* CALLED FROM:
* rivafb_cursor()
*/
static void rivafb_load_cursor_image(u8 *data, u8 *mask, struct riva_par *par,
int w, int h, u16 bg, u16 fg)
{
int i, j, k = 0;
u32 b, m, tmp;
for (i = 0; i < h; i++) {
b = *((u32 *)data)++;
m = *((u32 *)mask)++;
for (j = 0; j < w/2; j++) {
tmp = 0;
#if defined (__BIG_ENDIAN__)
if (m & (1 << 31))
tmp = (b & (1 << 31)) ? fg << 16 : bg << 16;
b <<= 1;
m <<= 1;
if (m & (1 << 31))
tmp |= (b & (1 << 31)) ? fg : bg;
b <<= 1;
m <<= 1;
#else
if (m & 1)
tmp = (b & 1) ? fg : bg;
b >>= 1;
m >>= 1;
if (m & 1)
tmp |= (b & 1) ? fg << 16 : bg << 16;
b >>= 1;
m >>= 1;
#endif
writel(tmp, par->riva.CURSOR + k++);
}
k += (MAX_CURS - w)/2;
}
}
/* ------------------------------------------------------------------------- *
*
* general utility functions
*
* ------------------------------------------------------------------------- */
/**
* riva_wclut - set CLUT entry
* @chip: pointer to RIVA_HW_INST object
* @regnum: register number
* @red: red component
* @green: green component
* @blue: blue component
*
* DESCRIPTION:
* Sets color register @regnum.
*
* CALLED FROM:
* rivafb_setcolreg()
*/
static void riva_wclut(RIVA_HW_INST *chip,
unsigned char regnum, unsigned char red,
unsigned char green, unsigned char blue)
{
VGA_WR08(chip->PDIO, 0x3c8, regnum);
VGA_WR08(chip->PDIO, 0x3c9, red);
VGA_WR08(chip->PDIO, 0x3c9, green);
VGA_WR08(chip->PDIO, 0x3c9, blue);
}
/**
* riva_save_state - saves current chip state
* @par: pointer to riva_par object containing info for current riva board
* @regs: pointer to riva_regs object
*
* DESCRIPTION:
* Saves current chip state to @regs.
*
* CALLED FROM:
* rivafb_init_one()
*/
/* from GGI */
static void riva_save_state(struct riva_par *par, struct riva_regs *regs)
{
int i;
par->riva.LockUnlock(&par->riva, 0);
par->riva.UnloadStateExt(&par->riva, &regs->ext);
regs->misc_output = MISCin(par);
for (i = 0; i < NUM_CRT_REGS; i++) {
regs->crtc[i] = CRTCin(par, i);
}
for (i = 0; i < NUM_ATC_REGS; i++) {
regs->attr[i] = ATTRin(par, i);
}
for (i = 0; i < NUM_GRC_REGS; i++) {
regs->gra[i] = GRAin(par, i);
}
for (i = 0; i < NUM_SEQ_REGS; i++) {
regs->seq[i] = SEQin(par, i);
}
}
/**
* riva_load_state - loads current chip state
* @par: pointer to riva_par object containing info for current riva board
* @regs: pointer to riva_regs object
*
* DESCRIPTION:
* Loads chip state from @regs.
*
* CALLED FROM:
* riva_load_video_mode()
* rivafb_init_one()
* rivafb_remove_one()
*/
/* from GGI */
static void riva_load_state(struct riva_par *par, struct riva_regs *regs)
{
RIVA_HW_STATE *state = &regs->ext;
int i;
CRTCout(par, 0x11, 0x00);
par->riva.LockUnlock(&par->riva, 0);
par->riva.LoadStateExt(&par->riva, state);
MISCout(par, regs->misc_output);
for (i = 0; i < NUM_CRT_REGS; i++) {
switch (i) {
case 0x19:
case 0x20 ... 0x40:
break;
default:
CRTCout(par, i, regs->crtc[i]);
}
}
for (i = 0; i < NUM_ATC_REGS; i++) {
ATTRout(par, i, regs->attr[i]);
}
for (i = 0; i < NUM_GRC_REGS; i++) {
GRAout(par, i, regs->gra[i]);
}
for (i = 0; i < NUM_SEQ_REGS; i++) {
SEQout(par, i, regs->seq[i]);
}
}
/**
* riva_load_video_mode - calculate timings
* @info: pointer to fb_info object containing info for current riva board
* @video_mode: video mode to set
*
* DESCRIPTION:
* Calculate some timings and then send em off to riva_load_state().
*
* CALLED FROM:
* rivafb_set_var()
*/
static void riva_load_video_mode(struct fb_info *info)
{
int bpp, width, hDisplaySize, hDisplay, hStart,
hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock;
int hBlankStart, hBlankEnd, vBlankStart, vBlankEnd;
struct riva_par *par = (struct riva_par *) info->par;
struct riva_regs newmode;
/* time to calculate */
rivafb_blank(1, info);
bpp = info->var.bits_per_pixel;
if (bpp == 16 && info->var.green.length == 5)
bpp = 15;
width = info->var.xres_virtual;
hDisplaySize = info->var.xres;
hDisplay = (hDisplaySize / 8) - 1;
hStart = (hDisplaySize + info->var.right_margin) / 8 + 2;
hEnd = (hDisplaySize + info->var.right_margin +
info->var.hsync_len) / 8 - 1;
hTotal = (hDisplaySize + info->var.right_margin +
info->var.hsync_len + info->var.left_margin) / 8 - 5;
hBlankStart = hDisplay;
hBlankEnd = hTotal + 4;
height = info->var.yres_virtual;
vDisplay = info->var.yres - 1;
vStart = info->var.yres + info->var.lower_margin - 1;
vEnd = info->var.yres + info->var.lower_margin +
info->var.vsync_len - 1;
vTotal = info->var.yres + info->var.lower_margin +
info->var.vsync_len + info->var.upper_margin + 2;
vBlankStart = vDisplay;
vBlankEnd = vTotal + 1;
dotClock = PICOS2KHZ(info->var.pixclock);
memcpy(&newmode, &reg_template, sizeof(struct riva_regs));
newmode.crtc[0x0] = Set8Bits (hTotal - 4);
if (par->FlatPanel) {
vStart = vTotal - 3;
vEnd = vTotal - 2;
vBlankStart = vStart;
hStart = hTotal - 3;
hEnd = hTotal - 2;
hBlankEnd = hTotal + 4;
}
newmode.crtc[0x0] = Set8Bits (hTotal);
newmode.crtc[0x1] = Set8Bits (hDisplay);
newmode.crtc[0x2] = Set8Bits (hBlankStart);
newmode.crtc[0x3] = SetBitField (hBlankEnd, 4: 0, 4:0) | SetBit (7);
newmode.crtc[0x4] = Set8Bits (hStart);
newmode.crtc[0x5] = SetBitField (hBlankEnd, 5: 5, 7:7)
| SetBitField (hEnd, 4: 0, 4:0);
newmode.crtc[0x6] = SetBitField (vTotal, 7: 0, 7:0);
newmode.crtc[0x7] = SetBitField (vTotal, 8: 8, 0:0)
| SetBitField (vDisplay, 8: 8, 1:1)
| SetBitField (vStart, 8: 8, 2:2)
| SetBitField (vBlankStart, 8: 8, 3:3)
| SetBit (4)
| SetBitField (vTotal, 9: 9, 5:5)
| SetBitField (vDisplay, 9: 9, 6:6)
| SetBitField (vStart, 9: 9, 7:7);
newmode.crtc[0x9] = SetBitField (vBlankStart, 9: 9, 5:5)
| SetBit (6);
newmode.crtc[0x10] = Set8Bits (vStart);
newmode.crtc[0x11] = SetBitField (vEnd, 3: 0, 3:0)
| SetBit (5);
newmode.crtc[0x12] = Set8Bits (vDisplay);
newmode.crtc[0x13] = (width / 8) * ((bpp + 1) / 8);
newmode.crtc[0x15] = Set8Bits (vBlankStart);
newmode.crtc[0x16] = Set8Bits (vBlankEnd + 1);
newmode.ext.screen = SetBitField(hBlankEnd,6:6,4:4)
| SetBitField(vBlankStart,10:10,3:3)
| SetBitField(vStart,10:10,2:2)
| SetBitField(vDisplay,10:10,1:1)
| SetBitField(vTotal,10:10,0:0);
newmode.ext.horiz = SetBitField(hTotal,8:8,0:0)
| SetBitField(hDisplay,8:8,1:1)
| SetBitField(hBlankStart,8:8,2:2)
| SetBitField(hStart,8:8,3:3);
newmode.ext.extra = SetBitField(vTotal,11:11,0:0)
| SetBitField(vDisplay,11:11,2:2)
| SetBitField(vStart,11:11,4:4)
| SetBitField(vBlankStart,11:11,6:6);
newmode.ext.interlace = 0xff; /* interlace off */
if(par->riva.Architecture >= NV_ARCH_10)
par->riva.CURSOR = (U032 *)(info->screen_base + par->riva.CursorStart);
par->riva.CalcStateExt(&par->riva, &newmode.ext, bpp, width,
hDisplaySize, height, dotClock);
newmode.ext.scale = par->riva.PRAMDAC[0x00000848/4] & 0xfff000ff;
if(par->FlatPanel == 1) {
newmode.ext.pixel |= (1 << 7);
newmode.ext.scale |= (1 << 8) ;
}
if(par->SecondCRTC) {
newmode.ext.head = par->riva.PCRTC0[0x00000860/4] & ~0x00001000;
newmode.ext.head2 = par->riva.PCRTC0[0x00002860/4] | 0x00001000;
newmode.ext.crtcOwner = 3;
newmode.ext.pllsel |= 0x20000800;
newmode.ext.vpll2 = newmode.ext.vpll;
} else if(par->riva.twoHeads) {
newmode.ext.head = par->riva.PCRTC0[0x00000860/4] | 0x00001000;
newmode.ext.head2 = par->riva.PCRTC0[0x00002860/4] & ~0x00001000;
newmode.ext.crtcOwner = 0;
newmode.ext.vpll2 = par->riva.PRAMDAC0[0x00000520/4];
}
newmode.ext.cursorConfig = 0x02000100;
par->current_state = newmode;
riva_load_state(par, &par->current_state);
rivafb_blank(0, info);
}
/**
* rivafb_do_maximize -
* @info: pointer to fb_info object containing info for current riva board
* @var:
* @nom:
* @den:
*
* DESCRIPTION:
* .
*
* RETURNS:
* -EINVAL on failure, 0 on success
*
*
* CALLED FROM:
* rivafb_set_var()
*/
static int rivafb_do_maximize(struct fb_info *info,
struct fb_var_screeninfo *var,
int nom, int den)
{
static struct {
int xres, yres;
} modes[] = {
{1600, 1280},
{1280, 1024},
{1024, 768},
{800, 600},
{640, 480},
{-1, -1}
};
int i;
/* use highest possible virtual resolution */
if (var->xres_virtual == -1 && var->yres_virtual == -1) {
printk(KERN_WARNING PFX
"using maximum available virtual resolution\n");
for (i = 0; modes[i].xres != -1; i++) {
if (modes[i].xres * nom / den * modes[i].yres <
info->fix.smem_len / 2)
break;
}
if (modes[i].xres == -1) {
printk(KERN_ERR PFX
"could not find a virtual resolution that fits into video memory!!\n");
DPRINTK("EXIT - EINVAL error\n");
return -EINVAL;
}
var->xres_virtual = modes[i].xres;
var->yres_virtual = modes[i].yres;
printk(KERN_INFO PFX
"virtual resolution set to maximum of %dx%d\n",
var->xres_virtual, var->yres_virtual);
} else if (var->xres_virtual == -1) {
var->xres_virtual = (info->fix.smem_len * den /
(nom * var->yres_virtual * 2)) & ~15;
printk(KERN_WARNING PFX
"setting virtual X resolution to %d\n", var->xres_virtual);
} else if (var->yres_virtual == -1) {
var->xres_virtual = (var->xres_virtual + 15) & ~15;
var->yres_virtual = info->fix.smem_len * den /
(nom * var->xres_virtual * 2);
printk(KERN_WARNING PFX
"setting virtual Y resolution to %d\n", var->yres_virtual);
} else {
var->xres_virtual = (var->xres_virtual + 15) & ~15;
if (var->xres_virtual * nom / den * var->yres_virtual > info->fix.smem_len) {
printk(KERN_ERR PFX
"mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
var->xres, var->yres, var->bits_per_pixel);
DPRINTK("EXIT - EINVAL error\n");
return -EINVAL;
}
}
if (var->xres_virtual * nom / den >= 8192) {
printk(KERN_WARNING PFX
"virtual X resolution (%d) is too high, lowering to %d\n",
var->xres_virtual, 8192 * den / nom - 16);
var->xres_virtual = 8192 * den / nom - 16;
}
if (var->xres_virtual < var->xres) {
printk(KERN_ERR PFX
"virtual X resolution (%d) is smaller than real\n", var->xres_virtual);
return -EINVAL;
}
if (var->yres_virtual < var->yres) {
printk(KERN_ERR PFX
"virtual Y resolution (%d) is smaller than real\n", var->yres_virtual);
return -EINVAL;
}
return 0;
}
/* acceleration routines */
inline void wait_for_idle(struct riva_par *par)
{
while (par->riva.Busy(&par->riva));
}
/* set copy ROP, no mask */
static void riva_setup_ROP(struct riva_par *par)
{
RIVA_FIFO_FREE(par->riva, Patt, 5);
par->riva.Patt->Shape = 0;
par->riva.Patt->Color0 = 0xffffffff;
par->riva.Patt->Color1 = 0xffffffff;
par->riva.Patt->Monochrome[0] = 0xffffffff;
par->riva.Patt->Monochrome[1] = 0xffffffff;
RIVA_FIFO_FREE(par->riva, Rop, 1);
par->riva.Rop->Rop3 = 0xCC;
}
void riva_setup_accel(struct riva_par *par)
{
RIVA_FIFO_FREE(par->riva, Clip, 2);
par->riva.Clip->TopLeft = 0x0;
par->riva.Clip->WidthHeight = 0x80008000;
riva_setup_ROP(par);
}
/**
* rivafb_fillrect - hardware accelerated color fill function
* @info: pointer to fb_info structure
* @rect: pointer to fb_fillrect structure
*
* DESCRIPTION:
* This function fills up a region of framebuffer memory with a solid
* color with a choice of two different ROP's, copy or invert.
*
* CALLED FROM:
* framebuffer hook
*/
static void rivafb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
{
struct riva_par *par = (struct riva_par *) info->par;
u_int color, rop = 0;
if (info->var.bits_per_pixel == 8)
color = rect->color;
else
color = par->riva_palette[rect->color];
switch (rect->rop) {
case ROP_XOR:
rop = 0x66;
break;
case ROP_COPY:
default:
rop = 0xCC;
break;
}
RIVA_FIFO_FREE(par->riva, Rop, 1);
par->riva.Rop->Rop3 = rop;
RIVA_FIFO_FREE(par->riva, Bitmap, 1);
par->riva.Bitmap->Color1A = color;
RIVA_FIFO_FREE(par->riva, Bitmap, 2);
par->riva.Bitmap->UnclippedRectangle[0].TopLeft =
(rect->dx << 16) | rect->dy;
par->riva.Bitmap->UnclippedRectangle[0].WidthHeight =
(rect->width << 16) | rect->height;
}
/**
* rivafb_copyarea - hardware accelerated blit function
* @info: pointer to fb_info structure
* @region: pointer to fb_copyarea structure
*
* DESCRIPTION:
* This copies an area of pixels from one location to another
*
* CALLED FROM:
* framebuffer hook
*/
static void rivafb_copyarea(struct fb_info *info, struct fb_copyarea *region)
{
struct riva_par *par = (struct riva_par *) info->par;
RIVA_FIFO_FREE(par->riva, Blt, 3);
par->riva.Blt->TopLeftSrc = (region->sy << 16) | region->sx;
par->riva.Blt->TopLeftDst = (region->dy << 16) | region->dx;
par->riva.Blt->WidthHeight = (region->height << 16) | region->width;
wait_for_idle(par);
}
static u8 byte_rev[256] = {
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
};
/**
* rivafb_imageblit: hardware accelerated color expand function
* @info: pointer to fb_info structure
* @image: pointer to fb_image structure
*
* DESCRIPTION:
* If the source is a monochrome bitmap, the function fills up a a region
* of framebuffer memory with pixels whose color is determined by the bit
* setting of the bitmap, 1 - foreground, 0 - background.
*
* If the source is not a monochrome bitmap, color expansion is not done.
* In this case, it is channeled to a software function.
*
* CALLED FROM:
* framebuffer hook
*/
static void rivafb_imageblit(struct fb_info *info, struct fb_image *image)
{
struct riva_par *par = (struct riva_par *) info->par;
u8 *cdat = image->data, *dat;
int w, h, dx, dy;
volatile u32 *d;
u32 fgx = 0, bgx = 0, size, width, mod;
int i, j;
if (image->depth != 1) {
wait_for_idle(par);
cfb_imageblit(info, image);
return;
}
w = image->width;
h = image->height;
dx = image->dx;
dy = image->dy;
width = (w + 7)/8;
size = width * h;
dat = cdat;
for (i = 0; i < size; i++) {
*dat = byte_rev[*dat];
dat++;
}
switch (info->var.bits_per_pixel) {
case 8:
fgx = image->fg_color | ~((1 << 8) - 1);
bgx = image->bg_color | ~((1 << 8) - 1);
break;
case 16:
/* set alpha bit */
if (info->var.green.length == 5) {
fgx = 1 << 15;
bgx = fgx;
}
/* Fall through... */
case 32:
fgx |= par->riva_palette[image->fg_color];
bgx |= par->riva_palette[image->bg_color];
break;
}
RIVA_FIFO_FREE(par->riva, Bitmap, 7);
par->riva.Bitmap->ClipE.TopLeft = (dy << 16) | (dx & 0xFFFF);
par->riva.Bitmap->ClipE.BottomRight = (((dy + h) << 16) |
((dx + w) & 0xffff));
par->riva.Bitmap->Color0E = bgx;
par->riva.Bitmap->Color1E = fgx;
par->riva.Bitmap->WidthHeightInE = (h << 16) | ((w + 31) & ~31);
par->riva.Bitmap->WidthHeightOutE = (h << 16) | ((w + 31) & ~31);
par->riva.Bitmap->PointE = (dy << 16) | (dx & 0xFFFF);
d = &par->riva.Bitmap->MonochromeData01E;
mod = width % 4;
if (width >= 4) {
while (h--) {
size = width / 4;
while (size >= 16) {
RIVA_FIFO_FREE(par->riva, Bitmap, 16);
for (i = 0; i < 16; i++)
d[i] = *((u32 *)cdat)++;
size -= 16;
}
if (size) {
RIVA_FIFO_FREE(par->riva, Bitmap, size);
for (i = 0; i < size; i++)
d[i] = *((u32 *) cdat)++;
}
if (mod) {
u32 tmp;
RIVA_FIFO_FREE(par->riva, Bitmap, 1);
for (i = 0; i < mod; i++)
((u8 *)&tmp)[i] = *cdat++;
d[i] = tmp;
}
}
}
else {
u32 k, tmp;
for (i = h; i > 0; i-=16) {
if (i >= 16)
size = 16;
else
size = i;
RIVA_FIFO_FREE(par->riva, Bitmap, size);
for (j = 0; j < size; j++) {
for (k = 0; k < width; k++)
((u8 *)&tmp)[k] = *cdat++;
d[j] = tmp;
}
}
}
}
/**
* rivafb_cursor - hardware cursor function
* @info: pointer to info structure
* @cursor: pointer to fbcursor structure
*
* DESCRIPTION:
* A cursor function that supports displaying a cursor image via hardware.
* Within the kernel, copy and invert rops are supported. If exported
* to user space, only the copy rop will be supported.
*
* CALLED FROM
* framebuffer hook
*/
static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
static u8 data[MAX_CURS*MAX_CURS/8], mask[MAX_CURS*MAX_CURS/8];
struct riva_par *par = (struct riva_par *) info->par;
int i, j, d_idx = 0, s_idx = 0;
u16 flags = cursor->set, fg, bg;
/*
* Can't do invert if one of the operands (dest) is missing,
* ie, only opaque cursor supported. This should be
* standard for GUI apps.
*/
if (cursor->dest == NULL && cursor->rop == ROP_XOR)
return 1;
if (par->cursor_reset) {
flags = FB_CUR_SETALL;
par->cursor_reset = 0;
}
par->riva.ShowHideCursor(&par->riva, 0);
if (flags & FB_CUR_SETPOS) {
u32 xx, yy, temp;
yy = cursor->image.dy - info->var.yoffset;
xx = cursor->image.dx - info->var.xoffset;
temp = xx & 0xFFFF;
temp |= yy << 16;
par->riva.PRAMDAC[0x0000300/4] = temp;
}
if (flags & FB_CUR_SETSIZE) {
memset(data, 0, MAX_CURS * MAX_CURS/8);
memset(mask, 0, MAX_CURS * MAX_CURS/8);
memset_io(par->riva.CURSOR, 0, MAX_CURS * MAX_CURS * 2);
}
if (flags & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETDEST)) {
int bg_idx = cursor->image.bg_color;
int fg_idx = cursor->image.fg_color;
switch (cursor->rop) {
case ROP_XOR:
for (i = 0; i < cursor->image.height; i++) {
for (j = 0; j < (cursor->image.width + 7)/8;
j++) {
d_idx = i * MAX_CURS/8 + j;
data[d_idx] = byte_rev[((u8 *)cursor->image.data)[s_idx] ^
((u8 *)cursor->dest)[s_idx]];
mask[d_idx] = byte_rev[((u8 *)cursor->mask)[s_idx]];
s_idx++;
}
}
break;
case ROP_COPY:
default:
for (i = 0; i < cursor->image.height; i++) {
for (j = 0; j < (cursor->image.width + 7)/8; j++) {
d_idx = i * MAX_CURS/8 + j;
data[d_idx] = byte_rev[((u8 *)cursor->image.data)[s_idx]];
mask[d_idx] = byte_rev[((u8 *)cursor->mask)[s_idx]];
s_idx++;
}
}
break;
}
bg = ((par->cmap[bg_idx].red & 0xf8) << 7) |
((par->cmap[bg_idx].green & 0xf8) << 2) |
((par->cmap[bg_idx].blue & 0xf8) >> 3) | 1 << 15;
fg = ((par->cmap[fg_idx].red & 0xf8) << 7) |
((par->cmap[fg_idx].green & 0xf8) << 2) |
((par->cmap[fg_idx].blue & 0xf8) >> 3) | 1 << 15;
par->riva.LockUnlock(&par->riva, 0);
rivafb_load_cursor_image(data, mask, par, cursor->image.width,
cursor->image.height, bg, fg);
}
if (cursor->enable)
par->riva.ShowHideCursor(&par->riva, 1);
return 0;
}
static int rivafb_sync(struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
wait_for_idle(par);
return 0;
}
/* ------------------------------------------------------------------------- *
*
* internal fb_ops helper functions
*
* ------------------------------------------------------------------------- */
/**
* riva_get_cmap_len - query current color map length
* @var: standard kernel fb changeable data
*
* DESCRIPTION:
* Get current color map length.
*
* RETURNS:
* Length of color map
*
* CALLED FROM:
* riva_getcolreg()
* rivafb_setcolreg()
* rivafb_get_cmap()
* rivafb_set_cmap()
*/
static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
{
int rc = 16; /* reasonable default */
assert(var != NULL);
switch (var->green.length) {
case 5:
rc = 32; /* fix for 15 bpp depths on Riva 128 based cards */
break;
case 6:
rc = 64; /* directcolor... 16 entries SW palette */
break; /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
default:
rc = 256; /* pseudocolor... 256 entries HW palette */
break;
}
return rc;
}
/* ------------------------------------------------------------------------- *
*
* framebuffer operations
*
* ------------------------------------------------------------------------- */
static int rivafb_open(struct fb_info *info, int user)
{
struct riva_par *par = (struct riva_par *) info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt) {
memset(&par->state, 0, sizeof(struct vgastate));
par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONT0;
/* save the DAC for Riva128 */
if (par->riva.Architecture == NV_ARCH_03)
par->state.flags |= VGA_SAVE_CMAP;
save_vga(&par->state);
RivaGetConfig(&par->riva, par->Chipset);
riva_save_state(par, &par->initial_state);
}
atomic_inc(&par->ref_count);
return 0;
}
static int rivafb_release(struct fb_info *info, int user)
{
struct riva_par *par = (struct riva_par *) info->par;
int cnt = atomic_read(&par->ref_count);
if (!cnt)
return -EINVAL;
if (cnt == 1) {
riva_load_state(par, &par->initial_state);
par->riva.LockUnlock(&par->riva, 1);
restore_vga(&par->state);
}
atomic_dec(&par->ref_count);
return 0;
}
static int rivafb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
int nom, den; /* translating from pixels->bytes */
if (par->riva.Architecture == NV_ARCH_03 &&
var->bits_per_pixel == 16)
var->bits_per_pixel = 15;
switch (var->bits_per_pixel) {
case 1 ... 8:
var->bits_per_pixel = 8;
nom = 1;
den = 1;
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 0;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
break;
case 9 ... 15:
var->green.length = 5;
/* fall through */
case 16:
var->bits_per_pixel = 16;
nom = 2;
den = 1;
if (var->green.length == 5) {
/* 0rrrrrgg gggbbbbb */
var->red.offset = 10;
var->green.offset = 5;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 5;
var->blue.length = 5;
} else {
/* rrrrrggg gggbbbbb */
var->red.offset = 11;
var->green.offset = 5;
var->blue.offset = 0;
var->red.length = 5;
var->green.length = 6;
var->blue.length = 5;
}
break;
case 17 ... 32:
var->bits_per_pixel = 32;
nom = 4;
den = 1;
var->red.offset = 16;
var->green.offset = 8;
var->blue.offset = 0;
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
break;
default:
printk(KERN_ERR PFX
"mode %dx%dx%d rejected...color depth not supported.\n",
var->xres, var->yres, var->bits_per_pixel);
DPRINTK("EXIT, returning -EINVAL\n");
return -EINVAL;
}
if (rivafb_do_maximize(info, var, nom, den) < 0)
return -EINVAL;
if (var->xoffset < 0)
var->xoffset = 0;
if (var->yoffset < 0)
var->yoffset = 0;
/* truncate xoffset and yoffset to maximum if too high */
if (var->xoffset > var->xres_virtual - var->xres)
var->xoffset = var->xres_virtual - var->xres - 1;
if (var->yoffset > var->yres_virtual - var->yres)
var->yoffset = var->yres_virtual - var->yres - 1;
var->red.msb_right =
var->green.msb_right =
var->blue.msb_right =
var->transp.offset = var->transp.length = var->transp.msb_right = 0;
return 0;
}
static int rivafb_set_par(struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
riva_load_video_mode(info);
if (info->var.accel_flags) {
riva_setup_accel(par);
info->fbops->fb_fillrect = rivafb_fillrect;
info->fbops->fb_copyarea = rivafb_copyarea;
info->fbops->fb_imageblit = rivafb_imageblit;
info->fbops->fb_cursor = rivafb_cursor;
info->fbops->fb_sync = rivafb_sync;
}
else {
info->fbops->fb_fillrect = cfb_fillrect;
info->fbops->fb_copyarea = cfb_copyarea;
info->fbops->fb_imageblit = cfb_imageblit;
info->fbops->fb_cursor = soft_cursor;
info->fbops->fb_sync = NULL;
}
info->fix.line_length = (info->var.xres_virtual * (info->var.bits_per_pixel >> 3));
info->fix.visual = (info->var.bits_per_pixel == 8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
return 0;
}
/**
* rivafb_pan_display
* @var: standard kernel fb changeable data
* @con: TODO
* @info: pointer to rivafb_info object containing info for current riva board
*
* DESCRIPTION:
* Pan (or wrap, depending on the `vmode' field) the display using the
* `xoffset' and `yoffset' fields of the `var' structure.
* If the values don't fit, return -EINVAL.
*
* This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
*/
static int rivafb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
unsigned int base;
if (var->xoffset > (var->xres_virtual - var->xres))
return -EINVAL;
if (var->yoffset > (var->yres_virtual - var->yres))
return -EINVAL;
if (var->vmode & FB_VMODE_YWRAP) {
if (var->yoffset < 0
|| var->yoffset >= info->var.yres_virtual
|| var->xoffset) return -EINVAL;
} else {
if (var->xoffset + info->var.xres > info->var.xres_virtual ||
var->yoffset + info->var.yres > info->var.yres_virtual)
return -EINVAL;
}
base = var->yoffset * info->fix.line_length + var->xoffset;
par->riva.SetStartAddress(&par->riva, base);
info->var.xoffset = var->xoffset;
info->var.yoffset = var->yoffset;
if (var->vmode & FB_VMODE_YWRAP)
info->var.vmode |= FB_VMODE_YWRAP;
else
info->var.vmode &= ~FB_VMODE_YWRAP;
/*
* HACK: The hardware cursor occasionally disappears during fast scrolling.
* We just reset the cursor each time we change the start address.
* This also has a beneficial side effect of restoring the cursor
* image when switching from X.
*/
par->cursor_reset = 1;
DPRINTK("EXIT, returning 0\n");
return 0;
}
static int rivafb_blank(int blank, struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
unsigned char tmp, vesa;
tmp = SEQin(par, 0x01) & ~0x20; /* screen on/off */
vesa = CRTCin(par, 0x1a) & ~0xc0; /* sync on/off */
if (blank) {
tmp |= 0x20;
switch (blank - 1) {
case VESA_NO_BLANKING:
break;
case VESA_VSYNC_SUSPEND:
vesa |= 0x80;
break;
case VESA_HSYNC_SUSPEND:
vesa |= 0x40;
break;
case VESA_POWERDOWN:
vesa |= 0xc0;
break;
}
}
SEQout(par, 0x01, tmp);
CRTCout(par, 0x1a, vesa);
DPRINTK("EXIT\n");
return 0;
}
/**
* rivafb_setcolreg
* @regno: register index
* @red: red component
* @green: green component
* @blue: blue component
* @transp: transparency
* @info: pointer to rivafb_info object containing info for current riva board
*
* DESCRIPTION:
* Set a single color register. The values supplied have a 16 bit
* magnitude.
*
* RETURNS:
* Return != 0 for invalid regno.
*
* CALLED FROM:
* rivafb_set_cmap()
* fbcmap.c:fb_set_cmap()
* fbgen.c:fbgen_get_cmap()
* fbgen.c:do_install_cmap()
* fbgen.c:fbgen_set_var()
* fbgen.c:fbgen_switch()
* fbgen.c:fbgen_blank()
* fbgen.c:fbgen_blank()
*/
static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
struct riva_par *par = (struct riva_par *) info->par;
RIVA_HW_INST *chip = &par->riva;
int i;
if (regno >= riva_get_cmap_len(&info->var))
return -EINVAL;
if (info->var.grayscale) {
/* gray = 0.30*R + 0.59*G + 0.11*B */
red = green = blue =
(red * 77 + green * 151 + blue * 28) >> 8;
}
if (!regno) {
for (i = 0; i < 256; i++) {
par->cmap[i].red = 0;
par->cmap[i].green = 0;
par->cmap[i].blue = 0;
}
}
par->cmap[regno].red = (u8) red;
par->cmap[regno].green = (u8) green;
par->cmap[regno].blue = (u8) blue;
if (info->var.green.length == 5) {
/* RGB555: all components have 32 entries, 8 indices apart */
for (i = 0; i < 8; i++)
riva_wclut(chip, (regno*8)+i, (u8) red, (u8) green, (u8) blue);
}
else if (info->var.green.length == 6) {
/*
* RGB 565: red and blue have 32 entries, 8 indices apart, while
* green has 64 entries, 4 indices apart
*/
if (regno < 32) {
for (i = 0; i < 8; i++) {
riva_wclut(chip, (regno*8)+i, (u8) red,
par->cmap[regno*2].green,
(u8) blue);
}
}
for (i = 0; i < 4; i++) {
riva_wclut(chip, (regno*4)+i, par->cmap[regno/2].red,
(u8) green, par->cmap[regno/2].blue);
}
}
else {
riva_wclut(chip, regno, (u8) red, (u8) green, (u8) blue);
}
if (regno < 16) {
switch (info->var.bits_per_pixel) {
case 16:
if (info->var.green.length == 5) {
/* 0rrrrrgg gggbbbbb */
((u32 *)(info->pseudo_palette))[regno] =
(regno << 10) | (regno << 5) | regno;
par->riva_palette[regno] =
((red & 0xf800) >> 1) |
((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
} else {
/* rrrrrggg gggbbbbb */
((u32 *)(info->pseudo_palette))[regno] =
(regno << 11) | (regno << 6) | regno;
par->riva_palette[regno] = ((red & 0xf800) >> 0) |
((green & 0xf800) >> 5) | ((blue & 0xf800) >> 11);
}
break;
case 32:
((u32 *)(info->pseudo_palette))[regno] =
(regno << 16) | (regno << 8) | regno;
par->riva_palette[regno] =
((red & 0xff00) << 8) |
((green & 0xff00)) | ((blue & 0xff00) >> 8);
break;
default:
/* do nothing */
break;
}
}
return 0;
}
/* ------------------------------------------------------------------------- *
*
* initialization helper functions
*
* ------------------------------------------------------------------------- */
/* kernel interface */
static struct fb_ops riva_fb_ops = {
.owner = THIS_MODULE,
.fb_open = rivafb_open,
.fb_release = rivafb_release,
.fb_check_var = rivafb_check_var,
.fb_set_par = rivafb_set_par,
.fb_setcolreg = rivafb_setcolreg,
.fb_pan_display=rivafb_pan_display,
.fb_blank = rivafb_blank,
.fb_fillrect = rivafb_fillrect,
.fb_copyarea = rivafb_copyarea,
.fb_imageblit = rivafb_imageblit,
.fb_cursor = rivafb_cursor,
.fb_sync = rivafb_sync,
};
static int __devinit riva_set_fbinfo(struct fb_info *info)
{
unsigned int cmap_len;
info->node = NODEV;
info->flags = FBINFO_FLAG_DEFAULT;
info->fbops = &riva_fb_ops;
info->var = rivafb_default_var;
info->fix = rivafb_fix;
/* FIXME: set monspecs to what??? */
info->display_fg = NULL;
info->pseudo_palette = pseudo_palette;
cmap_len = riva_get_cmap_len(&info->var);
fb_alloc_cmap(&info->cmap, cmap_len, 0);
#ifndef MODULE
if (mode_option)
fb_find_mode(&info->var, info, mode_option,
NULL, 0, NULL, 8);
#endif
info->fix.line_length = (info->var.xres_virtual * (info->var.bits_per_pixel >> 3));
info->fix.visual = (info->var.bits_per_pixel == 8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
return 0;
}
/* ------------------------------------------------------------------------- *
*
* PCI bus
*
* ------------------------------------------------------------------------- */
static void __devinit rivafb_get_mem_len(struct riva_par *par,
struct fb_fix_screeninfo *fix)
{
RIVA_HW_INST *chip = &par->riva;
switch (chip->Architecture) {
case NV_ARCH_03:
if (chip->PFB[0x00000000/4] & 0x00000020) {
if (((chip->PMC[0x00000000/4] & 0xF0) == 0x20)
&& ((chip->PMC[0x00000000/4] & 0x0F) >= 0x02)) {
/*
* SDRAM 128 ZX.
*/
switch (chip->PFB[0x00000000/4] & 0x03) {
case 2:
fix->smem_len = 1024 * 1024 * 4;
break;
case 1:
fix->smem_len = 1024 * 1024 * 2;
break;
default:
fix->smem_len = 1024 * 1024 * 8;
break;
}
}
else {
fix->smem_len = 1024 * 1024 * 8;
}
}
else {
/*
* SGRAM 128.
*/
switch (chip->PFB[0x00000000/4] & 0x00000003) {
case 0:
fix->smem_len = 1024 * 1024 * 8;
break;
case 2:
fix->smem_len = 1024 * 1024 * 4;
break;
default:
fix->smem_len = 1024 * 1024 * 2;
break;
}
}
break;
case NV_ARCH_04:
if (chip->PFB[0x00000000/4] & 0x00000100) {
fix->smem_len = (((chip->PFB[0x00000000/4] >> 12)
& 0x0F) * 1024 * 2 + 1024 * 2) * 1024;
}
else {
switch (chip->PFB[0x00000000/4] & 0x00000003) {
case 0:
fix->smem_len = 1024 * 1024 * 32;
break;
case 1:
fix->smem_len = 1024 * 1024 * 4;
break;
case 2:
fix->smem_len = 1024 * 1024 * 8;
break;
case 3:
default:
fix->smem_len = 1024 * 1024 * 16;
break;
}
}
break;
case NV_ARCH_10:
case NV_ARCH_20:
switch ((chip->PFB[0x0000020C/4] >> 20) & 0x000000FF) {
case 0x02:
fix->smem_len = 1024 * 1024 * 2;
break;
case 0x04:
fix->smem_len = 1024 * 1024 * 4;
break;
case 0x08:
fix->smem_len = 1024 * 1024 * 8;
break;
case 0x10:
fix->smem_len = 1024 * 1024 * 16;
break;
case 0x20:
fix->smem_len = 1024 * 1024 * 32;
break;
case 0x40:
fix->smem_len = 1024 * 1024 * 64;
break;
case 0x80:
fix->smem_len = 1024 * 1024 * 128;
break;
default:
fix->smem_len = 1024 * 1024 * 16;
break;
}
}
}
static int __devinit rivafb_init_one(struct pci_dev *pd,
const struct pci_device_id *ent)
{
struct riva_chip_info *rci = &riva_chip_info[ent->driver_data];
struct riva_par *default_par;
struct fb_info *info;
assert(pd != NULL);
assert(rci != NULL);
info = kmalloc(sizeof(struct fb_info), GFP_KERNEL);
if (!info)
goto err_out;
default_par = kmalloc(sizeof(struct riva_par), GFP_KERNEL);
if (!default_par)
goto err_out_kfree;
memset(info, 0, sizeof(struct fb_info));
memset(default_par, 0, sizeof(struct riva_par));
strcat(rivafb_fix.id, rci->name);
default_par->riva.Architecture = rci->arch_rev;
default_par->Chipset = pd->device;
printk(KERN_INFO PFX "nVidia device/chipset %X\n",default_par->Chipset);
/*default_par->FlatPanel = flatpanel;
if (flatpanel == 1)
printk(KERN_INFO PFX "flatpanel support enabled\n");
default_par->forceCRTC = forceCRTC;
*/
rivafb_fix.mmio_len = pci_resource_len(pd, 0);
rivafb_fix.smem_len = pci_resource_len(pd, 1);
rivafb_fix.mmio_start = pci_resource_start(pd, 0);
rivafb_fix.smem_start = pci_resource_start(pd, 1);
if (!request_mem_region(rivafb_fix.mmio_start,
rivafb_fix.mmio_len, "rivafb")) {
printk(KERN_ERR PFX "cannot reserve MMIO region\n");
goto err_out_kfree;
}
default_par->ctrl_base = ioremap(rivafb_fix.mmio_start,
rivafb_fix.mmio_len);
if (!default_par->ctrl_base) {
printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
goto err_out_free_base0;
}
info->screen_base = ioremap(rivafb_fix.smem_start,
rivafb_fix.smem_len);
if (!info->screen_base) {
printk(KERN_ERR PFX "cannot ioremap FB base\n");
goto err_out_iounmap_ctrl;
}
default_par->riva.EnableIRQ = 0;
default_par->riva.PRAMDAC = (unsigned *)(default_par->ctrl_base +
0x00680000);
default_par->riva.PFB = (unsigned *)(default_par->ctrl_base +
0x00100000);
default_par->riva.PFIFO = (unsigned *)(default_par->ctrl_base +
0x00002000);
default_par->riva.PGRAPH = (unsigned *)(default_par->ctrl_base +
0x00400000);
default_par->riva.PEXTDEV = (unsigned *)(default_par->ctrl_base +
0x00101000);
default_par->riva.PTIMER = (unsigned *)(default_par->ctrl_base +
0x00009000);
default_par->riva.PMC = (unsigned *)(default_par->ctrl_base +
0x00000000);
default_par->riva.FIFO = (unsigned *)(default_par->ctrl_base +
0x00800000);
default_par->riva.PCIO = (U008 *)(default_par->ctrl_base + 0x00601000);
default_par->riva.PDIO = (U008 *)(default_par->ctrl_base + 0x00681000);
default_par->riva.PVIO = (U008 *)(default_par->ctrl_base + 0x000C0000);
default_par->riva.IO = (MISCin(default_par) & 0x01) ? 0x3D0 : 0x3B0;
switch (default_par->riva.Architecture) {
case NV_ARCH_03:
default_par->riva.PRAMIN = (unsigned *)(info->screen_base +
0x00C00000);
default_par->dclk_max = 256000000;
rivafb_fix.accel = FB_ACCEL_NV3;
break;
case NV_ARCH_04:
case NV_ARCH_10:
case NV_ARCH_20:
default_par->riva.PCRTC = (unsigned *)(default_par->ctrl_base
+ 0x00600000);
default_par->riva.PRAMIN = (unsigned *)(default_par->ctrl_base
+ 0x00710000);
default_par->dclk_max = 250000000;
rivafb_fix.accel = FB_ACCEL_NV4;
break;
}
rivafb_get_mem_len(default_par, &rivafb_fix);
info->par = default_par;
if (!request_mem_region(rivafb_fix.smem_start,
rivafb_fix.smem_len, "rivafb")) {
printk(KERN_ERR PFX "cannot reserve FB region\n");
goto err_out_free_base0;
}
info->screen_base = ioremap(rivafb_fix.smem_start,
rivafb_fix.smem_len);
if (!info->screen_base) {
printk(KERN_ERR PFX "cannot ioremap FB base\n");
goto err_out_iounmap_ctrl;
}
#ifdef CONFIG_MTRR
if (!nomtrr) {
default_par->mtrr.vram = mtrr_add(rivafb_fix.smem_start,
rivafb_fix.smem_len,
MTRR_TYPE_WRCOMB, 1);
if (default_par->mtrr.vram < 0) {
printk(KERN_ERR PFX "unable to setup MTRR\n");
} else {
default_par->mtrr.vram_valid = 1;
/* let there be speed */
printk(KERN_INFO PFX "RIVA MTRR set to ON\n");
}
}
#endif /* CONFIG_MTRR */
if (riva_set_fbinfo(info) < 0) {
printk(KERN_ERR PFX "error setting initial video mode\n");
goto err_out_cursor;
}
if (register_framebuffer(info) < 0) {
printk(KERN_ERR PFX
"error registering riva framebuffer\n");
goto err_out_load_state;
}
pci_set_drvdata(pd,info);
printk(KERN_INFO PFX
"PCI nVidia NV%x framebuffer ver %s (%s, %dMB @ 0x%lX)\n",
default_par->riva.Architecture,
RIVAFB_VERSION,
info->fix.id,
info->fix.smem_len / (1024 * 1024),
info->fix.smem_start);
return 0;
err_out_load_state:
err_out_cursor:
/* err_out_iounmap_fb: */
iounmap(info->screen_base);
err_out_iounmap_ctrl:
iounmap(default_par->ctrl_base);
err_out_free_base1:
release_mem_region(info->fix.smem_start, info->fix.smem_len);
err_out_free_base0:
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
err_out_kfree:
kfree(info);
err_out:
return -ENODEV;
}
static void __devexit rivafb_remove_one(struct pci_dev *pd)
{
struct fb_info *info = pci_get_drvdata(pd);
struct riva_par *par = (struct riva_par *) info->par;
if (!info)
return;
unregister_framebuffer(info);
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
mtrr_del(par->mtrr.vram, info->fix.smem_start,
info->fix.smem_len);
#endif /* CONFIG_MTRR */
iounmap(par->ctrl_base);
iounmap(info->screen_base);
release_mem_region(info->fix.mmio_start,
info->fix.mmio_len);
release_mem_region(info->fix.smem_start,
info->fix.smem_len);
kfree(info);
pci_set_drvdata(pd, NULL);
}
/* ------------------------------------------------------------------------- *
*
* initialization
*
* ------------------------------------------------------------------------- */
#ifndef MODULE
int __init rivafb_setup(char *options)
{
char *this_opt;
if (!options || !*options)
return 0;
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt)
continue;
#ifdef CONFIG_MTRR
if (!strncmp(this_opt, "nomtrr", 6)) {
nomtrr = 1;
} else
#endif
mode_option = this_opt;
}
return 0;
}
#endif /* !MODULE */
static struct pci_driver rivafb_driver = {
name: "rivafb",
id_table: rivafb_pci_tbl,
probe: rivafb_init_one,
remove: __devexit_p(rivafb_remove_one),
};
/* ------------------------------------------------------------------------- *
*
* modularization
*
* ------------------------------------------------------------------------- */
int __init rivafb_init(void)
{
pci_register_driver(&rivafb_driver);
return 0;
}
#ifdef MODULE
static void __exit rivafb_exit(void)
{
pci_unregister_driver(&rivafb_driver);
}
module_init(rivafb_init);
module_exit(rivafb_exit);
MODULE_PARM(flatpanel, "i");
MODULE_PARM_DESC(flatpanel, "Enables experimental flat panel support for some chipsets. (0 or 1=enabled) (default=0)");
MODULE_PARM(forceCRTC, "i");
MODULE_PARM_DESC(forceCRTC, "Forces usage of a particular CRTC in case autodetection fails. (0 or 1) (default=autodetect)");
MODULE_PARM(noaccel, "i");
MODULE_PARM_DESC(noaccel, "Disables hardware acceleration (0 or 1=disabled) (default=0)");
#ifdef CONFIG_MTRR
MODULE_PARM(nomtrr, "i");
MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) (default=0)");
#endif
#endif /* MODULE */
MODULE_AUTHOR("Ani Joshi, maintainer");
MODULE_DESCRIPTION("Framebuffer driver for nVidia Riva 128, TNT, TNT2, GeForce Series");
MODULE_LICENSE("GPL");
......@@ -378,6 +378,9 @@ struct sti_struct {
/* PCI data structures (pg. 17ff from sti.pdf) */
struct pci_dev *pd;
u8 rm_entry[16]; /* pci region mapper array == pci config space offset */
/* pointer to the fb_info where this STI device is used */
struct fb_info *info;
};
......
/*
* linux/drivers/video/sti/stifb.c -
* Frame buffer driver for HP workstations with STI (standard text interface)
* video firmware.
* linux/drivers/video/stifb.c -
* Low level Frame buffer driver for HP workstations with
* STI (standard text interface) video firmware.
*
* Copyright (C) 2001-2002 Helge Deller <deller@gmx.de>
* Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
......@@ -40,10 +40,9 @@
/* TODO:
* - remove the static fb_info to support multiple cards
* - remove the completely untested 1bpp mode
* - 1bpp mode is completely untested
* - add support for h/w acceleration
* - add hardware cursor
* -
*/
......@@ -68,21 +67,18 @@
#include <linux/ioport.h>
#include <linux/pci.h>
#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
#include <video/fbcon-cfb32.h>
#include "console/fbcon.h"
#include <asm/grfioctl.h> /* for HP-UX compatibility */
#include "sticore.h"
/* REGION_BASE(fb_info, index) returns the virtual address for region <index> */
#ifdef __LP64__
/* return virtual address */
#define REGION_BASE(fb_info, index) \
#define REGION_BASE(fb_info, index) \
(fb_info->sti->glob_cfg->region_ptrs[index] | 0xffffffff00000000)
#else
/* return virtual address */
#define REGION_BASE(fb_info, index) \
#define REGION_BASE(fb_info, index) \
fb_info->sti->glob_cfg->region_ptrs[index]
#endif
......@@ -936,53 +932,6 @@ stifb_setcolreg(u_int regno, u_int red, u_int green,
return 0;
}
#if 0
static void
stifb_loadcmap(struct stifb_info *fb)
{
u32 color;
int i;
if (!fb->cmap_reload)
return;
START_IMAGE_COLORMAP_ACCESS(fb);
for (i = 0; i < 256; i++) {
if (fb->info.var.bits_per_pixel > 8) {
color = (i << 16) | (i << 8) | i;
} else {
if (fb->info.var.grayscale) {
/* gray = 0.30*R + 0.59*G + 0.11*B */
color = ((fb->palette[i].red * 77) +
(fb->palette[i].green * 151) +
(fb->palette[i].blue * 28)) >> 8;
} else {
color = ((fb->palette[i].red << 16) |
(fb->palette[i].green << 8) |
(fb->palette[i].blue));
}
}
WRITE_IMAGE_COLOR(fb, i, color);
}
if (fb->id == S9000_ID_HCRX) {
NgleLutBltCtl lutBltCtl;
lutBltCtl = setHyperLutBltCtl(fb,
0, /* Offset w/i LUT */
256); /* Load entire LUT */
NGLE_BINC_SET_SRCADDR(fb,
NGLE_LONG_FB_ADDRESS(0, 0x100, 0));
/* 0x100 is same as used in WRITE_IMAGE_COLOR() */
START_COLORMAPLOAD(fb, lutBltCtl.all);
SETUP_FB(fb);
} else {
/* cleanup colormap hardware */
FINISH_IMAGE_COLORMAP_ACCESS(fb);
}
fb->cmap_reload = 0;
}
#endif
static int
stifb_blank(int blank_mode, struct fb_info *info)
{
......@@ -1075,24 +1024,18 @@ stifb_init_display(struct stifb_info *fb)
static struct fb_ops stifb_ops = {
.owner = THIS_MODULE,
.fb_set_var = gen_set_var,
.fb_get_cmap = gen_get_cmap,
.fb_set_cmap = gen_set_cmap,
.fb_setcolreg = stifb_setcolreg,
/* .fb_pan_display = stifb_pan_display, */
.fb_blank = stifb_blank,
/*
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
*/
.fb_imageblit = cfb_imageblit,
.fb_cursor = soft_cursor,
};
/*
* Initialization
*/
/*
* Initialization
*/
int __init
stifb_init_fb(struct sti_struct *sti, int force_bpp)
......@@ -1100,7 +1043,6 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
struct fb_fix_screeninfo *fix;
struct fb_var_screeninfo *var;
struct display *disp;
struct display_switch *dispsw;
struct stifb_info *fb;
struct fb_info *info;
unsigned long sti_rom_address;
......@@ -1120,7 +1062,6 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
fix = &info->fix;
var = &info->var;
disp = &fb->disp;
info->disp = &fb->disp;
fb->sti = sti;
/* store upper 32bits of the graphics id */
......@@ -1234,30 +1175,22 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
case 1:
fix->type = FB_TYPE_PLANES; /* well, sort of */
fix->visual = FB_VISUAL_MONO10;
dispsw = &fbcon_sti;
break;
#ifdef FBCON_HAS_CFB8
case 8:
fix->type = FB_TYPE_PACKED_PIXELS;
fix->visual = FB_VISUAL_PSEUDOCOLOR;
dispsw = &fbcon_cfb8;
var->red.length = var->green.length = var->blue.length = 8;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
fix->type = FB_TYPE_PACKED_PIXELS;
fix->visual = FB_VISUAL_TRUECOLOR;
dispsw = &fbcon_cfb32;
var->red.length = var->green.length = var->blue.length = var->transp.length = 8;
var->blue.offset = 0;
var->green.offset = 8;
var->red.offset = 16;
var->transp.offset = 24;
break;
#endif
default:
dispsw = &fbcon_dummy;
break;
}
......@@ -1265,22 +1198,16 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
var->yres = var->yres_virtual = yres;
var->bits_per_pixel = bpp;
strcpy(info->modename, "stifb");
strcpy(fix->id, "stifb");
info->node = NODEV;
info->fbops = &stifb_ops;
info->screen_base = (void*) REGION_BASE(fb,1);
info->disp = disp;
info->changevar = NULL;
info->switch_con = gen_switch;
info->updatevar = &gen_update_var;
info->flags = FBINFO_FLAG_DEFAULT;
info->currcon = -1;
/* This has to been done !!! */
fb_alloc_cmap(&info->cmap, 256, 0);
stifb_init_display(fb);
gen_set_disp(-1, info);
disp->dispsw = dispsw;
if (!request_mem_region(fix->smem_start, fix->smem_len, "stifb")) {
printk(KERN_ERR "stifb: cannot reserve fb region 0x%04lx-0x%04lx\n",
......@@ -1297,13 +1224,15 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
if (register_framebuffer(&fb->info) < 0)
goto out_err3;
sti->info = info; /* save for unregister_framebuffer() */
printk(KERN_INFO
"fb%d: %s %dx%d-%d frame buffer device, id: %04x, mmio: 0x%04lx\n",
minor(fb->info.node),
fb->info.modename,
disp->var.xres,
disp->var.yres,
disp->var.bits_per_pixel,
fix->id,
var->xres,
var->yres,
var->bits_per_pixel,
fb->id,
fix->mmio_start);
......@@ -1315,6 +1244,7 @@ stifb_init_fb(struct sti_struct *sti, int force_bpp)
out_err2:
release_mem_region(fix->smem_start, fix->smem_len);
out_err1:
fb_dealloc_cmap(&info->cmap);
kfree(fb);
return -ENXIO;
}
......@@ -1325,7 +1255,6 @@ stifb_init(void)
struct sti_struct *sti;
int i;
if (sti_init_roms() == NULL)
return -ENXIO; /* no STI cards available */
......@@ -1346,7 +1275,17 @@ stifb_init(void)
static void __exit
stifb_cleanup(void)
{
// unregister_framebuffer();
struct sti_struct *sti;
int i;
for (i = 0; i < MAX_STI_ROMS; i++) {
sti = sti_get_rom(i);
if (!sti)
break;
if (sti->info)
unregister_framebuffer(sti->info);
sti->info = NULL;
}
}
int __init
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment