Commit b58b80ea authored by James Simmons's avatar James Simmons

Updates to STI framebuffer and STI console. Cleanup of include/video and a few minor fixes.

parent 76e97c93
...@@ -63,7 +63,7 @@ obj-$(CONFIG_FB_TCX) += tcxfb.o sbusfb.o ...@@ -63,7 +63,7 @@ obj-$(CONFIG_FB_TCX) += tcxfb.o sbusfb.o
obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o obj-$(CONFIG_FB_CGFOURTEEN) += cgfourteenfb.o sbusfb.o
obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o obj-$(CONFIG_FB_P9100) += p9100fb.o sbusfb.o
obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o obj-$(CONFIG_FB_LEO) += leofb.o sbusfb.o
obj-$(CONFIG_FB_STI) += stifb.o sticore.o obj-$(CONFIG_FB_STI) += stifb.o console/sticore.o
obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.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_PMAGB_B) += pmagb-b-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_MAXINE) += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_MAXINE) += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
......
...@@ -17,7 +17,7 @@ if [ "$CONFIG_VT" != "n" ]; then ...@@ -17,7 +17,7 @@ if [ "$CONFIG_VT" != "n" ]; then
# fi # fi
# fi # fi
fi fi
tristate 'MDA text console (dual-headed) ' CONFIG_MDA_CONSOLE tristate 'MDA text console ' CONFIG_MDA_CONSOLE
if [ "$CONFIG_SGI_IP22" = "y" ]; then if [ "$CONFIG_SGI_IP22" = "y" ]; then
tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE
if [ "$CONFIG_SGI_NEWPORT_CONSOLE" != "y" ]; then if [ "$CONFIG_SGI_NEWPORT_CONSOLE" != "y" ]; then
......
...@@ -14,7 +14,7 @@ export-objs := fbcon.o fbcon-accel.o fbcon-afb.o fbcon-ilbm.o \ ...@@ -14,7 +14,7 @@ export-objs := fbcon.o fbcon-accel.o fbcon-afb.o fbcon-ilbm.o \
obj-$(CONFIG_DUMMY_CONSOLE) += dummycon.o obj-$(CONFIG_DUMMY_CONSOLE) += dummycon.o
obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o
obj-$(CONFIG_PROM_CONSOLE) += promcon.o promcon_tbl.o obj-$(CONFIG_PROM_CONSOLE) += promcon.o promcon_tbl.o
obj-$(CONFIG_STI_CONSOLE) += sticon.o sticon-bmode.o ../sticore.o obj-$(CONFIG_STI_CONSOLE) += sticon.o sticore.o
obj-$(CONFIG_VGA_CONSOLE) += vgacon.o obj-$(CONFIG_VGA_CONSOLE) += vgacon.o
obj-$(CONFIG_MDA_CONSOLE) += mdacon.o obj-$(CONFIG_MDA_CONSOLE) += mdacon.o
......
...@@ -17,42 +17,18 @@ ...@@ -17,42 +17,18 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <asm/gsc.h> /* for gsc_read/write */
#include <asm/types.h> #include <asm/types.h>
#include "fbcon.h" #include <video/fbcon.h>
#include "fbcon-mfb.h" #include <video/fbcon-mfb.h>
#include "sti.h" #include "../sticore.h"
/* Translate an address as it would be found in a 2048x2048x1 bit frame
* buffer into a logical address Artist actually expects. Addresses fed
* into Artist look like this:
* fixed Y X
* FFFF FFFF LLLL LLLL LLLC CCCC CCCC CC00
*
* our "RAM" addresses look like this:
*
* FFFF FFFF 0000 0LLL LLLL LLLL CCCC CCCC [CCC]
*
* */
static inline u32 static inline u32
ram2log(void * addr) ram2log(void * addr)
{ {
u32 a = (unsigned long) addr; return (unsigned long) addr;
u32 r;
#if 0
r = a & 0xff000000; /* fixed part */
r += ((a & 0x000000ff) << 5);
r += ((a & 0x00ffff00) << 3);
#else
r = a & 0xff000000; /* fixed part */
r += ((a & 0x000000ff) << 5);
r += ((a & 0x0007ff00) << 5);
#endif
return r;
} }
/* All those functions need better names. */ /* All those functions need better names. */
...@@ -74,30 +50,6 @@ memcpy_fromhp_tohp(void *dest, void *src, int count) ...@@ -74,30 +50,6 @@ memcpy_fromhp_tohp(void *dest, void *src, int count)
} }
} }
static void
memcpy_tohp(void *dest, void *src, int count)
{
unsigned long d = (unsigned long) dest;
u32 *s = (u32 *)src;
count += 3;
count &= ~3; /* XXX */
d = ram2log(dest);
while(count) {
count--;
gsc_writel(*s++, d);
d += 32*4;
}
}
static void
memcopy_fromhp(void *dest, void *src, int count)
{
/* FIXME */
printk("uhm ...\n");
}
static void static void
memset_tohp(void *dest, u32 word, int count) memset_tohp(void *dest, u32 word, int count)
...@@ -139,10 +91,11 @@ writeb_hp(u8 b, void *dst) ...@@ -139,10 +91,11 @@ writeb_hp(u8 b, void *dst)
static void static void
fbcon_sti_setup(struct display *p) fbcon_sti_setup(struct display *p)
{ {
if (p->line_length) /* in kernel 2.5 the value of sadly line_length disapeared */
p->next_line = p->line_length; if (p->var.xres_virtual /*line_length*/)
else
p->next_line = p->var.xres_virtual>>3; p->next_line = p->var.xres_virtual>>3;
else
p->next_line = 2048; /* default STI value */
p->next_plane = 0; p->next_plane = 0;
} }
...@@ -152,7 +105,7 @@ fbcon_sti_bmove(struct display *p, int sy, int sx, ...@@ -152,7 +105,7 @@ fbcon_sti_bmove(struct display *p, int sy, int sx,
int height, int width) int height, int width)
{ {
#if 0 /* Unfortunately, still broken */ #if 0 /* Unfortunately, still broken */
sti_bmove(&default_sti /* FIXME */, sy, sx, dy, dx, height, width); sti_bmove(default_sti /* FIXME */, sy, sx, dy, dx, height, width);
#else #else
u8 *src, *dest; u8 *src, *dest;
u_int rows; u_int rows;
...@@ -285,7 +238,6 @@ static void fbcon_sti_revc(struct display *p, ...@@ -285,7 +238,6 @@ static void fbcon_sti_revc(struct display *p,
u8 *dest, d; u8 *dest, d;
u_int rows; u_int rows;
dest = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx; dest = p->fb_info->screen_base+yy*fontheight(p)*p->next_line+xx;
for (rows = fontheight(p); rows--; dest += p->next_line) { for (rows = fontheight(p); rows--; dest += p->next_line) {
d = readb_hp(dest); d = readb_hp(dest);
......
...@@ -99,11 +99,11 @@ ...@@ -99,11 +99,11 @@
#define INCLUDE_LINUX_LOGO_DATA #define INCLUDE_LINUX_LOGO_DATA
#include <asm/linux_logo.h> #include <asm/linux_logo.h>
#include <video/fbcon.h> #include "fbcon.h"
#ifdef CONFIG_FBCON_ACCEL #ifdef CONFIG_FBCON_ACCEL
#include "fbcon-accel.h" #include "fbcon-accel.h"
#endif #endif
#include <video/font.h> #include "font.h"
#ifdef FBCONDEBUG #ifdef FBCONDEBUG
# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) # define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
/* */ /* */
/**********************************************/ /**********************************************/
#include <video/font.h> #include "font.h"
#define FONTDATAMAX (11*256) #define FONTDATAMAX (11*256)
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
/* */ /* */
/**********************************************/ /**********************************************/
#include <video/font.h> #include "font.h"
#define FONTDATAMAX 4096 #define FONTDATAMAX 4096
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
/* */ /* */
/**********************************************/ /**********************************************/
#include <video/font.h> #include "font.h"
#define FONTDATAMAX 2048 #define FONTDATAMAX 2048
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <video/font.h> #include "font.h"
static unsigned char acorndata_8x8[] = { static unsigned char acorndata_8x8[] = {
/* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */ /* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */
......
...@@ -39,7 +39,7 @@ __END__; ...@@ -39,7 +39,7 @@ __END__;
MSBit to LSBit = left to right. MSBit to LSBit = left to right.
*/ */
#include <video/font.h> #include "font.h"
#define FONTDATAMAX 1536 #define FONTDATAMAX 1536
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
/* */ /* */
/**********************************************/ /**********************************************/
#include <video/font.h> #include "font.h"
#define FONTDATAMAX 2048 #define FONTDATAMAX 2048
......
#include <video/font.h> #include "font.h"
#define FONTDATAMAX 11264 #define FONTDATAMAX 11264
......
#include <video/font.h> #include "font.h"
#define FONTDATAMAX 4096 #define FONTDATAMAX 4096
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#if defined(__mc68000__) || defined(CONFIG_APUS) #if defined(__mc68000__) || defined(CONFIG_APUS)
#include <asm/setup.h> #include <asm/setup.h>
#endif #endif
#include <video/font.h> #include "font.h"
#define NO_FONTS #define NO_FONTS
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#define INCLUDE_LINUX_LOGO_DATA #define INCLUDE_LINUX_LOGO_DATA
#include <asm/linux_logo.h> #include <asm/linux_logo.h>
#include <video/font.h> #include "font.h"
#define LOGO_W 80 #define LOGO_W 80
#define LOGO_H 80 #define LOGO_H 80
......
#define STI_REGION_MAX 8
#define STI_DEV_NAME_LENGTH 32
typedef struct {
u8 res[3];
u8 data;
} __attribute__((packed)) sti_u8;
typedef struct {
sti_u8 data[2];
} __attribute__((packed)) sti_u16;
typedef struct {
sti_u8 data[4];
} __attribute__((packed)) sti_u32;
#define STI_U8( u8) ((u8).data)
#define STI_U16(u16) ((STI_U8((u16).data[0])<<8) | STI_U8((u16).data[1]))
#define STI_U32(u32) ((STI_U8((u32).data[0])<<24) | \
(STI_U8((u32).data[1])<<16) | \
(STI_U8((u32).data[2])<< 8) | \
(STI_U8((u32).data[3])<< 0))
struct sti_rom_region {
sti_u32 region;
};
struct sti_rom_font {
sti_u16 first_char;
sti_u16 last_char;
sti_u8 width;
sti_u8 height;
sti_u8 font_type;
sti_u8 bytes_per_char;
sti_u32 next_font;
sti_u8 underline_height;
sti_u8 underline_pos;
sti_u8 res008[2];
};
struct sti_rom {
sti_u8 type;
sti_u8 num_mons;
sti_u8 revno[2];
sti_u8 graphics_id[8]; /* 0x010 */
sti_u32 font_start; /* 0x030 */
sti_u32 statesize;
sti_u32 last_addr;
sti_u32 region_list;
sti_u16 reentsize; /* 0x070 */
sti_u16 maxtime;
sti_u32 mon_tbl_addr;
sti_u32 user_data_addr;
sti_u32 sti_mem_req;
sti_u32 user_data_size; /* 0x0b0 */
sti_u16 power; /* 0x0c0 */
sti_u8 bus_support;
sti_u8 ext_bus_support;
sti_u8 alt_code_type; /* 0x0d0 */
sti_u8 ext_dd_struct[3];
sti_u32 cfb_addr; /* 0x0e0 */
sti_u8 res0f0[4];
sti_u32 init_graph; /* 0x0e0 */
sti_u32 state_mgmt;
sti_u32 font_unpmv;
sti_u32 block_move;
sti_u32 self_test;
sti_u32 excep_hdlr;
sti_u32 inq_conf;
sti_u32 set_cm_entry;
sti_u32 dma_ctrl;
sti_u32 flow_ctrl;
sti_u32 user_timing;
sti_u32 process_mgr;
sti_u32 sti_util;
sti_u32 end_addr;
sti_u32 res0b8;
sti_u32 res0bc;
sti_u32 init_graph_m68k; /* 0x0e0 */
sti_u32 state_mgmt_m68k;
sti_u32 font_unpmv_m68k;
sti_u32 block_move_m68k;
sti_u32 self_test_m68k;
sti_u32 excep_hdlr_m68k;
sti_u32 inq_conf_m68k;
sti_u32 set_cm_entry_m68k;
sti_u32 dma_ctrl_m68k;
sti_u32 flow_ctrl_m68k;
sti_u32 user_timing_m68k;
sti_u32 process_mgr_m68k;
sti_u32 sti_util_m68k;
sti_u32 end_addr_m68k;
sti_u32 res0b8_m68k;
sti_u32 res0bc_m68k;
sti_u8 res040[7 * 4];
};
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); \
})
...@@ -86,6 +86,7 @@ int cfb_cursor(struct fb_info *info, struct fbcursor *cursor) ...@@ -86,6 +86,7 @@ int cfb_cursor(struct fb_info *info, struct fbcursor *cursor)
if (info->fbops->fb_imageblit) if (info->fbops->fb_imageblit)
info->fbops->fb_imageblit(info, &image); info->fbops->fb_imageblit(info, &image);
} }
return 0;
} }
int fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) int fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
#include <linux/fb.h> #include <linux/fb.h>
#ifdef CONFIG_VT #ifdef CONFIG_VT
#include <linux/console.h> #include <linux/console.h>
#include <video/fbcon.h> #include "console/fbcon.h"
#endif #endif
/* /*
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/string.h> #include <linux/string.h>
#include <video/macmodes.h> #include "macmodes.h"
/* /*
* MacOS video mode definitions * MacOS video mode definitions
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
#include <asm/bootx.h> #include <asm/bootx.h>
#endif #endif
#include <video/macmodes.h> #include "macmodes.h"
/* Supported palette hacks */ /* Supported palette hacks */
enum { enum {
......
#ifndef STICORE_H
#define STICORE_H
/* generic STI structures & functions */
#if 0
#define DPRINTK(x) printk x
#else
#define DPRINTK(x)
#endif
#define MAX_STI_ROMS 4 /* max no. of ROMs which this driver handles */
#define STI_REGION_MAX 8 /* hardcoded STI constants */
#define STI_DEV_NAME_LENGTH 32
#define STI_MONITOR_MAX 256
#define STI_FONT_HPROMAN8 1
#define STI_FONT_KANA8 2
/* 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
*/
#define STI_WAIT 1
#include <asm/io.h> /* for USE_HPPA_IOREMAP */
#if USE_HPPA_IOREMAP
#define STI_PTR(p) (p)
#define PTR_STI(p) (p)
static int inline STI_CALL( unsigned long func,
void *flags, void *inptr, void *outptr, void *glob_cfg )
{
int (*f)(void *,void *,void *,void *);
f = (void*)func;
return f(flags, inptr, outptr, glob_cfg);
}
#else /* !USE_HPPA_IOREMAP */
#define STI_PTR(p) ( virt_to_phys(p) )
#define PTR_STI(p) ( phys_to_virt((long)p) )
#define STI_CALL(func, flags, inptr, outptr, glob_cfg) \
({ \
pdc_sti_call( func, (unsigned long)STI_PTR(flags), \
(unsigned long)STI_PTR(inptr), \
(unsigned long)STI_PTR(outptr), \
(unsigned long)STI_PTR(glob_cfg)); \
})
#endif /* USE_HPPA_IOREMAP */
#define sti_onscreen_x(sti) (sti->glob_cfg->onscreen_x)
#define sti_onscreen_y(sti) (sti->glob_cfg->onscreen_y)
/* sti_font_xy() use the native font ROM ! */
#define sti_font_x(sti) (PTR_STI(sti->font)->width)
#define sti_font_y(sti) (PTR_STI(sti->font)->height)
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
#endif
extern struct sti_struct *sti_init_roms(void);
/* 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;
extern struct display_switch fbcon_sti; /* fbcon-sti.c */
int 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, int c);
void sti_bmove(struct sti_struct *sti, int src_y, int src_x,
int dst_y, int dst_x, int height, int width);
/* STI function configuration structs */
typedef union region {
struct {
u32 offset : 14; /* offset in 4kbyte page */
u32 sys_only : 1; /* don't map to user space */
u32 cache : 1; /* map to data cache */
u32 btlb : 1; /* map to block tlb */
u32 last : 1; /* last region in list */
u32 length : 14; /* length in 4kbyte page */
} region_desc;
u32 region; /* complete region value */
} region_t;
#define REGION_OFFSET_TO_PHYS( rt, hpa ) \
(((rt).region_desc.offset << 12) + (hpa))
struct sti_glob_cfg_ext {
u8 curr_mon; /* current monitor configured */
u8 friendly_boot; /* in friendly boot mode */
s16 power; /* power calculation (in Watts) */
s32 freq_ref; /* frequency refrence */
u32 sti_mem_addr; /* pointer to global sti memory (size=sti_mem_request) */
u32 future_ptr; /* pointer to future data */
};
struct sti_glob_cfg {
s32 text_planes; /* number of planes used for text */
s16 onscreen_x; /* screen width in pixels */
s16 onscreen_y; /* screen height in pixels */
s16 offscreen_x; /* offset width in pixels */
s16 offscreen_y; /* offset height in pixels */
s16 total_x; /* frame buffer width in pixels */
s16 total_y; /* frame buffer height in pixels */
u32 region_ptrs[STI_REGION_MAX]; /* region pointers */
s32 reent_lvl; /* storage for reentry level value */
u32 save_addr; /* where to save or restore reentrant state */
u32 ext_ptr; /* pointer to extended glob_cfg data structure */
};
/* STI init function structs */
struct sti_init_flags {
u32 wait : 1; /* should routine idle wait or not */
u32 reset : 1; /* hard reset the device? */
u32 text : 1; /* turn on text display planes? */
u32 nontext : 1; /* turn on non-text display planes? */
u32 clear : 1; /* clear text display planes? */
u32 cmap_blk : 1; /* non-text planes cmap black? */
u32 enable_be_timer : 1; /* enable bus error timer */
u32 enable_be_int : 1; /* enable bus error timer interrupt */
u32 no_chg_tx : 1; /* don't change text settings */
u32 no_chg_ntx : 1; /* don't change non-text settings */
u32 no_chg_bet : 1; /* don't change berr timer settings */
u32 no_chg_bei : 1; /* don't change berr int settings */
u32 init_cmap_tx : 1; /* initialize cmap for text planes */
u32 cmt_chg : 1; /* change current monitor type */
u32 retain_ie : 1; /* don't allow reset to clear int enables */
u32 caller_bootrom : 1; /* set only by bootrom for each call */
u32 caller_kernel : 1; /* set only by kernel for each call */
u32 caller_other : 1; /* set only by non-[BR/K] caller */
u32 pad : 14; /* pad to word boundary */
u32 future_ptr; /* pointer to future data */
};
struct sti_init_inptr_ext {
u8 config_mon_type; /* configure to monitor type */
u8 pad[1]; /* pad to word boundary */
u16 inflight_data; /* inflight data possible on PCI */
u32 future_ptr; /* pointer to future data */
};
struct sti_init_inptr {
s32 text_planes; /* number of planes to use for text */
u32 ext_ptr; /* pointer to extended init_graph inptr data structure*/
};
struct sti_init_outptr {
s32 errno; /* error number on failure */
s32 text_planes; /* number of planes used for text */
u32 future_ptr; /* pointer to future data */
};
/* STI configuration function structs */
struct sti_conf_flags {
u32 wait : 1; /* should routine idle wait or not */
u32 pad : 31; /* pad to word boundary */
u32 future_ptr; /* pointer to future data */
};
struct sti_conf_inptr {
u32 future_ptr; /* pointer to future data */
};
struct sti_conf_outptr_ext {
u32 crt_config[3]; /* hardware specific X11/OGL information */
u32 crt_hdw[3];
u32 future_ptr;
};
struct sti_conf_outptr {
s32 errno; /* error number on failure */
s16 onscreen_x; /* screen width in pixels */
s16 onscreen_y; /* screen height in pixels */
s16 offscreen_x; /* offscreen width in pixels */
s16 offscreen_y; /* offscreen height in pixels */
s16 total_x; /* frame buffer width in pixels */
s16 total_y; /* frame buffer height in pixels */
s32 bits_per_pixel; /* bits/pixel device has configured */
s32 bits_used; /* bits which can be accessed */
s32 planes; /* number of fb planes in system */
u8 dev_name[STI_DEV_NAME_LENGTH]; /* null terminated product name */
u32 attributes; /* flags denoting attributes */
u32 ext_ptr; /* pointer to future data */
};
struct sti_rom {
u8 type[4];
u8 res004;
u8 num_mons;
u8 revno[2];
u32 graphics_id[2];
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_addr;
u32 state_mgmt_addr;
u32 font_unp_addr;
u32 block_move_addr;
u32 self_test_addr;
u32 excep_hdlr_addr;
u32 inq_conf_addr;
u32 set_cm_entry_addr;
u32 image_unpack_addr;
u32 pa_risx_addrs[7];
};
struct sti_rom_font {
u16 first_char;
u16 last_char;
u8 width;
u8 height;
u8 font_type; /* language type */
u8 bytes_per_char;
u32 next_font;
u8 underline_height;
u8 underline_pos;
u8 res008[2];
};
/* sticore internal font handling */
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;
};
/* STI font printing function structs */
struct sti_font_inptr {
u32 font_start_addr; /* address of font start */
s16 index; /* index into font table of character */
u8 fg_color; /* foreground color of character */
u8 bg_color; /* background color of character */
s16 dest_x; /* X location of character upper left */
s16 dest_y; /* Y location of character upper left */
u32 future_ptr; /* pointer to future data */
};
struct sti_font_flags {
u32 wait : 1; /* should routine idle wait or not */
u32 non_text : 1; /* font unpack/move in non_text planes =1, text =0 */
u32 pad : 30; /* pad to word boundary */
u32 future_ptr; /* pointer to future data */
};
struct sti_font_outptr {
s32 errno; /* error number on failure */
u32 future_ptr; /* pointer to future data */
};
/* STI blockmove structs */
struct sti_blkmv_flags {
u32 wait : 1; /* should routine idle wait or not */
u32 color : 1; /* change color during move? */
u32 clear : 1; /* clear during move? */
u32 non_text : 1; /* block move in non_text planes =1, text =0 */
u32 pad : 28; /* pad to word boundary */
u32 future_ptr; /* pointer to future data */
};
struct sti_blkmv_inptr {
u8 fg_color; /* foreground color after move */
u8 bg_color; /* background color after move */
s16 src_x; /* source upper left pixel x location */
s16 src_y; /* source upper left pixel y location */
s16 dest_x; /* dest upper left pixel x location */
s16 dest_y; /* dest upper left pixel y location */
s16 width; /* block width in pixels */
s16 height; /* block height in pixels */
u32 future_ptr; /* pointer to future data */
};
struct sti_blkmv_outptr {
s32 errno; /* error number on failure */
u32 future_ptr; /* pointer to future data */
};
/* internal generic STI struct */
struct sti_struct {
spinlock_t lock;
/* the following fields needs to be filled in by the word/byte routines */
int font_width;
int font_height;
/* char **mon_strings; */
int sti_mem_request;
u32 graphics_id[2];
struct sti_cooked_rom *rom;
unsigned long font_unpmv;
unsigned long block_move;
unsigned long init_graph;
unsigned long inq_conf;
/* all following fields are initialized by the generic routines */
int text_planes;
region_t regions[STI_REGION_MAX];
unsigned long regions_phys[STI_REGION_MAX];
struct sti_glob_cfg *glob_cfg;
struct sti_cooked_font *font; /* ptr to selected font (cooked) */
struct sti_conf_outptr outptr; /* configuration */
struct sti_conf_outptr_ext outptr_ext;
/* PCI data structures (pg. 17ff from sti.pdf) */
struct pci_dev *pd;
u8 rm_entry[16]; /* pci region mapper array == pci config space offset */
};
/* helper functions */
struct sti_struct *sti_init_roms(void);
struct sti_struct *sti_get_rom(int);
void sti_rom_copy(unsigned long base, unsigned long count, void *dest);
struct sti_cooked_font *sti_select_font(struct sti_cooked_rom *rom,
int (*search_font_fnc) (struct sti_cooked_rom *,int,int) );
int sti_read_rom(int wordmode, struct sti_struct *sti,
unsigned long address);
/* FIXME: Do we have another solution for this ? */
#include <linux/kernel.h>
#include <linux/slab.h>
#include <asm/cacheflush.h>
static inline void sti_flush(unsigned long from, unsigned long len)
{
flush_data_cache();
flush_kernel_dcache_range(from, len);
flush_icache_range(from, from+len);
}
#endif /* STICORE_H */
/* /*
* linux/drivers/video/stifb.c - Generic frame buffer driver for HP * linux/drivers/video/sti/stifb.c -
* workstations with STI (standard text interface) video firmware. * Frame buffer driver for HP workstations with STI (standard text interface)
* video firmware.
* *
* Based on: * Copyright (C) 2001-2002 Helge Deller <deller@gmx.de>
* linux/drivers/video/artistfb.c -- Artist frame buffer driver * Portions Copyright (C) 2001 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
* *
* Based on:
* - linux/drivers/video/artistfb.c -- Artist frame buffer driver
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
* * - based on skeletonfb, which was
* based on skeletonfb, which was
* Created 28 Dec 1997 by Geert Uytterhoeven * Created 28 Dec 1997 by Geert Uytterhoeven
* - HP Xhp cfb-based X11 window driver for XFree86
* (c)Copyright 1992 Hewlett-Packard Co.
*
*
* The following graphics display devices (NGLE family) are supported by this driver:
*
* HPA4070A known as "HCRX", a 1280x1024 color device with 8 planes
* HPA4071A known as "HCRX24", a 1280x1024 color device with 24 planes,
* optionally available with a hardware accelerator as HPA4071A_Z
* HPA1659A known as "CRX", a 1280x1024 color device with 8 planes
* HPA1439A known as "CRX24", a 1280x1024 color device with 24 planes,
* optionally available with a hardware accelerator.
* HPA1924A known as "GRX", a 1280x1024 grayscale device with 8 planes
* HPA2269A known as "Dual CRX", a 1280x1024 color device with 8 planes,
* implements support for two displays on a single graphics card.
* HP710C internal graphics support optionally available on the HP9000s710 SPU,
* supports 1280x1024 color displays with 8 planes.
* HP710G same as HP710C, 1280x1024 grayscale only
* HP710L same as HP710C, 1024x768 color only
* HP712 internal graphics support on HP9000s712 SPU, supports 640x480,
* 1024x768 or 1280x1024 color displays on 8 planes (Artist)
* *
* This file is subject to the terms and conditions of the GNU General Public * 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 * License. See the file COPYING in the main directory of this archive
* for more details. */ * for more details.
*/
/* /* TODO:
* Notes: * - remove the static fb_info to support multiple cards
* * - remove the completely untested 1bpp mode
* This driver assumes that the video has been set up in 1bpp mode by * - add support for h/w acceleration
* the firmware. Since HP video tends to be planar rather than * - add hardware cursor
* packed-pixel this will probably work anyway even if it isn't. * -
*/ */
/* on supported graphic devices you may:
* #define FALLBACK_TO_1BPP to fall back to 1 bpp, or
* #undef FALLBACK_TO_1BPP to reject support for unsupported cards */
#undef FALLBACK_TO_1BPP
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -32,179 +64,1322 @@ ...@@ -32,179 +64,1322 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/selection.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <video/fbcon.h> #include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
#include <video/fbcon-cfb32.h>
#include <asm/grfioctl.h> /* for HP-UX compatibility */
#include "sticore.h"
#ifdef __LP64__
/* return virtual address */
#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) \
fb_info->sti->glob_cfg->region_ptrs[index]
#endif
#include "sti.h" #define NGLEDEVDEPROM_CRT_REGION 1
static struct fb_ops stifb_ops; typedef struct {
__s32 video_config_reg;
__s32 misc_video_start;
__s32 horiz_timing_fmt;
__s32 serr_timing_fmt;
__s32 vert_timing_fmt;
__s32 horiz_state;
__s32 vert_state;
__s32 vtg_state_elements;
__s32 pipeline_delay;
__s32 misc_video_end;
} video_setup_t;
typedef struct {
__s16 sizeof_ngle_data;
__s16 x_size_visible; /* visible screen dim in pixels */
__s16 y_size_visible;
__s16 pad2[15];
__s16 cursor_pipeline_delay;
__s16 video_interleaves;
__s32 pad3[11];
} ngle_rom_t;
struct stifb_info { struct stifb_info {
struct fb_info_gen gen; struct fb_info info;
unsigned int id;
ngle_rom_t ngle_rom;
struct sti_struct *sti; struct sti_struct *sti;
int deviceSpecificConfig;
struct display disp;
}; };
struct stifb_par { static int stifb_force_bpp[MAX_STI_ROMS] = {0, };
};
static struct stifb_info fb_info; /* ------------------- chipset specific functions -------------------------- */
static struct display disp;
int stifb_init(void); /* offsets to graphic-chip internal registers */
int stifb_setup(char*);
extern struct display_switch fbcon_sti; #define REG_1 0x000118
#define REG_2 0x000480
#define REG_3 0x0004a0
#define REG_4 0x000600
#define REG_6 0x000800
#define REG_8 0x000820
#define REG_9 0x000a04
#define REG_10 0x018000
#define REG_11 0x018004
#define REG_12 0x01800c
#define REG_13 0x018018
#define REG_14 0x01801c
#define REG_15 0x200000
#define REG_15b0 0x200000
#define REG_16b1 0x200005
#define REG_16b3 0x200007
#define REG_21 0x200218
#define REG_22 0x0005a0
#define REG_23 0x0005c0
#define REG_26 0x200118
#define REG_27 0x200308
#define REG_32 0x21003c
#define REG_33 0x210040
#define REG_34 0x200008
#define REG_35 0x018010
#define REG_38 0x210020
#define REG_39 0x210120
#define REG_40 0x210130
#define REG_42 0x210028
#define REG_43 0x21002c
#define REG_44 0x210030
#define REG_45 0x210034
/* ------------------- chipset specific functions -------------------------- */ #define READ_BYTE(fb,reg) __raw_readb((fb)->info.fix.mmio_start + (reg))
#define READ_WORD(fb,reg) __raw_readl((fb)->info.fix.mmio_start + (reg))
#define WRITE_BYTE(value,fb,reg) __raw_writeb((value),(fb)->info.fix.mmio_start + (reg))
#define WRITE_WORD(value,fb,reg) __raw_writel((value),(fb)->info.fix.mmio_start + (reg))
static int #define ENABLE 1 /* for enabling/disabling screen */
sti_encode_fix(struct fb_fix_screeninfo *fix, #define DISABLE 0
const void *par, struct fb_info_gen *info)
#define NGLE_LOCK(fb_info) do { } while (0)
#define NGLE_UNLOCK(fb_info) do { } while (0)
static void
SETUP_HW(struct stifb_info *fb)
{ {
/* XXX: what about smem_len? */ char stat;
fix->smem_start = PTR_STI(fb_info.sti->glob_cfg)->region_ptrs[1];
fix->type = FB_TYPE_PLANES; /* well, sort of */
return 0; do {
stat = READ_BYTE(fb, REG_15b0);
if (!stat)
stat = READ_BYTE(fb, REG_15b0);
} while (stat);
} }
static int
sti_decode_var(const struct fb_var_screeninfo *var, static void
void *par, struct fb_info_gen *info) SETUP_FB(struct stifb_info *fb)
{ {
return 0; unsigned int reg10_value = 0;
SETUP_HW(fb);
switch (fb->id)
{
case CRT_ID_VISUALIZE_EG:
case S9000_ID_ARTIST:
case S9000_ID_A1659A:
reg10_value = 0x13601000;
break;
case S9000_ID_A1439A:
if (fb->info.var.bits_per_pixel == 32)
reg10_value = 0xBBA0A000;
else
reg10_value = 0x13601000;
break;
case S9000_ID_HCRX:
if (fb->info.var.bits_per_pixel == 32)
reg10_value = 0xBBA0A000;
else
reg10_value = 0x13602000;
break;
case S9000_ID_TIMBER:
case CRX24_OVERLAY_PLANES:
reg10_value = 0x13602000;
break;
}
if (reg10_value)
WRITE_WORD(reg10_value, fb, REG_10);
WRITE_WORD(0x83000300, fb, REG_14);
SETUP_HW(fb);
WRITE_BYTE(1, fb, REG_16b1);
} }
static int static void
sti_encode_var(struct fb_var_screeninfo *var, START_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
const void *par, struct fb_info_gen *info)
{ {
var->xres = PTR_STI(fb_info.sti->glob_cfg)->onscreen_x; SETUP_HW(fb);
var->yres = PTR_STI(fb_info.sti->glob_cfg)->onscreen_y; WRITE_WORD(0xBBE0F000, fb, REG_10);
var->xres_virtual = PTR_STI(fb_info.sti->glob_cfg)->total_x; WRITE_WORD(0x03000300, fb, REG_14);
var->yres_virtual = PTR_STI(fb_info.sti->glob_cfg)->total_y; WRITE_WORD(~0, fb, REG_13);
var->xoffset = var->yoffset = 0; }
var->bits_per_pixel = 1; static void
var->grayscale = 0; WRITE_IMAGE_COLOR(struct stifb_info *fb, int index, int color)
{
SETUP_HW(fb);
WRITE_WORD(((0x100+index)<<2), fb, REG_3);
WRITE_WORD(color, fb, REG_4);
}
return 0; static void
FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
{
WRITE_WORD(0x400, fb, REG_2);
if (fb->info.var.bits_per_pixel == 32) {
WRITE_WORD(0x83000100, fb, REG_1);
} else {
if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
WRITE_WORD(0x80000100, fb, REG_26);
else
WRITE_WORD(0x80000100, fb, REG_1);
}
SETUP_FB(fb);
} }
static void static void
sti_get_par(void *par, struct fb_info_gen *info) SETUP_RAMDAC(struct stifb_info *fb)
{ {
SETUP_HW(fb);
WRITE_WORD(0x04000000, fb, 0x1020);
WRITE_WORD(0xff000000, fb, 0x1028);
} }
static void static void
sti_set_par(const void *par, struct fb_info_gen *info) CRX24_SETUP_RAMDAC(struct stifb_info *fb)
{ {
SETUP_HW(fb);
WRITE_WORD(0x04000000, fb, 0x1000);
WRITE_WORD(0x02000000, fb, 0x1004);
WRITE_WORD(0xff000000, fb, 0x1008);
WRITE_WORD(0x05000000, fb, 0x1000);
WRITE_WORD(0x02000000, fb, 0x1004);
WRITE_WORD(0x03000000, fb, 0x1008);
} }
#if 0
static void
HCRX_SETUP_RAMDAC(struct stifb_info *fb)
{
WRITE_WORD(0xffffffff, fb, REG_32);
}
#endif
static void
CRX24_SET_OVLY_MASK(struct stifb_info *fb)
{
SETUP_HW(fb);
WRITE_WORD(0x13a02000, fb, REG_11);
WRITE_WORD(0x03000300, fb, REG_14);
WRITE_WORD(0x000017f0, fb, REG_3);
WRITE_WORD(0xffffffff, fb, REG_13);
WRITE_WORD(0xffffffff, fb, REG_22);
WRITE_WORD(0x00000000, fb, REG_23);
}
static void
ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
{
unsigned int value = enable ? 0x43000000 : 0x03000000;
SETUP_HW(fb);
WRITE_WORD(0x06000000, fb, 0x1030);
WRITE_WORD(value, fb, 0x1038);
}
static void
CRX24_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
{
unsigned int value = enable ? 0x10000000 : 0x30000000;
SETUP_HW(fb);
WRITE_WORD(0x01000000, fb, 0x1000);
WRITE_WORD(0x02000000, fb, 0x1004);
WRITE_WORD(value, fb, 0x1008);
}
static void
ARTIST_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
{
u32 DregsMiscVideo = REG_21;
u32 DregsMiscCtl = REG_27;
SETUP_HW(fb);
if (enable) {
WRITE_WORD(READ_WORD(fb, DregsMiscVideo) | 0x0A000000, fb, DregsMiscVideo);
WRITE_WORD(READ_WORD(fb, DregsMiscCtl) | 0x00800000, fb, DregsMiscCtl);
} else {
WRITE_WORD(READ_WORD(fb, DregsMiscVideo) & ~0x0A000000, fb, DregsMiscVideo);
WRITE_WORD(READ_WORD(fb, DregsMiscCtl) & ~0x00800000, fb, DregsMiscCtl);
}
}
#define GET_ROMTABLE_INDEX(fb) \
(READ_BYTE(fb, REG_16b3) - 1)
#define HYPER_CONFIG_PLANES_24 0x00000100
#define IS_24_DEVICE(fb) \
(fb->deviceSpecificConfig & HYPER_CONFIG_PLANES_24)
#define IS_888_DEVICE(fb) \
(!(IS_24_DEVICE(fb)))
#define GET_FIFO_SLOTS(fb, cnt, numslots) \
{ while (cnt < numslots) \
cnt = READ_WORD(fb, REG_34); \
cnt -= numslots; \
}
#define IndexedDcd 0 /* Pixel data is indexed (pseudo) color */
#define Otc04 2 /* Pixels in each longword transfer (4) */
#define Otc32 5 /* Pixels in each longword transfer (32) */
#define Ots08 3 /* Each pixel is size (8)d transfer (1) */
#define OtsIndirect 6 /* Each bit goes through FG/BG color(8) */
#define AddrLong 5 /* FB address is Long aligned (pixel) */
#define BINovly 0x2 /* 8 bit overlay */
#define BINapp0I 0x0 /* Application Buffer 0, Indexed */
#define BINapp1I 0x1 /* Application Buffer 1, Indexed */
#define BINapp0F8 0xa /* Application Buffer 0, Fractional 8-8-8 */
#define BINattr 0xd /* Attribute Bitmap */
#define RopSrc 0x3
#define BitmapExtent08 3 /* Each write hits ( 8) bits in depth */
#define BitmapExtent32 5 /* Each write hits (32) bits in depth */
#define DataDynamic 0 /* Data register reloaded by direct access */
#define MaskDynamic 1 /* Mask register reloaded by direct access */
#define MaskOtc 0 /* Mask contains Object Count valid bits */
#define MaskAddrOffset(offset) (offset)
#define StaticReg(en) (en)
#define BGx(en) (en)
#define FGx(en) (en)
#define BAJustPoint(offset) (offset)
#define BAIndexBase(base) (base)
#define BA(F,C,S,A,J,B,I) \
(((F)<<31)|((C)<<27)|((S)<<24)|((A)<<21)|((J)<<16)|((B)<<12)|(I))
#define IBOvals(R,M,X,S,D,L,B,F) \
(((R)<<8)|((M)<<16)|((X)<<24)|((S)<<29)|((D)<<28)|((L)<<31)|((B)<<1)|(F))
#define NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb, val) \
WRITE_WORD(val, fb, REG_14)
#define NGLE_QUICK_SET_DST_BM_ACCESS(fb, val) \
WRITE_WORD(val, fb, REG_11)
#define NGLE_QUICK_SET_CTL_PLN_REG(fb, val) \
WRITE_WORD(val, fb, REG_12)
#define NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, plnmsk32) \
WRITE_WORD(plnmsk32, fb, REG_13)
#define NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, fg32) \
WRITE_WORD(fg32, fb, REG_35)
#define NGLE_SET_TRANSFERDATA(fb, val) \
WRITE_WORD(val, fb, REG_8)
#define NGLE_SET_DSTXY(fb, val) \
WRITE_WORD(val, fb, REG_6)
#define NGLE_LONG_FB_ADDRESS(fbaddrbase, x, y) ( \
(u32) (fbaddrbase) + \
( (unsigned int) ( (y) << 13 ) | \
(unsigned int) ( (x) << 2 ) ) \
)
#define NGLE_BINC_SET_DSTADDR(fb, addr) \
WRITE_WORD(addr, fb, REG_3)
#define NGLE_BINC_SET_SRCADDR(fb, addr) \
WRITE_WORD(addr, fb, REG_2)
#define NGLE_BINC_SET_DSTMASK(fb, mask) \
WRITE_WORD(mask, fb, REG_22)
#define NGLE_BINC_WRITE32(fb, data32) \
WRITE_WORD(data32, fb, REG_23)
#define START_COLORMAPLOAD(fb, cmapBltCtlData32) \
WRITE_WORD((cmapBltCtlData32), fb, REG_38)
#define SET_LENXY_START_RECFILL(fb, lenxy) \
WRITE_WORD(lenxy, fb, REG_9)
static void
HYPER_ENABLE_DISABLE_DISPLAY(struct stifb_info *fb, int enable)
{
u32 DregsHypMiscVideo = REG_33;
unsigned int value;
SETUP_HW(fb);
value = READ_WORD(fb, DregsHypMiscVideo);
if (enable)
value |= 0x0A000000;
else
value &= ~0x0A000000;
WRITE_WORD(value, fb, DregsHypMiscVideo);
}
/* BufferNumbers used by SETUP_ATTR_ACCESS() */
#define BUFF0_CMAP0 0x00001e02
#define BUFF1_CMAP0 0x02001e02
#define BUFF1_CMAP3 0x0c001e02
#define ARTIST_CMAP0 0x00000102
#define HYPER_CMAP8 0x00000100
#define HYPER_CMAP24 0x00000800
static void
SETUP_ATTR_ACCESS(struct stifb_info *fb, unsigned BufferNumber)
{
SETUP_HW(fb);
WRITE_WORD(0x2EA0D000, fb, REG_11);
WRITE_WORD(0x23000302, fb, REG_14);
WRITE_WORD(BufferNumber, fb, REG_12);
WRITE_WORD(0xffffffff, fb, REG_8);
}
static void
SET_ATTR_SIZE(struct stifb_info *fb, int width, int height)
{
WRITE_WORD(0x00000000, fb, REG_6);
WRITE_WORD((width<<16) | height, fb, REG_9);
WRITE_WORD(0x05000000, fb, REG_6);
WRITE_WORD(0x00040001, fb, REG_9);
}
static void
FINISH_ATTR_ACCESS(struct stifb_info *fb)
{
SETUP_HW(fb);
WRITE_WORD(0x00000000, fb, REG_12);
}
static void
elkSetupPlanes(struct stifb_info *fb)
{
SETUP_RAMDAC(fb);
SETUP_FB(fb);
}
static void
ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
{
SETUP_ATTR_ACCESS(fb, BufferNumber);
SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres);
FINISH_ATTR_ACCESS(fb);
SETUP_FB(fb);
}
static void
rattlerSetupPlanes(struct stifb_info *fb)
{
CRX24_SETUP_RAMDAC(fb);
/* replacement for: SETUP_FB(fb, CRX24_OVERLAY_PLANES); */
WRITE_WORD(0x83000300, fb, REG_14);
SETUP_HW(fb);
WRITE_BYTE(1, fb, REG_16b1);
/* XXX: replace by fb_setmem(), smem_start or screen_base ? */
memset_io(fb->info.fix.smem_start, 0xff,
fb->info.var.yres*fb->info.fix.line_length);
CRX24_SET_OVLY_MASK(fb);
SETUP_FB(fb);
}
#define HYPER_CMAP_TYPE 0
#define NGLE_CMAP_INDEXED0_TYPE 0
#define NGLE_CMAP_OVERLAY_TYPE 3
/* typedef of LUT (Colormap) BLT Control Register */
typedef union /* Note assumption that fields are packed left-to-right */
{ u32 all;
struct
{
unsigned enable : 1;
unsigned waitBlank : 1;
unsigned reserved1 : 4;
unsigned lutOffset : 10; /* Within destination LUT */
unsigned lutType : 2; /* Cursor, image, overlay */
unsigned reserved2 : 4;
unsigned length : 10;
} fields;
} NgleLutBltCtl;
#if 0
static NgleLutBltCtl
setNgleLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
{
NgleLutBltCtl lutBltCtl;
/* set enable, zero reserved fields */
lutBltCtl.all = 0x80000000;
lutBltCtl.fields.length = length;
switch (fb->id)
{
case S9000_ID_A1439A: /* CRX24 */
if (fb->var.bits_per_pixel == 8) {
lutBltCtl.fields.lutType = NGLE_CMAP_OVERLAY_TYPE;
lutBltCtl.fields.lutOffset = 0;
} else {
lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
lutBltCtl.fields.lutOffset = 0 * 256;
}
break;
case S9000_ID_ARTIST:
lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
lutBltCtl.fields.lutOffset = 0 * 256;
break;
default:
lutBltCtl.fields.lutType = NGLE_CMAP_INDEXED0_TYPE;
lutBltCtl.fields.lutOffset = 0;
break;
}
/* Offset points to start of LUT. Adjust for within LUT */
lutBltCtl.fields.lutOffset += offsetWithinLut;
return lutBltCtl;
}
#endif
static NgleLutBltCtl
setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
{
NgleLutBltCtl lutBltCtl;
/* set enable, zero reserved fields */
lutBltCtl.all = 0x80000000;
lutBltCtl.fields.length = length;
lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
/* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
if (fb->info.var.bits_per_pixel == 8)
lutBltCtl.fields.lutOffset = 2 * 256;
else
lutBltCtl.fields.lutOffset = 0 * 256;
/* Offset points to start of LUT. Adjust for within LUT */
lutBltCtl.fields.lutOffset += offsetWithinLut;
return lutBltCtl;
}
static void hyperUndoITE(struct stifb_info *fb)
{
int nFreeFifoSlots = 0;
u32 fbAddr;
NGLE_LOCK(fb);
GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
WRITE_WORD(0xffffffff, fb, REG_32);
/* Write overlay transparency mask so only entry 255 is transparent */
/* Hardware setup for full-depth write to "magic" location */
GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
NGLE_QUICK_SET_DST_BM_ACCESS(fb,
BA(IndexedDcd, Otc04, Ots08, AddrLong,
BAJustPoint(0), BINovly, BAIndexBase(0)));
NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
IBOvals(RopSrc, MaskAddrOffset(0),
BitmapExtent08, StaticReg(0),
DataDynamic, MaskOtc, BGx(0), FGx(0)));
/* Now prepare to write to the "magic" location */
fbAddr = NGLE_LONG_FB_ADDRESS(0, 1532, 0);
NGLE_BINC_SET_DSTADDR(fb, fbAddr);
NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffff);
NGLE_BINC_SET_DSTMASK(fb, 0xffffffff);
/* Finally, write a zero to clear the mask */
NGLE_BINC_WRITE32(fb, 0);
NGLE_UNLOCK(fb);
}
static void
ngleDepth8_ClearImagePlanes(struct stifb_info *fb)
{
/* FIXME! */
}
static void
ngleDepth24_ClearImagePlanes(struct stifb_info *fb)
{
/* FIXME! */
}
static void
ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
{
int nFreeFifoSlots = 0;
u32 packed_dst;
u32 packed_len;
NGLE_LOCK(fb);
GET_FIFO_SLOTS(fb, nFreeFifoSlots, 4);
NGLE_QUICK_SET_DST_BM_ACCESS(fb,
BA(IndexedDcd, Otc32, OtsIndirect,
AddrLong, BAJustPoint(0),
BINattr, BAIndexBase(0)));
NGLE_QUICK_SET_CTL_PLN_REG(fb, ctlPlaneReg);
NGLE_SET_TRANSFERDATA(fb, 0xffffffff);
NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
IBOvals(RopSrc, MaskAddrOffset(0),
BitmapExtent08, StaticReg(1),
DataDynamic, MaskOtc,
BGx(0), FGx(0)));
packed_dst = 0;
packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
NGLE_SET_DSTXY(fb, packed_dst);
SET_LENXY_START_RECFILL(fb, packed_len);
/*
* In order to work around an ELK hardware problem (Buffy doesn't
* always flush it's buffers when writing to the attribute
* planes), at least 4 pixels must be written to the attribute
* planes starting at (X == 1280) and (Y != to the last Y written
* by BIF):
*/
if (fb->id == S9000_ID_A1659A) { /* ELK_DEVICE_ID */
/* It's safe to use scanline zero: */
packed_dst = (1280 << 16);
GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
NGLE_SET_DSTXY(fb, packed_dst);
packed_len = (4 << 16) | 1;
SET_LENXY_START_RECFILL(fb, packed_len);
} /* ELK Hardware Kludge */
/**** Finally, set the Control Plane Register back to zero: ****/
GET_FIFO_SLOTS(fb, nFreeFifoSlots, 1);
NGLE_QUICK_SET_CTL_PLN_REG(fb, 0);
NGLE_UNLOCK(fb);
}
static void
ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
{
int nFreeFifoSlots = 0;
u32 packed_dst;
u32 packed_len;
NGLE_LOCK(fb);
/* Hardware setup */
GET_FIFO_SLOTS(fb, nFreeFifoSlots, 8);
NGLE_QUICK_SET_DST_BM_ACCESS(fb,
BA(IndexedDcd, Otc04, Ots08, AddrLong,
BAJustPoint(0), BINovly, BAIndexBase(0)));
NGLE_SET_TRANSFERDATA(fb, 0xffffffff); /* Write foreground color */
NGLE_REALLY_SET_IMAGE_FG_COLOR(fb, data);
NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
packed_dst = 0;
packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
NGLE_SET_DSTXY(fb, packed_dst);
/* Write zeroes to overlay planes */
NGLE_QUICK_SET_IMAGE_BITMAP_OP(fb,
IBOvals(RopSrc, MaskAddrOffset(0),
BitmapExtent08, StaticReg(0),
DataDynamic, MaskOtc, BGx(0), FGx(0)));
SET_LENXY_START_RECFILL(fb, packed_len);
NGLE_UNLOCK(fb);
}
static void
hyperResetPlanes(struct stifb_info *fb, int enable)
{
unsigned int controlPlaneReg;
NGLE_LOCK(fb);
if (IS_24_DEVICE(fb))
if (fb->info.var.bits_per_pixel == 32)
controlPlaneReg = 0x04000F00;
else
controlPlaneReg = 0x00000F00; /* 0x00000800 should be enought, but lets clear all 4 bits */
else
controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */
switch (enable) {
case 1: /* ENABLE */
/* clear screen */
if (IS_24_DEVICE(fb))
ngleDepth24_ClearImagePlanes(fb);
else
ngleDepth8_ClearImagePlanes(fb);
/* Paint attribute planes for default case.
* On Hyperdrive, this means all windows using overlay cmap 0. */
ngleResetAttrPlanes(fb, controlPlaneReg);
/* clear overlay planes */
ngleClearOverlayPlanes(fb, 0xff, 255);
/**************************************************
** Also need to counteract ITE settings
**************************************************/
hyperUndoITE(fb);
break;
case 0: /* DISABLE */
/* clear screen */
if (IS_24_DEVICE(fb))
ngleDepth24_ClearImagePlanes(fb);
else
ngleDepth8_ClearImagePlanes(fb);
ngleResetAttrPlanes(fb, controlPlaneReg);
ngleClearOverlayPlanes(fb, 0xff, 0);
break;
case -1: /* RESET */
hyperUndoITE(fb);
ngleResetAttrPlanes(fb, controlPlaneReg);
break;
}
NGLE_UNLOCK(fb);
}
/* Return pointer to in-memory structure holding ELK device-dependent ROM values. */
static void
ngleGetDeviceRomData(struct stifb_info *fb)
{
#if 0
XXX: FIXME: !!!
int *pBytePerLongDevDepData;/* data byte == LSB */
int *pRomTable;
NgleDevRomData *pPackedDevRomData;
int sizePackedDevRomData = sizeof(*pPackedDevRomData);
char *pCard8;
int i;
char *mapOrigin = NULL;
int romTableIdx;
pPackedDevRomData = fb->ngle_rom;
SETUP_HW(fb);
if (fb->id == S9000_ID_ARTIST) {
pPackedDevRomData->cursor_pipeline_delay = 4;
pPackedDevRomData->video_interleaves = 4;
} else {
/* Get pointer to unpacked byte/long data in ROM */
pBytePerLongDevDepData = fb->sti->regions[NGLEDEVDEPROM_CRT_REGION];
/* Tomcat supports several resolutions: 1280x1024, 1024x768, 640x480 */
if (fb->id == S9000_ID_TOMCAT)
{
/* jump to the correct ROM table */
GET_ROMTABLE_INDEX(romTableIdx);
while (romTableIdx > 0)
{
pCard8 = (Card8 *) pPackedDevRomData;
pRomTable = pBytePerLongDevDepData;
/* Pack every fourth byte from ROM into structure */
for (i = 0; i < sizePackedDevRomData; i++)
{
*pCard8++ = (Card8) (*pRomTable++);
}
pBytePerLongDevDepData = (Card32 *)
((Card8 *) pBytePerLongDevDepData +
pPackedDevRomData->sizeof_ngle_data);
romTableIdx--;
}
}
pCard8 = (Card8 *) pPackedDevRomData;
/* Pack every fourth byte from ROM into structure */
for (i = 0; i < sizePackedDevRomData; i++)
{
*pCard8++ = (Card8) (*pBytePerLongDevDepData++);
}
}
SETUP_FB(fb);
#endif
}
#define HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES 4
#define HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE 8
#define HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE 10
#define HYPERBOWL_MODE2_8_24 15
/* HCRX specific boot-time initialization */
static void __init
SETUP_HCRX(struct stifb_info *fb)
{
int hyperbowl;
int nFreeFifoSlots = 0;
if (fb->id != S9000_ID_HCRX)
return;
/* Initialize Hyperbowl registers */
GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
if (IS_24_DEVICE(fb)) {
hyperbowl = (fb->info.var.bits_per_pixel == 32) ?
HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
/* First write to Hyperbowl must happen twice (bug) */
WRITE_WORD(hyperbowl, fb, REG_40);
WRITE_WORD(hyperbowl, fb, REG_40);
WRITE_WORD(HYPERBOWL_MODE2_8_24, fb, REG_39);
WRITE_WORD(0x014c0148, fb, REG_42); /* Set lut 0 to be the direct color */
WRITE_WORD(0x404c4048, fb, REG_43);
WRITE_WORD(0x034c0348, fb, REG_44);
WRITE_WORD(0x444c4448, fb, REG_45);
} else {
hyperbowl = HYPERBOWL_MODE_FOR_8_OVER_88_LUT0_NO_TRANSPARENCIES;
/* First write to Hyperbowl must happen twice (bug) */
WRITE_WORD(hyperbowl, fb, REG_40);
WRITE_WORD(hyperbowl, fb, REG_40);
WRITE_WORD(0x00000000, fb, REG_42);
WRITE_WORD(0x00000000, fb, REG_43);
WRITE_WORD(0x00000000, fb, REG_44);
WRITE_WORD(0x444c4048, fb, REG_45);
}
}
/* ------------------- driver specific functions --------------------------- */
static int static int
sti_getcolreg(unsigned regno, unsigned *red, unsigned *green, stifb_setcolreg(u_int regno, u_int red, u_int green,
unsigned *blue, unsigned *transp, struct fb_info *info) u_int blue, u_int transp, struct fb_info *info)
{ {
struct stifb_info *fb = (struct stifb_info *) info;
u32 color;
if (regno >= 256) /* no. of hw registers */
return 1;
START_IMAGE_COLORMAP_ACCESS(fb);
if (fb->info.var.grayscale) {
/* gray = 0.30*R + 0.59*G + 0.11*B */
color = ((red * 77) +
(green * 151) +
(blue * 28)) >> 8;
} else {
color = ((red << 16) |
(green << 8) |
(blue));
}
WRITE_IMAGE_COLOR(fb, regno, 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);
}
return 0; return 0;
} }
#if 0
static void static void
sti_set_disp(const void *par, struct display *disp, stifb_loadcmap(struct stifb_info *fb)
struct fb_info_gen *info)
{ {
disp->dispsw = &fbcon_sti; 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 void static int
sti_detect(void) stifb_blank(int blank_mode, struct fb_info *info)
{ {
struct stifb_info *fb = (struct stifb_info *) info;
int enable = (blank_mode == 0) ? ENABLE : DISABLE;
switch (fb->id) {
case S9000_ID_A1439A:
CRX24_ENABLE_DISABLE_DISPLAY(fb, enable);
break;
case CRT_ID_VISUALIZE_EG:
case S9000_ID_ARTIST:
ARTIST_ENABLE_DISABLE_DISPLAY(fb, enable);
break;
case S9000_ID_HCRX:
HYPER_ENABLE_DISABLE_DISPLAY(fb, enable);
break;
case S9000_ID_A1659A:; /* fall through */
case S9000_ID_TIMBER:;
case CRX24_OVERLAY_PLANES:;
default:
ENABLE_DISABLE_DISPLAY(fb, enable);
break;
}
SETUP_FB(fb);
return 0;
}
static void __init
stifb_init_display(struct stifb_info *fb)
{
int id = fb->id;
SETUP_FB(fb);
/* HCRX specific initialization */
SETUP_HCRX(fb);
/*
if (id == S9000_ID_HCRX)
hyperInitSprite(fb);
else
ngleInitSprite(fb);
*/
/* Initialize the image planes. */
switch (id) {
case S9000_ID_HCRX:
hyperResetPlanes(fb, ENABLE);
break;
case S9000_ID_A1439A:
rattlerSetupPlanes(fb);
break;
case S9000_ID_A1659A:
case S9000_ID_ARTIST:
case CRT_ID_VISUALIZE_EG:
elkSetupPlanes(fb);
break;
}
/* Clear attribute planes on non HCRX devices. */
switch (id) {
case S9000_ID_A1659A:
case S9000_ID_A1439A:
if (fb->info.var.bits_per_pixel == 32)
ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
else {
ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
}
if (id == S9000_ID_A1439A)
ngleClearOverlayPlanes(fb, 0xff, 0);
break;
case S9000_ID_ARTIST:
case CRT_ID_VISUALIZE_EG:
if (fb->info.var.bits_per_pixel == 32)
ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
else {
ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
}
break;
}
stifb_blank(0, (struct fb_info *)fb); /* 0=enable screen */
SETUP_FB(fb);
} }
/* ------------ Interfaces to hardware functions ------------ */ /* ------------ Interfaces to hardware functions ------------ */
struct fbgen_hwswitch sti_switch = { static struct fb_ops stifb_ops = {
.detect = sti_detect, .owner = THIS_MODULE,
.encode_fix = sti_encode_fix, .fb_set_var = gen_set_var,
.decode_var = sti_decode_var, .fb_get_cmap = gen_get_cmap,
.encode_var = sti_encode_var, .fb_set_cmap = gen_set_cmap,
.get_par = sti_get_par, .fb_setcolreg = stifb_setcolreg,
.set_par = sti_set_par, /* .fb_pan_display = stifb_pan_display, */
.getcolreg = sti_getcolreg, .fb_blank = stifb_blank,
.set_disp = sti_set_disp
};
/*
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
*/
};
/* ------------ Hardware Independent Functions ------------ */
/* /*
* Initialization * Initialization
*/ */
int __init int __init
stifb_init(void) stifb_init_fb(struct sti_struct *sti, int force_bpp)
{ {
printk("searching for word mode STI ROMs\n"); struct fb_fix_screeninfo *fix;
/* XXX: in the future this will return a list of ROMs */ struct fb_var_screeninfo *var;
if ((fb_info.sti = sti_init_roms()) == NULL) struct display *disp;
return -ENXIO; struct display_switch *dispsw;
struct stifb_info *fb;
struct fb_info *info;
unsigned long sti_rom_address;
char *dev_name;
int bpp, xres, yres;
fb = kmalloc(sizeof(*fb), GFP_ATOMIC);
if (!fb) {
printk(KERN_ERR "stifb: Could not allocate stifb structure\n");
return -ENODEV;
}
info = &fb->info;
/* set struct to a known state */
memset(fb, 0, sizeof(*fb));
fix = &info->fix;
var = &info->var;
disp = &fb->disp;
info->disp = &fb->disp;
fb->sti = sti;
/* store upper 32bits of the graphics id */
fb->id = fb->sti->graphics_id[0];
/* only supported cards are allowed */
switch (fb->id) {
case S9000_ID_ARTIST:
case S9000_ID_HCRX:
case S9000_ID_TIMBER:
case S9000_ID_A1659A:
case S9000_ID_A1439A:
case CRT_ID_VISUALIZE_EG:
break;
default:
printk(KERN_WARNING "stifb: Unsupported gfx card id 0x%08x\n",
fb->id);
goto out_err1;
}
fb_info.gen.info.node = NODEV; /* default to 8 bpp on most graphic chips */
fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT; bpp = 8;
fb_info.gen.info.fbops = &stifb_ops; xres = sti_onscreen_x(fb->sti);
fb_info.gen.info.disp = &disp; yres = sti_onscreen_y(fb->sti);
fb_info.gen.info.changevar = NULL;
fb_info.gen.info.switch_con = &fbgen_switch; ngleGetDeviceRomData(fb);
fb_info.gen.info.updatevar = &fbgen_update_var;
strcpy(fb_info.gen.info.modename, "STI Generic"); /* get (virtual) io region base addr */
fb_info.gen.fbhw = &sti_switch; fix->mmio_start = REGION_BASE(fb,2);
fb_info.gen.fbhw->detect(); fix->mmio_len = 0x400000;
fb_info.gen.info.screen_base =
(void *) PTR_STI(fb_info.sti->glob_cfg)->region_ptrs[1]; /* Reject any device not in the NGLE family */
/* This should give a reasonable default video mode */ switch (fb->id) {
fbgen_get_var(&disp.var, -1, &fb_info.gen.info); case S9000_ID_A1659A: /* CRX/A1659A */
fbgen_do_set_var(&disp.var, 1, &fb_info.gen); break;
fbgen_set_disp(-1, &fb_info.gen); case S9000_ID_ELM: /* GRX, grayscale but else same as A1659A */
do_install_cmap(0, &fb_info.gen); var->grayscale = 1;
pdc_console_die(); fb->id = S9000_ID_A1659A;
if (register_framebuffer(&fb_info.gen.info) < 0) break;
return -EINVAL; case S9000_ID_TIMBER: /* HP9000/710 Any (may be a grayscale device) */
dev_name = fb->sti->outptr.dev_name;
printk(KERN_INFO "fb%d: %s frame buffer device\n", if (strstr(dev_name, "GRAYSCALE") ||
GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename); strstr(dev_name, "Grayscale") ||
strstr(dev_name, "grayscale"))
var->grayscale = 1;
break;
case S9000_ID_TOMCAT: /* Dual CRX, behaves else like a CRX */
/* FIXME: TomCat supports two heads:
* fb.iobase = REGION_BASE(fb_info,3);
* fb.screen_base = (void*) REGION_BASE(fb_info,2);
* for now we only support the left one ! */
xres = fb->ngle_rom.x_size_visible;
yres = fb->ngle_rom.y_size_visible;
fb->id = S9000_ID_A1659A;
break;
case S9000_ID_A1439A: /* CRX24/A1439A */
bpp = 32;
break;
case S9000_ID_HCRX: /* Hyperdrive/HCRX */
memset(&fb->ngle_rom, 0, sizeof(fb->ngle_rom));
if ((fb->sti->regions_phys[0] & 0xfc000000) ==
(fb->sti->regions_phys[2] & 0xfc000000))
sti_rom_address = fb->sti->regions_phys[0];
else
sti_rom_address = fb->sti->regions_phys[1];
#ifdef __LP64__
sti_rom_address |= 0xffffffff00000000;
#endif
fb->deviceSpecificConfig = __raw_readl(sti_rom_address);
if (IS_24_DEVICE(fb)) {
if (force_bpp == 8 || force_bpp == 32)
bpp = force_bpp;
else
bpp = 32;
} else
bpp = 8;
READ_WORD(fb, REG_15);
SETUP_HW(fb);
break;
case CRT_ID_VISUALIZE_EG:
case S9000_ID_ARTIST: /* Artist */
break;
default:
#ifdef FALLBACK_TO_1BPP
printk(KERN_WARNING
"stifb: Unsupported graphics card (id=0x%08x) "
"- now trying 1bpp mode instead\n",
fb->id);
bpp = 1; /* default to 1 bpp */
break;
#else
printk(KERN_WARNING
"stifb: Unsupported graphics card (id=0x%08x) "
"- skipping.\n",
fb->id);
goto out_err1;
#endif
}
/* get framebuffer pysical and virtual base addr & len (64bit ready) */
fix->smem_start = fb->sti->regions_phys[1] | 0xffffffff00000000;
fix->smem_len = fb->sti->regions[1].region_desc.length * 4096;
fix->line_length = (fb->sti->glob_cfg->total_x * bpp) / 8;
if (!fix->line_length)
fix->line_length = 2048; /* default */
fix->accel = FB_ACCEL_NONE;
switch (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;
}
var->xres = var->xres_virtual = xres;
var->yres = var->yres_virtual = yres;
var->bits_per_pixel = bpp;
strcpy(info->modename, "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",
fix->smem_start, fix->smem_start+fix->smem_len);
goto out_err1;
}
if (!request_mem_region(fix->mmio_start, fix->mmio_len, "stifb mmio")) {
printk(KERN_ERR "stifb: cannot reserve sti mmio region 0x%04lx-0x%04lx\n",
fix->mmio_start, fix->mmio_start+fix->mmio_len);
goto out_err2;
}
if (register_framebuffer(&fb->info) < 0)
goto out_err3;
printk(KERN_INFO
"fb%d: %s %dx%d-%d frame buffer device, id: %04x, mmio: 0x%04lx\n",
GET_FB_IDX(fb->info.node),
fb->info.modename,
disp->var.xres,
disp->var.yres,
disp->var.bits_per_pixel,
fb->id,
fix->mmio_start);
return 0; return 0;
out_err3:
release_mem_region(fix->mmio_start, fix->mmio_len);
out_err2:
release_mem_region(fix->smem_start, fix->smem_len);
out_err1:
kfree(fb);
return -ENXIO;
} }
int __init
stifb_init(void)
{
struct sti_struct *sti;
int i;
/* if (sti_init_roms() == NULL)
return -ENXIO; /* no STI cards available */
for (i = 0; i < MAX_STI_ROMS; i++) {
sti = sti_get_rom(i);
if (sti)
stifb_init_fb(sti, stifb_force_bpp[i]);
else
break;
}
return 0;
}
/*
* Cleanup * Cleanup
*/ */
void static void __exit
stifb_cleanup(struct fb_info *info) stifb_cleanup(void)
{ {
printk("stifb_cleanup: you're on crack\n"); // unregister_framebuffer();
} }
int __init int __init
stifb_setup(char *options) stifb_setup(char *options)
{ {
/* XXX: we should take the resolution, bpp as command line arguments. */ int i;
if (!options || !*options)
return 0;
if (strncmp(options, "bpp", 3) == 0) {
options += 3;
for (i = 0; i < MAX_STI_ROMS; i++) {
if (*options++ == ':')
stifb_force_bpp[i] = simple_strtoul(options, &options, 10);
else
break;
}
}
return 0; return 0;
} }
__setup("stifb=", stifb_setup);
/* ------------------------------------------------------------------------- */ #ifdef MODULE
module_init(stifb_init);
#endif
module_exit(stifb_cleanup);
MODULE_AUTHOR("Helge Deller <deller@gmx.de>, Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
MODULE_DESCRIPTION("Framebuffer driver for HP's NGLE series graphics cards in HP PARISC machines");
MODULE_LICENSE("GPL");
MODULE_PARM(bpp, "i");
MODULE_PARM_DESC(mem, "Bits per pixel (default: 8)");
static struct fb_ops stifb_ops = {
.owner = THIS_MODULE,
.fb_get_fix = fbgen_get_fix,
.fb_get_var = fbgen_get_var,
.fb_set_var = fbgen_set_var,
.fb_get_cmap = fbgen_get_cmap,
.fb_set_cmap = gen_set_cmap,
.fb_pan_display =fbgen_pan_display,
.fb_blank = fbgen_blank,
};
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