2005-04-17 02:20:36 +04:00
/*
* linux / drivers / video / stifb . c -
* Low level Frame buffer driver for HP workstations with
* STI ( standard text interface ) video firmware .
*
2006-03-23 01:19:46 +03:00
* Copyright ( C ) 2001 - 2006 Helge Deller < deller @ gmx . de >
2005-04-17 02:20:36 +04:00
* 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 >
* - based on skeletonfb , which was
* 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 1280 x1024 color device with 8 planes
* HPA4071A known as " HCRX24 " , a 1280 x1024 color device with 24 planes ,
* optionally available with a hardware accelerator as HPA4071A_Z
* HPA1659A known as " CRX " , a 1280 x1024 color device with 8 planes
* HPA1439A known as " CRX24 " , a 1280 x1024 color device with 24 planes ,
* optionally available with a hardware accelerator .
* HPA1924A known as " GRX " , a 1280 x1024 grayscale device with 8 planes
* HPA2269A known as " Dual CRX " , a 1280 x1024 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 1280 x1024 color displays with 8 planes .
* HP710G same as HP710C , 1280 x1024 grayscale only
* HP710L same as HP710C , 1024 x768 color only
* HP712 internal graphics support on HP9000s712 SPU , supports 640 x480 ,
* 1024 x768 or 1280 x1024 color displays on 8 planes ( Artist )
*
* 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:
* - 1 bpp mode is completely untested
* - add support for h / w acceleration
* - add hardware cursor
* - automatically disable double buffering ( e . g . on RDI precisionbook laptop )
*/
/* 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
# undef DEBUG_STIFB_REGS /* debug sti register accesses */
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/string.h>
# include <linux/mm.h>
# include <linux/slab.h>
# include <linux/delay.h>
# include <linux/fb.h>
# include <linux/init.h>
# include <linux/ioport.h>
# include <asm/grfioctl.h> /* for HP-UX compatibility */
# include <asm/uaccess.h>
# include "sticore.h"
/* REGION_BASE(fb_info, index) returns the virtual address for region <index> */
2006-01-11 04:48:03 +03:00
# define REGION_BASE(fb_info, index) \
F_EXTEND ( fb_info - > sti - > glob_cfg - > region_ptrs [ index ] )
2005-04-17 02:20:36 +04:00
# define NGLEDEVDEPROM_CRT_REGION 1
2006-01-11 04:48:04 +03:00
# define NR_PALETTE 256
2005-04-17 02:20:36 +04:00
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 fb_info info ;
unsigned int id ;
ngle_rom_t ngle_rom ;
struct sti_struct * sti ;
int deviceSpecificConfig ;
2006-01-11 04:48:04 +03:00
u32 pseudo_palette [ 16 ] ;
2005-04-17 02:20:36 +04:00
} ;
static int __initdata stifb_bpp_pref [ MAX_STI_ROMS ] ;
/* ------------------- chipset specific functions -------------------------- */
/* offsets to graphic-chip internal registers */
# 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
# define READ_BYTE(fb,reg) gsc_readb((fb)->info.fix.mmio_start + (reg))
# define READ_WORD(fb,reg) gsc_readl((fb)->info.fix.mmio_start + (reg))
# ifndef DEBUG_STIFB_REGS
# define DEBUG_OFF()
# define DEBUG_ON()
# define WRITE_BYTE(value,fb,reg) gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
# define WRITE_WORD(value,fb,reg) gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
# else
static int debug_on = 1 ;
# define DEBUG_OFF() debug_on=0
# define DEBUG_ON() debug_on=1
# define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
printk ( KERN_DEBUG " %30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x) \n " , \
2008-04-28 13:15:47 +04:00
__func__ , reg , value , READ_BYTE ( fb , reg ) ) ; \
2005-04-17 02:20:36 +04:00
gsc_writeb ( ( value ) , ( fb ) - > info . fix . mmio_start + ( reg ) ) ; } while ( 0 )
# define WRITE_WORD(value,fb,reg) do { if (debug_on) \
printk ( KERN_DEBUG " %30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x) \n " , \
2008-04-28 13:15:47 +04:00
__func__ , reg , value , READ_WORD ( fb , reg ) ) ; \
2005-04-17 02:20:36 +04:00
gsc_writel ( ( value ) , ( fb ) - > info . fix . mmio_start + ( reg ) ) ; } while ( 0 )
# endif /* DEBUG_STIFB_REGS */
# define ENABLE 1 /* for enabling/disabling screen */
# define DISABLE 0
# define NGLE_LOCK(fb_info) do { } while (0)
# define NGLE_UNLOCK(fb_info) do { } while (0)
static void
SETUP_HW ( struct stifb_info * fb )
{
char stat ;
do {
stat = READ_BYTE ( fb , REG_15b0 ) ;
if ( ! stat )
stat = READ_BYTE ( fb , REG_15b0 ) ;
} while ( stat ) ;
}
static void
SETUP_FB ( struct stifb_info * fb )
{
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 void
START_IMAGE_COLORMAP_ACCESS ( struct stifb_info * fb )
{
SETUP_HW ( fb ) ;
WRITE_WORD ( 0xBBE0F000 , fb , REG_10 ) ;
WRITE_WORD ( 0x03000300 , fb , REG_14 ) ;
WRITE_WORD ( ~ 0 , fb , REG_13 ) ;
}
static void
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 ) ;
}
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
SETUP_RAMDAC ( struct stifb_info * fb )
{
SETUP_HW ( fb ) ;
WRITE_WORD ( 0x04000000 , fb , 0x1020 ) ;
WRITE_WORD ( 0xff000000 , fb , 0x1028 ) ;
}
static void
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 ) ) )
2006-01-11 04:48:04 +03:00
# define GET_FIFO_SLOTS(fb, cnt, numslots) \
{ while ( cnt < numslots ) \
2005-04-17 02:20:36 +04:00
cnt = READ_WORD ( fb , REG_34 ) ; \
2006-01-11 04:48:04 +03:00
cnt - = numslots ; \
2005-04-17 02:20:36 +04:00
}
# 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 )
{
/* REG_6 seems to have special values when run on a
RDI precisionbook parisc laptop ( INTERNAL_EG_DX1024 or
INTERNAL_EG_X1024 ) . The values are :
0x2f0 : internal ( LCD ) & external display enabled
0x2a0 : external display only
0x000 : zero on standard artist graphic cards
*/
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 )
{
2008-03-10 21:44:01 +03:00
int saved_id , y ;
/* Write RAMDAC pixel read mask register so all overlay
* planes are display - enabled . ( CRX24 uses Bt462 pixel
* read mask register for overlay planes , not image planes ) .
*/
2005-04-17 02:20:36 +04:00
CRX24_SETUP_RAMDAC ( fb ) ;
2008-03-10 21:44:01 +03:00
/* change fb->id temporarily to fool SETUP_FB() */
saved_id = fb - > id ;
fb - > id = CRX24_OVERLAY_PLANES ;
SETUP_FB ( fb ) ;
fb - > id = saved_id ;
for ( y = 0 ; y < fb - > info . var . yres ; + + y )
memset ( fb - > info . screen_base + y * fb - > info . fix . line_length ,
0xff , fb - > info . var . xres * fb - > info . var . bits_per_pixel / 8 ) ;
2005-04-17 02:20:36 +04:00
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 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 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
stifb_setcolreg ( u_int regno , u_int red , u_int green ,
u_int blue , u_int transp , struct fb_info * info )
{
struct stifb_info * fb = ( struct stifb_info * ) info ;
u32 color ;
2006-01-11 04:48:04 +03:00
if ( regno > = NR_PALETTE )
2005-04-17 02:20:36 +04:00
return 1 ;
red > > = 8 ;
green > > = 8 ;
blue > > = 8 ;
DEBUG_OFF ( ) ;
START_IMAGE_COLORMAP_ACCESS ( fb ) ;
2006-01-11 04:48:04 +03:00
if ( unlikely ( fb - > info . var . grayscale ) ) {
2005-04-17 02:20:36 +04:00
/* 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 ) ) ;
}
2006-01-11 04:48:04 +03:00
if ( fb - > info . fix . visual = = FB_VISUAL_DIRECTCOLOR ) {
struct fb_var_screeninfo * var = & fb - > info . var ;
if ( regno < 16 )
( ( u32 * ) fb - > info . pseudo_palette ) [ regno ] =
regno < < var - > red . offset |
regno < < var - > green . offset |
regno < < var - > blue . offset ;
2005-04-17 02:20:36 +04:00
}
WRITE_IMAGE_COLOR ( fb , regno , color ) ;
2006-01-11 04:48:04 +03:00
2005-04-17 02:20:36 +04:00
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 ) ;
}
DEBUG_ON ( ) ;
return 0 ;
}
static int
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 ;
2006-01-11 04:48:04 +03:00
case S9000_ID_A1659A : /* fall through */
case S9000_ID_TIMBER :
case CRX24_OVERLAY_PLANES :
2005-04-17 02:20:36 +04:00
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 ------------ */
static struct fb_ops stifb_ops = {
. owner = THIS_MODULE ,
. fb_setcolreg = stifb_setcolreg ,
. fb_blank = stifb_blank ,
. fb_fillrect = cfb_fillrect ,
. fb_copyarea = cfb_copyarea ,
. fb_imageblit = cfb_imageblit ,
} ;
/*
* Initialization
*/
2008-07-26 06:46:27 +04:00
static int __init stifb_init_fb ( struct sti_struct * sti , int bpp_pref )
2005-04-17 02:20:36 +04:00
{
struct fb_fix_screeninfo * fix ;
struct fb_var_screeninfo * var ;
struct stifb_info * fb ;
struct fb_info * info ;
unsigned long sti_rom_address ;
char * dev_name ;
int bpp , xres , yres ;
2006-03-23 01:19:46 +03:00
fb = kzalloc ( sizeof ( * fb ) , GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( ! fb ) {
printk ( KERN_ERR " stifb: Could not allocate stifb structure \n " ) ;
return - ENODEV ;
}
info = & fb - > info ;
/* set struct to a known state */
fix = & info - > fix ;
var = & info - > var ;
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 CRT_ID_VISUALIZE_EG :
2007-08-11 00:00:45 +04:00
/* Visualize cards can run either in "double buffer" or
" standard " mode . Depending on the mode , the card reports
a different device name , e . g . " INTERNAL_EG_DX1024 " in double
buffer mode and " INTERNAL_EG_X1024 " in standard mode .
Since this driver only supports standard mode , we check
if the device name contains the string " DX " and tell the
user how to reconfigure the card . */
if ( strstr ( sti - > outptr . dev_name , " DX " ) ) {
printk ( KERN_WARNING " WARNING: stifb framebuffer driver does not "
" support '%s' in double-buffer mode. \n "
KERN_WARNING " WARNING: Please disable the double-buffer mode "
" in IPL menu (the PARISC-BIOS). \n " ,
2005-04-17 02:20:36 +04:00
sti - > outptr . dev_name ) ;
goto out_err0 ;
}
/* fall though */
case S9000_ID_ARTIST :
case S9000_ID_HCRX :
case S9000_ID_TIMBER :
case S9000_ID_A1659A :
case S9000_ID_A1439A :
break ;
default :
printk ( KERN_WARNING " stifb: '%s' (id: 0x%08x) not supported. \n " ,
sti - > outptr . dev_name , fb - > id ) ;
goto out_err0 ;
}
/* default to 8 bpp on most graphic chips */
bpp = 8 ;
xres = sti_onscreen_x ( fb - > sti ) ;
yres = sti_onscreen_y ( fb - > sti ) ;
ngleGetDeviceRomData ( fb ) ;
/* get (virtual) io region base addr */
fix - > mmio_start = REGION_BASE ( fb , 2 ) ;
fix - > mmio_len = 0x400000 ;
/* Reject any device not in the NGLE family */
switch ( fb - > id ) {
case S9000_ID_A1659A : /* CRX/A1659A */
break ;
case S9000_ID_ELM : /* GRX, grayscale but else same as A1659A */
var - > grayscale = 1 ;
fb - > id = S9000_ID_A1659A ;
break ;
case S9000_ID_TIMBER : /* HP9000/710 Any (may be a grayscale device) */
dev_name = fb - > sti - > outptr . dev_name ;
if ( strstr ( dev_name , " GRAYSCALE " ) | |
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 ) ;
2006-03-23 01:19:46 +03:00
* fb . screen_base = ioremap_nocache ( REGION_BASE ( fb_info , 2 ) , xxx ) ;
2005-04-17 02:20:36 +04:00
* 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 ) )
2006-01-11 04:48:03 +03:00
sti_rom_address = F_EXTEND ( fb - > sti - > regions_phys [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
else
2006-01-11 04:48:03 +03:00
sti_rom_address = F_EXTEND ( fb - > sti - > regions_phys [ 1 ] ) ;
2005-04-17 02:20:36 +04:00
fb - > deviceSpecificConfig = gsc_readl ( sti_rom_address ) ;
if ( IS_24_DEVICE ( fb ) ) {
if ( bpp_pref = = 8 | | bpp_pref = = 32 )
bpp = bpp_pref ;
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_err0 ;
# endif
}
/* get framebuffer physical and virtual base addr & len (64bit ready) */
fix - > smem_start = F_EXTEND ( fb - > sti - > regions_phys [ 1 ] ) ;
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 */
/* limit fbsize to max visible screen size */
if ( fix - > smem_len > yres * fix - > line_length )
fix - > smem_len = yres * fix - > line_length ;
fix - > accel = FB_ACCEL_NONE ;
switch ( bpp ) {
case 1 :
fix - > type = FB_TYPE_PLANES ; /* well, sort of */
fix - > visual = FB_VISUAL_MONO10 ;
var - > red . length = var - > green . length = var - > blue . length = 1 ;
break ;
case 8 :
fix - > type = FB_TYPE_PACKED_PIXELS ;
fix - > visual = FB_VISUAL_PSEUDOCOLOR ;
var - > red . length = var - > green . length = var - > blue . length = 8 ;
break ;
case 32 :
fix - > type = FB_TYPE_PACKED_PIXELS ;
2006-01-11 04:48:04 +03:00
fix - > visual = FB_VISUAL_DIRECTCOLOR ;
2005-04-17 02:20:36 +04:00
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 ;
default :
break ;
}
var - > xres = var - > xres_virtual = xres ;
var - > yres = var - > yres_virtual = yres ;
var - > bits_per_pixel = bpp ;
strcpy ( fix - > id , " stifb " ) ;
info - > fbops = & stifb_ops ;
2006-03-23 01:19:46 +03:00
info - > screen_base = ioremap_nocache ( REGION_BASE ( fb , 1 ) , fix - > smem_len ) ;
info - > screen_size = fix - > smem_len ;
2005-04-17 02:20:36 +04:00
info - > flags = FBINFO_DEFAULT ;
info - > pseudo_palette = & fb - > pseudo_palette ;
/* This has to been done !!! */
2006-01-11 04:48:04 +03:00
fb_alloc_cmap ( & info - > cmap , NR_PALETTE , 0 ) ;
2005-04-17 02:20:36 +04:00
stifb_init_display ( fb ) ;
if ( ! request_mem_region ( fix - > smem_start , fix - > smem_len , " stifb fb " ) ) {
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 ;
sti - > info = info ; /* save for unregister_framebuffer() */
printk ( KERN_INFO
" fb%d: %s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx \n " ,
fb - > info . node ,
fix - > id ,
var - > xres ,
var - > yres ,
var - > bits_per_pixel ,
sti - > outptr . dev_name ,
fb - > id ,
fix - > mmio_start ) ;
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 :
2006-12-08 13:40:05 +03:00
iounmap ( info - > screen_base ) ;
2005-04-17 02:20:36 +04:00
fb_dealloc_cmap ( & info - > cmap ) ;
out_err0 :
kfree ( fb ) ;
return - ENXIO ;
}
static int stifb_disabled __initdata ;
int __init
stifb_setup ( char * options ) ;
2008-07-26 06:46:27 +04:00
static int __init stifb_init ( void )
2005-04-17 02:20:36 +04:00
{
struct sti_struct * sti ;
struct sti_struct * def_sti ;
int i ;
# ifndef MODULE
char * option = NULL ;
if ( fb_get_options ( " stifb " , & option ) )
return - ENODEV ;
stifb_setup ( option ) ;
# endif
if ( stifb_disabled ) {
printk ( KERN_INFO " stifb: disabled by \" stifb=off \" kernel parameter \n " ) ;
return - ENXIO ;
}
def_sti = sti_get_rom ( 0 ) ;
if ( def_sti ) {
for ( i = 1 ; i < = MAX_STI_ROMS ; i + + ) {
sti = sti_get_rom ( i ) ;
if ( ! sti )
break ;
if ( sti = = def_sti ) {
stifb_init_fb ( sti , stifb_bpp_pref [ i - 1 ] ) ;
break ;
}
}
}
for ( i = 1 ; i < = MAX_STI_ROMS ; i + + ) {
sti = sti_get_rom ( i ) ;
if ( ! sti )
break ;
if ( sti = = def_sti )
continue ;
stifb_init_fb ( sti , stifb_bpp_pref [ i - 1 ] ) ;
}
return 0 ;
}
/*
* Cleanup
*/
static void __exit
stifb_cleanup ( void )
{
struct sti_struct * sti ;
int i ;
for ( i = 1 ; i < = MAX_STI_ROMS ; i + + ) {
sti = sti_get_rom ( i ) ;
if ( ! sti )
break ;
if ( sti - > info ) {
struct fb_info * info = sti - > info ;
unregister_framebuffer ( sti - > info ) ;
release_mem_region ( info - > fix . mmio_start , info - > fix . mmio_len ) ;
release_mem_region ( info - > fix . smem_start , info - > fix . smem_len ) ;
2006-12-08 13:40:05 +03:00
if ( info - > screen_base )
iounmap ( info - > screen_base ) ;
2005-04-17 02:20:36 +04:00
fb_dealloc_cmap ( & info - > cmap ) ;
kfree ( info ) ;
}
sti - > info = NULL ;
}
}
int __init
stifb_setup ( char * options )
{
int i ;
if ( ! options | | ! * options )
2006-03-31 14:30:33 +04:00
return 1 ;
2005-04-17 02:20:36 +04:00
if ( strncmp ( options , " off " , 3 ) = = 0 ) {
stifb_disabled = 1 ;
options + = 3 ;
}
if ( strncmp ( options , " bpp " , 3 ) = = 0 ) {
options + = 3 ;
for ( i = 0 ; i < MAX_STI_ROMS ; i + + ) {
if ( * options + + ! = ' : ' )
break ;
stifb_bpp_pref [ i ] = simple_strtoul ( options , & options , 10 ) ;
}
}
2006-03-31 14:30:33 +04:00
return 1 ;
2005-04-17 02:20:36 +04:00
}
__setup ( " stifb= " , stifb_setup ) ;
module_init ( stifb_init ) ;
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 v2 " ) ;