2005-04-17 02:20:36 +04:00
/*
* drivers / video / cirrusfb . c - driver for Cirrus Logic chipsets
*
* Copyright 1999 - 2001 Jeff Garzik < jgarzik @ pobox . com >
*
* Contributors ( thanks , all ! )
*
* David Eger :
* Overhaul for Linux 2.6
*
* Jeff Rugen :
* Major contributions ; Motorola PowerStack ( PPC and PCI ) support ,
* GD54xx , 1280 x1024 mode support , change MCLK based on VCLK .
*
* Geert Uytterhoeven :
* Excellent code review .
*
* Lars Hecking :
* Amiga updates and testing .
*
* Original cirrusfb author : Frank Neumann
*
* Based on retz3fb . c and cirrusfb . c :
* Copyright ( C ) 1997 Jes Sorensen
* Copyright ( C ) 1996 Frank Neumann
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Format this code with GNU indent ' - kr - i8 - pcs ' options .
*
* 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 .
*
*/
# define CIRRUSFB_VERSION "2.0-pre2"
# 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/selection.h>
# include <asm/pgtable.h>
# ifdef CONFIG_ZORRO
# include <linux/zorro.h>
# endif
# ifdef CONFIG_PCI
# include <linux/pci.h>
# endif
# ifdef CONFIG_AMIGA
# include <asm/amigahw.h>
# endif
# ifdef CONFIG_PPC_PREP
2006-03-28 16:15:54 +04:00
# include <asm/machdep.h>
2007-10-16 12:29:08 +04:00
# define isPReP machine_is(prep)
2005-04-17 02:20:36 +04:00
# else
# define isPReP 0
# endif
# include "video/vga.h"
# include "video/cirrus.h"
/*****************************************************************
*
* debugging and utility macros
*
*/
/* enable debug output? */
/* #define CIRRUSFB_DEBUG 1 */
/* disable runtime assertions? */
/* #define CIRRUSFB_NDEBUG */
/* debug output */
# ifdef CIRRUSFB_DEBUG
2007-10-16 12:29:08 +04:00
# define DPRINTK(fmt, args...) \
printk ( KERN_DEBUG " %s: " fmt , __FUNCTION__ , # # args )
2005-04-17 02:20:36 +04:00
# else
# define DPRINTK(fmt, args...)
# endif
/* debugging assertions */
# ifndef CIRRUSFB_NDEBUG
# define assert(expr) \
2007-10-16 12:29:08 +04:00
if ( ! ( expr ) ) { \
printk ( " Assertion failed! %s,%s,%s,line=%d \n " , \
# expr, __FILE__, __FUNCTION__, __LINE__); \
}
2005-04-17 02:20:36 +04:00
# else
# define assert(expr)
# endif
2007-10-16 12:29:08 +04:00
# define MB_ (1024 * 1024)
2005-04-17 02:20:36 +04:00
# define KB_ (1024)
# define MAX_NUM_BOARDS 7
/*****************************************************************
*
* chipset information
*
*/
/* board types */
2007-10-16 12:29:11 +04:00
enum cirrus_board {
2005-04-17 02:20:36 +04:00
BT_NONE = 0 ,
BT_SD64 ,
BT_PICCOLO ,
BT_PICASSO ,
BT_SPECTRUM ,
BT_PICASSO4 , /* GD5446 */
BT_ALPINE , /* GD543x/4x */
BT_GD5480 ,
BT_LAGUNA , /* GD546x */
2007-10-16 12:29:11 +04:00
} ;
2005-04-17 02:20:36 +04:00
/*
* per - board - type information , used for enumerating and abstracting
* chip - specific information
2007-10-16 12:29:11 +04:00
* NOTE : MUST be in the same order as enum cirrus_board in order to
2005-04-17 02:20:36 +04:00
* use direct indexing on this array
* NOTE : ' __initdata ' cannot be used as some of this info
* is required at runtime . Maybe separate into an init - only and
* a run - time table ?
*/
static const struct cirrusfb_board_info_rec {
char * name ; /* ASCII name of chipset */
long maxclock [ 5 ] ; /* maximum video clock */
/* for 1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */
2007-05-08 11:38:29 +04:00
bool init_sr07 : 1 ; /* init SR07 during init_vgachip() */
bool init_sr1f : 1 ; /* write SR1F during init_vgachip() */
2007-10-16 12:29:08 +04:00
/* construct bit 19 of screen start address */
bool scrn_start_bit19 : 1 ;
2005-04-17 02:20:36 +04:00
/* initial SR07 value, then for each mode */
unsigned char sr07 ;
unsigned char sr07_1bpp ;
unsigned char sr07_1bpp_mux ;
unsigned char sr07_8bpp ;
unsigned char sr07_8bpp_mux ;
unsigned char sr1f ; /* SR1F VGA initial register value */
} cirrusfb_board_info [ ] = {
[ BT_SD64 ] = {
. name = " CL SD64 " ,
. maxclock = {
/* guess */
/* the SD64/P4 have a higher max. videoclock */
140000 , 140000 , 140000 , 140000 , 140000 ,
} ,
2007-05-08 11:38:29 +04:00
. init_sr07 = true ,
. init_sr1f = true ,
. scrn_start_bit19 = true ,
2005-04-17 02:20:36 +04:00
. sr07 = 0xF0 ,
. sr07_1bpp = 0xF0 ,
. sr07_8bpp = 0xF1 ,
. sr1f = 0x20
} ,
[ BT_PICCOLO ] = {
. name = " CL Piccolo " ,
. maxclock = {
/* guess */
90000 , 90000 , 90000 , 90000 , 90000
} ,
2007-05-08 11:38:29 +04:00
. init_sr07 = true ,
. init_sr1f = true ,
. scrn_start_bit19 = false ,
2005-04-17 02:20:36 +04:00
. sr07 = 0x80 ,
. sr07_1bpp = 0x80 ,
. sr07_8bpp = 0x81 ,
. sr1f = 0x22
} ,
[ BT_PICASSO ] = {
. name = " CL Picasso " ,
. maxclock = {
/* guess */
90000 , 90000 , 90000 , 90000 , 90000
} ,
2007-05-08 11:38:29 +04:00
. init_sr07 = true ,
. init_sr1f = true ,
. scrn_start_bit19 = false ,
2005-04-17 02:20:36 +04:00
. sr07 = 0x20 ,
. sr07_1bpp = 0x20 ,
. sr07_8bpp = 0x21 ,
. sr1f = 0x22
} ,
[ BT_SPECTRUM ] = {
. name = " CL Spectrum " ,
. maxclock = {
/* guess */
90000 , 90000 , 90000 , 90000 , 90000
} ,
2007-05-08 11:38:29 +04:00
. init_sr07 = true ,
. init_sr1f = true ,
. scrn_start_bit19 = false ,
2005-04-17 02:20:36 +04:00
. sr07 = 0x80 ,
. sr07_1bpp = 0x80 ,
. sr07_8bpp = 0x81 ,
. sr1f = 0x22
} ,
[ BT_PICASSO4 ] = {
. name = " CL Picasso4 " ,
. maxclock = {
135100 , 135100 , 85500 , 85500 , 0
} ,
2007-05-08 11:38:29 +04:00
. init_sr07 = true ,
. init_sr1f = false ,
. scrn_start_bit19 = true ,
2005-04-17 02:20:36 +04:00
. sr07 = 0x20 ,
. sr07_1bpp = 0x20 ,
. sr07_8bpp = 0x21 ,
. sr1f = 0
} ,
[ BT_ALPINE ] = {
. name = " CL Alpine " ,
. maxclock = {
/* for the GD5430. GD5446 can do more... */
85500 , 85500 , 50000 , 28500 , 0
} ,
2007-05-08 11:38:29 +04:00
. init_sr07 = true ,
. init_sr1f = true ,
. scrn_start_bit19 = true ,
2005-04-17 02:20:36 +04:00
. sr07 = 0xA0 ,
. sr07_1bpp = 0xA1 ,
. sr07_1bpp_mux = 0xA7 ,
. sr07_8bpp = 0xA1 ,
. sr07_8bpp_mux = 0xA7 ,
. sr1f = 0x1C
} ,
[ BT_GD5480 ] = {
. name = " CL GD5480 " ,
. maxclock = {
135100 , 200000 , 200000 , 135100 , 135100
} ,
2007-05-08 11:38:29 +04:00
. init_sr07 = true ,
. init_sr1f = true ,
. scrn_start_bit19 = true ,
2005-04-17 02:20:36 +04:00
. sr07 = 0x10 ,
. sr07_1bpp = 0x11 ,
. sr07_8bpp = 0x11 ,
. sr1f = 0x1C
} ,
[ BT_LAGUNA ] = {
. name = " CL Laguna " ,
. maxclock = {
/* guess */
135100 , 135100 , 135100 , 135100 , 135100 ,
} ,
2007-05-08 11:38:29 +04:00
. init_sr07 = false ,
. init_sr1f = false ,
. scrn_start_bit19 = true ,
2005-04-17 02:20:36 +04:00
}
} ;
# ifdef CONFIG_PCI
# define CHIP(id, btype) \
2005-09-29 04:40:52 +04:00
{ PCI_VENDOR_ID_CIRRUS , id , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , ( btype ) }
2005-04-17 02:20:36 +04:00
static struct pci_device_id cirrusfb_pci_table [ ] = {
2007-10-16 12:29:08 +04:00
CHIP ( PCI_DEVICE_ID_CIRRUS_5436 , BT_ALPINE ) ,
CHIP ( PCI_DEVICE_ID_CIRRUS_5434_8 , BT_ALPINE ) ,
CHIP ( PCI_DEVICE_ID_CIRRUS_5434_4 , BT_ALPINE ) ,
CHIP ( PCI_DEVICE_ID_CIRRUS_5430 , BT_ALPINE ) , /* GD-5440 is same id */
CHIP ( PCI_DEVICE_ID_CIRRUS_7543 , BT_ALPINE ) ,
CHIP ( PCI_DEVICE_ID_CIRRUS_7548 , BT_ALPINE ) ,
CHIP ( PCI_DEVICE_ID_CIRRUS_5480 , BT_GD5480 ) , /* MacPicasso likely */
CHIP ( PCI_DEVICE_ID_CIRRUS_5446 , BT_PICASSO4 ) , /* Picasso 4 is 5446 */
CHIP ( PCI_DEVICE_ID_CIRRUS_5462 , BT_LAGUNA ) , /* CL Laguna */
CHIP ( PCI_DEVICE_ID_CIRRUS_5464 , BT_LAGUNA ) , /* CL Laguna 3D */
CHIP ( PCI_DEVICE_ID_CIRRUS_5465 , BT_LAGUNA ) , /* CL Laguna 3DA*/
2005-04-17 02:20:36 +04:00
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , cirrusfb_pci_table ) ;
# undef CHIP
# endif /* CONFIG_PCI */
# ifdef CONFIG_ZORRO
static const struct zorro_device_id cirrusfb_zorro_table [ ] = {
{
. id = ZORRO_PROD_HELFRICH_SD64_RAM ,
. driver_data = BT_SD64 ,
} , {
. id = ZORRO_PROD_HELFRICH_PICCOLO_RAM ,
. driver_data = BT_PICCOLO ,
} , {
2007-10-16 12:29:08 +04:00
. id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM ,
2005-04-17 02:20:36 +04:00
. driver_data = BT_PICASSO ,
} , {
. id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM ,
. driver_data = BT_SPECTRUM ,
} , {
. id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3 ,
. driver_data = BT_PICASSO4 ,
} ,
{ 0 }
} ;
static const struct {
zorro_id id2 ;
unsigned long size ;
} cirrusfb_zorro_table2 [ ] = {
[ BT_SD64 ] = {
. id2 = ZORRO_PROD_HELFRICH_SD64_REG ,
. size = 0x400000
} ,
[ BT_PICCOLO ] = {
. id2 = ZORRO_PROD_HELFRICH_PICCOLO_REG ,
. size = 0x200000
} ,
[ BT_PICASSO ] = {
. id2 = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG ,
. size = 0x200000
} ,
[ BT_SPECTRUM ] = {
. id2 = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG ,
. size = 0x200000
} ,
[ BT_PICASSO4 ] = {
. id2 = 0 ,
. size = 0x400000
}
} ;
# endif /* CONFIG_ZORRO */
struct cirrusfb_regs {
__u32 line_length ; /* in BYTES! */
__u32 visual ;
__u32 type ;
long freq ;
long nom ;
long den ;
long div ;
long multiplexing ;
long mclk ;
long divMCLK ;
long HorizRes ; /* The x resolution in pixel */
long HorizTotal ;
long HorizDispEnd ;
long HorizBlankStart ;
long HorizBlankEnd ;
long HorizSyncStart ;
long HorizSyncEnd ;
long VertRes ; /* the physical y resolution in scanlines */
long VertTotal ;
long VertDispEnd ;
long VertSyncStart ;
long VertSyncEnd ;
long VertBlankStart ;
long VertBlankEnd ;
} ;
# ifdef CIRRUSFB_DEBUG
2007-10-16 12:29:11 +04:00
enum cirrusfb_dbg_reg_class {
2007-10-16 12:29:08 +04:00
CRT ,
SEQ
2007-10-16 12:29:11 +04:00
} ;
2007-10-16 12:29:08 +04:00
# endif /* CIRRUSFB_DEBUG */
2005-04-17 02:20:36 +04:00
/* info about board */
struct cirrusfb_info {
u8 __iomem * regbase ;
2007-10-16 12:29:11 +04:00
enum cirrus_board btype ;
2005-04-17 02:20:36 +04:00
unsigned char SFR ; /* Shadow of special function register */
struct cirrusfb_regs currentmode ;
int blank_mode ;
2005-11-30 06:34:43 +03:00
u32 pseudo_palette [ 16 ] ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_ZORRO
struct zorro_dev * zdev ;
# endif
# ifdef CONFIG_PCI
struct pci_dev * pdev ;
# endif
2007-10-16 12:29:12 +04:00
void ( * unmap ) ( struct fb_info * info ) ;
2005-04-17 02:20:36 +04:00
} ;
static unsigned cirrusfb_def_mode = 1 ;
2007-10-16 12:29:08 +04:00
static int noaccel ;
2005-04-17 02:20:36 +04:00
/*
* Predefined Video Modes
*/
static const struct {
const char * name ;
struct fb_var_screeninfo var ;
} cirrusfb_predefined [ ] = {
{
/* autodetect mode */
. name = " Autodetect " ,
} , {
/* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
. name = " 640x480 " ,
. var = {
. xres = 640 ,
. yres = 480 ,
. xres_virtual = 640 ,
. yres_virtual = 480 ,
. bits_per_pixel = 8 ,
. red = { . length = 8 } ,
. green = { . length = 8 } ,
. blue = { . length = 8 } ,
. width = - 1 ,
. height = - 1 ,
. pixclock = 40000 ,
. left_margin = 48 ,
. right_margin = 16 ,
. upper_margin = 32 ,
. lower_margin = 8 ,
. hsync_len = 96 ,
. vsync_len = 4 ,
2007-10-16 12:29:08 +04:00
. sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT ,
2005-04-17 02:20:36 +04:00
. vmode = FB_VMODE_NONINTERLACED
}
} , {
/* 800x600, 48 kHz, 76 Hz, 50 MHz PixClock */
. name = " 800x600 " ,
. var = {
. xres = 800 ,
. yres = 600 ,
. xres_virtual = 800 ,
. yres_virtual = 600 ,
. bits_per_pixel = 8 ,
. red = { . length = 8 } ,
. green = { . length = 8 } ,
. blue = { . length = 8 } ,
. width = - 1 ,
. height = - 1 ,
. pixclock = 20000 ,
. left_margin = 128 ,
. right_margin = 16 ,
. upper_margin = 24 ,
. lower_margin = 2 ,
. hsync_len = 96 ,
. vsync_len = 6 ,
. vmode = FB_VMODE_NONINTERLACED
}
} , {
/*
* Modeline from XF86Config :
* Mode " 1024x768 " 80 1024 1136 1340 1432 768 770 774 805
*/
/* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
. name = " 1024x768 " ,
. var = {
. xres = 1024 ,
. yres = 768 ,
. xres_virtual = 1024 ,
. yres_virtual = 768 ,
. bits_per_pixel = 8 ,
. red = { . length = 8 } ,
. green = { . length = 8 } ,
. blue = { . length = 8 } ,
. width = - 1 ,
. height = - 1 ,
. pixclock = 12500 ,
. left_margin = 144 ,
. right_margin = 32 ,
. upper_margin = 30 ,
. lower_margin = 2 ,
. hsync_len = 192 ,
. vsync_len = 6 ,
. vmode = FB_VMODE_NONINTERLACED
}
}
} ;
# define NUM_TOTAL_MODES ARRAY_SIZE(cirrusfb_predefined)
/****************************************************************************/
/**** BEGIN PROTOTYPES ******************************************************/
/*--- Interface used by the world ------------------------------------------*/
2007-10-16 12:29:08 +04:00
static int cirrusfb_init ( void ) ;
2005-04-17 02:20:36 +04:00
# ifndef MODULE
2007-10-16 12:29:08 +04:00
static int cirrusfb_setup ( char * options ) ;
2005-04-17 02:20:36 +04:00
# endif
2007-10-16 12:29:08 +04:00
static int cirrusfb_open ( struct fb_info * info , int user ) ;
static int cirrusfb_release ( struct fb_info * info , int user ) ;
static int cirrusfb_setcolreg ( unsigned regno , unsigned red , unsigned green ,
unsigned blue , unsigned transp ,
struct fb_info * info ) ;
static int cirrusfb_check_var ( struct fb_var_screeninfo * var ,
struct fb_info * info ) ;
static int cirrusfb_set_par ( struct fb_info * info ) ;
static int cirrusfb_pan_display ( struct fb_var_screeninfo * var ,
struct fb_info * info ) ;
static int cirrusfb_blank ( int blank_mode , struct fb_info * info ) ;
static void cirrusfb_fillrect ( struct fb_info * info ,
const struct fb_fillrect * region ) ;
static void cirrusfb_copyarea ( struct fb_info * info ,
const struct fb_copyarea * area ) ;
static void cirrusfb_imageblit ( struct fb_info * info ,
const struct fb_image * image ) ;
2005-04-17 02:20:36 +04:00
/* function table of the above functions */
static struct fb_ops cirrusfb_ops = {
. owner = THIS_MODULE ,
. fb_open = cirrusfb_open ,
. fb_release = cirrusfb_release ,
. fb_setcolreg = cirrusfb_setcolreg ,
. fb_check_var = cirrusfb_check_var ,
. fb_set_par = cirrusfb_set_par ,
. fb_pan_display = cirrusfb_pan_display ,
. fb_blank = cirrusfb_blank ,
. fb_fillrect = cirrusfb_fillrect ,
. fb_copyarea = cirrusfb_copyarea ,
. fb_imageblit = cirrusfb_imageblit ,
} ;
/*--- Hardware Specific Routines -------------------------------------------*/
2007-10-16 12:29:08 +04:00
static int cirrusfb_decode_var ( const struct fb_var_screeninfo * var ,
2005-04-17 02:20:36 +04:00
struct cirrusfb_regs * regs ,
const struct fb_info * info ) ;
/*--- Internal routines ----------------------------------------------------*/
2007-10-16 12:29:12 +04:00
static void init_vgachip ( struct fb_info * info ) ;
2007-10-16 12:29:08 +04:00
static void switch_monitor ( struct cirrusfb_info * cinfo , int on ) ;
static void WGen ( const struct cirrusfb_info * cinfo ,
int regnum , unsigned char val ) ;
static unsigned char RGen ( const struct cirrusfb_info * cinfo , int regnum ) ;
static void AttrOn ( const struct cirrusfb_info * cinfo ) ;
static void WHDR ( const struct cirrusfb_info * cinfo , unsigned char val ) ;
static void WSFR ( struct cirrusfb_info * cinfo , unsigned char val ) ;
static void WSFR2 ( struct cirrusfb_info * cinfo , unsigned char val ) ;
static void WClut ( struct cirrusfb_info * cinfo , unsigned char regnum ,
unsigned char red , unsigned char green , unsigned char blue ) ;
2005-04-17 02:20:36 +04:00
#if 0
2007-10-16 12:29:08 +04:00
static void RClut ( struct cirrusfb_info * cinfo , unsigned char regnum ,
unsigned char * red , unsigned char * green ,
unsigned char * blue ) ;
2005-04-17 02:20:36 +04:00
# endif
2007-10-16 12:29:08 +04:00
static void cirrusfb_WaitBLT ( u8 __iomem * regbase ) ;
static void cirrusfb_BitBLT ( u8 __iomem * regbase , int bits_per_pixel ,
u_short curx , u_short cury ,
u_short destx , u_short desty ,
u_short width , u_short height ,
u_short line_length ) ;
static void cirrusfb_RectFill ( u8 __iomem * regbase , int bits_per_pixel ,
u_short x , u_short y ,
u_short width , u_short height ,
u_char color , u_short line_length ) ;
static void bestclock ( long freq , long * best ,
long * nom , long * den ,
long * div , long maxfreq ) ;
2005-04-17 02:20:36 +04:00
# ifdef CIRRUSFB_DEBUG
2007-10-16 12:29:08 +04:00
static void cirrusfb_dump ( void ) ;
static void cirrusfb_dbg_reg_dump ( caddr_t regbase ) ;
static void cirrusfb_dbg_print_regs ( caddr_t regbase ,
2007-10-16 12:29:11 +04:00
enum cirrusfb_dbg_reg_class reg_class , . . . ) ;
2007-10-16 12:29:08 +04:00
static void cirrusfb_dbg_print_byte ( const char * name , unsigned char val ) ;
2005-04-17 02:20:36 +04:00
# endif /* CIRRUSFB_DEBUG */
/*** END PROTOTYPES ********************************************************/
/*****************************************************************************/
/*** BEGIN Interface Used by the World ***************************************/
2007-10-16 12:29:08 +04:00
static int opencount ;
2005-04-17 02:20:36 +04:00
/*--- Open /dev/fbx ---------------------------------------------------------*/
2007-10-16 12:29:08 +04:00
static int cirrusfb_open ( struct fb_info * info , int user )
2005-04-17 02:20:36 +04:00
{
if ( opencount + + = = 0 )
2007-10-16 12:29:08 +04:00
switch_monitor ( info - > par , 1 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*--- Close /dev/fbx --------------------------------------------------------*/
2007-10-16 12:29:08 +04:00
static int cirrusfb_release ( struct fb_info * info , int user )
2005-04-17 02:20:36 +04:00
{
if ( - - opencount = = 0 )
2007-10-16 12:29:08 +04:00
switch_monitor ( info - > par , 0 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/**** END Interface used by the World *************************************/
/****************************************************************************/
/**** BEGIN Hardware specific Routines **************************************/
/* Get a good MCLK value */
2007-10-16 12:29:08 +04:00
static long cirrusfb_get_mclk ( long freq , int bpp , long * div )
2005-04-17 02:20:36 +04:00
{
long mclk ;
2007-10-16 12:29:08 +04:00
assert ( div ! = NULL ) ;
2005-04-17 02:20:36 +04:00
/* Calculate MCLK, in case VCLK is high enough to require > 50MHz.
* Assume a 64 - bit data path for now . The formula is :
* ( ( B * PCLK * 2 ) / W ) * 1.2
* B = bytes per pixel , PCLK = pixclock , W = data width in bytes */
mclk = ( ( bpp / 8 ) * freq * 2 ) / 4 ;
mclk = ( mclk * 12 ) / 10 ;
if ( mclk < 50000 )
mclk = 50000 ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " Use MCLK of %ld kHz \n " , mclk ) ;
2005-04-17 02:20:36 +04:00
/* Calculate value for SR1F. Multiply by 2 so we can round up. */
mclk = ( ( mclk * 16 ) / 14318 ) ;
mclk = ( mclk + 1 ) / 2 ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " Set SR1F[5:0] to 0x%lx \n " , mclk ) ;
2005-04-17 02:20:36 +04:00
/* Determine if we should use MCLK instead of VCLK, and if so, what we
* should divide it by to get VCLK */
switch ( freq ) {
case 24751 . . . 25249 :
* div = 2 ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " Using VCLK = MCLK/2 \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
case 49501 . . . 50499 :
* div = 1 ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " Using VCLK = MCLK \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
* div = 0 ;
break ;
}
return mclk ;
}
static int cirrusfb_check_var ( struct fb_var_screeninfo * var ,
struct fb_info * info )
{
int nom , den ; /* translyting from pixels->bytes */
int yres , i ;
static struct { int xres , yres ; } modes [ ] =
{ { 1600 , 1280 } ,
{ 1280 , 1024 } ,
{ 1024 , 768 } ,
{ 800 , 600 } ,
{ 640 , 480 } ,
{ - 1 , - 1 } } ;
switch ( var - > bits_per_pixel ) {
2007-10-16 12:29:13 +04:00
case 1 :
2005-04-17 02:20:36 +04:00
nom = 4 ;
den = 8 ;
break ; /* 8 pixel per byte, only 1/4th of mem usable */
2007-10-16 12:29:13 +04:00
case 8 :
case 16 :
case 24 :
case 32 :
nom = var - > bits_per_pixel / 8 ;
2005-04-17 02:20:36 +04:00
den = 1 ;
break ; /* 1 pixel == 1 byte */
default :
2007-10-16 12:29:08 +04:00
printk ( KERN_ERR " cirrusfb: mode %dx%dx%d rejected... "
" color depth not supported. \n " ,
2005-04-17 02:20:36 +04:00
var - > xres , var - > yres , var - > bits_per_pixel ) ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT - EINVAL error \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2007-10-16 12:29:12 +04:00
if ( var - > xres * nom / den * var - > yres > info - > screen_size ) {
2007-10-16 12:29:08 +04:00
printk ( KERN_ERR " cirrusfb: mode %dx%dx%d rejected... "
" resolution too high to fit into video memory! \n " ,
2005-04-17 02:20:36 +04:00
var - > xres , var - > yres , var - > bits_per_pixel ) ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT - EINVAL error \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
/* use highest possible virtual resolution */
if ( var - > xres_virtual = = - 1 & &
var - > yres_virtual = = - 1 ) {
2007-10-16 12:29:08 +04:00
printk ( KERN_INFO
" cirrusfb: using maximum available virtual resolution \n " ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; modes [ i ] . xres ! = - 1 ; i + + ) {
2007-10-16 12:29:12 +04:00
int size = modes [ i ] . xres * nom / den * modes [ i ] . yres ;
if ( size < info - > screen_size / 2 )
2005-04-17 02:20:36 +04:00
break ;
}
if ( modes [ i ] . xres = = - 1 ) {
2007-10-16 12:29:08 +04:00
printk ( KERN_ERR " cirrusfb: could not find a virtual "
" resolution that fits into video memory!! \n " ) ;
DPRINTK ( " EXIT - EINVAL error \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
var - > xres_virtual = modes [ i ] . xres ;
var - > yres_virtual = modes [ i ] . yres ;
2007-10-16 12:29:08 +04:00
printk ( KERN_INFO " cirrusfb: virtual resolution set to "
" maximum of %dx%d \n " , var - > xres_virtual ,
var - > yres_virtual ) ;
2005-04-17 02:20:36 +04:00
}
if ( var - > xres_virtual < var - > xres )
var - > xres_virtual = var - > xres ;
if ( var - > yres_virtual < var - > yres )
var - > yres_virtual = var - > yres ;
if ( var - > xoffset < 0 )
var - > xoffset = 0 ;
if ( var - > yoffset < 0 )
var - > yoffset = 0 ;
/* truncate xoffset and yoffset to maximum if too high */
if ( var - > xoffset > var - > xres_virtual - var - > xres )
var - > xoffset = var - > xres_virtual - var - > xres - 1 ;
if ( var - > yoffset > var - > yres_virtual - var - > yres )
var - > yoffset = var - > yres_virtual - var - > yres - 1 ;
switch ( var - > bits_per_pixel ) {
case 1 :
var - > red . offset = 0 ;
var - > red . length = 1 ;
2007-10-16 12:29:13 +04:00
var - > green = var - > red ;
var - > blue = var - > red ;
2005-04-17 02:20:36 +04:00
break ;
case 8 :
var - > red . offset = 0 ;
var - > red . length = 6 ;
2007-10-16 12:29:13 +04:00
var - > green = var - > red ;
var - > blue = var - > red ;
2005-04-17 02:20:36 +04:00
break ;
case 16 :
2007-10-16 12:29:08 +04:00
if ( isPReP ) {
2005-04-17 02:20:36 +04:00
var - > red . offset = 2 ;
var - > green . offset = - 3 ;
var - > blue . offset = 8 ;
} else {
var - > red . offset = 10 ;
var - > green . offset = 5 ;
var - > blue . offset = 0 ;
}
var - > red . length = 5 ;
var - > green . length = 5 ;
var - > blue . length = 5 ;
break ;
case 24 :
case 32 :
2007-10-16 12:29:08 +04:00
if ( isPReP ) {
2005-04-17 02:20:36 +04:00
var - > red . offset = 8 ;
var - > green . offset = 16 ;
var - > blue . offset = 24 ;
} else {
var - > red . offset = 16 ;
var - > green . offset = 8 ;
var - > blue . offset = 0 ;
}
var - > red . length = 8 ;
var - > green . length = 8 ;
var - > blue . length = 8 ;
break ;
default :
DPRINTK ( " Unsupported bpp size: %d \n " , var - > bits_per_pixel ) ;
2007-05-08 11:38:29 +04:00
assert ( false ) ;
2005-04-17 02:20:36 +04:00
/* should never occur */
break ;
}
var - > red . msb_right =
var - > green . msb_right =
var - > blue . msb_right =
var - > transp . offset =
var - > transp . length =
var - > transp . msb_right = 0 ;
yres = var - > yres ;
if ( var - > vmode & FB_VMODE_DOUBLE )
yres * = 2 ;
else if ( var - > vmode & FB_VMODE_INTERLACED )
yres = ( yres + 1 ) / 2 ;
if ( yres > = 1280 ) {
2007-10-16 12:29:08 +04:00
printk ( KERN_ERR " cirrusfb: ERROR: VerticalTotal >= 1280; "
" special treatment required! (TODO) \n " ) ;
DPRINTK ( " EXIT - EINVAL error \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
return 0 ;
}
2007-10-16 12:29:08 +04:00
static int cirrusfb_decode_var ( const struct fb_var_screeninfo * var ,
2005-04-17 02:20:36 +04:00
struct cirrusfb_regs * regs ,
const struct fb_info * info )
{
long freq ;
long maxclock ;
2007-10-16 12:29:13 +04:00
int maxclockidx = var - > bits_per_pixel > > 3 ;
2005-04-17 02:20:36 +04:00
struct cirrusfb_info * cinfo = info - > par ;
int xres , hfront , hsync , hback ;
int yres , vfront , vsync , vback ;
2007-10-16 12:29:08 +04:00
switch ( var - > bits_per_pixel ) {
2005-04-17 02:20:36 +04:00
case 1 :
regs - > line_length = var - > xres_virtual / 8 ;
regs - > visual = FB_VISUAL_MONO10 ;
break ;
case 8 :
regs - > line_length = var - > xres_virtual ;
regs - > visual = FB_VISUAL_PSEUDOCOLOR ;
break ;
case 16 :
case 24 :
case 32 :
2007-10-16 12:29:13 +04:00
regs - > line_length = var - > xres_virtual * maxclockidx ;
2005-04-17 02:20:36 +04:00
regs - > visual = FB_VISUAL_DIRECTCOLOR ;
break ;
default :
DPRINTK ( " Unsupported bpp size: %d \n " , var - > bits_per_pixel ) ;
2007-05-08 11:38:29 +04:00
assert ( false ) ;
2005-04-17 02:20:36 +04:00
/* should never occur */
break ;
}
regs - > type = FB_TYPE_PACKED_PIXELS ;
/* convert from ps to kHz */
2007-10-16 12:29:13 +04:00
freq = PICOS2KHZ ( var - > pixclock ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " desired pixclock: %ld kHz \n " , freq ) ;
2005-04-17 02:20:36 +04:00
maxclock = cirrusfb_board_info [ cinfo - > btype ] . maxclock [ maxclockidx ] ;
regs - > multiplexing = 0 ;
/* If the frequency is greater than we can support, we might be able
* to use multiplexing for the video mode */
if ( freq > maxclock ) {
switch ( cinfo - > btype ) {
case BT_ALPINE :
case BT_GD5480 :
regs - > multiplexing = 1 ;
break ;
default :
2007-10-16 12:29:08 +04:00
printk ( KERN_ERR " cirrusfb: Frequency greater "
" than maxclock (%ld kHz) \n " , maxclock ) ;
DPRINTK ( " EXIT - return -EINVAL \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
}
#if 0
/* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where
* the VCLK is double the pixel clock . */
switch ( var - > bits_per_pixel ) {
case 16 :
case 32 :
if ( regs - > HorizRes < = 800 )
2007-10-16 12:29:08 +04:00
/* Xbh has this type of clock for 32-bit */
freq / = 2 ;
2005-04-17 02:20:36 +04:00
break ;
}
# endif
2007-10-16 12:29:08 +04:00
bestclock ( freq , & regs - > freq , & regs - > nom , & regs - > den , & regs - > div ,
maxclock ) ;
regs - > mclk = cirrusfb_get_mclk ( freq , var - > bits_per_pixel ,
& regs - > divMCLK ) ;
2005-04-17 02:20:36 +04:00
xres = var - > xres ;
hfront = var - > right_margin ;
hsync = var - > hsync_len ;
hback = var - > left_margin ;
yres = var - > yres ;
vfront = var - > lower_margin ;
vsync = var - > vsync_len ;
vback = var - > upper_margin ;
if ( var - > vmode & FB_VMODE_DOUBLE ) {
yres * = 2 ;
vfront * = 2 ;
vsync * = 2 ;
vback * = 2 ;
} else if ( var - > vmode & FB_VMODE_INTERLACED ) {
yres = ( yres + 1 ) / 2 ;
vfront = ( vfront + 1 ) / 2 ;
vsync = ( vsync + 1 ) / 2 ;
vback = ( vback + 1 ) / 2 ;
}
regs - > HorizRes = xres ;
regs - > HorizTotal = ( xres + hfront + hsync + hback ) / 8 - 5 ;
regs - > HorizDispEnd = xres / 8 - 1 ;
regs - > HorizBlankStart = xres / 8 ;
2007-10-16 12:29:08 +04:00
/* does not count with "-5" */
regs - > HorizBlankEnd = regs - > HorizTotal + 5 ;
2005-04-17 02:20:36 +04:00
regs - > HorizSyncStart = ( xres + hfront ) / 8 + 1 ;
regs - > HorizSyncEnd = ( xres + hfront + hsync ) / 8 + 1 ;
regs - > VertRes = yres ;
regs - > VertTotal = yres + vfront + vsync + vback - 2 ;
regs - > VertDispEnd = yres - 1 ;
regs - > VertBlankStart = yres ;
regs - > VertBlankEnd = regs - > VertTotal ;
regs - > VertSyncStart = yres + vfront - 1 ;
regs - > VertSyncEnd = yres + vfront + vsync - 1 ;
if ( regs - > VertRes > = 1024 ) {
regs - > VertTotal / = 2 ;
regs - > VertSyncStart / = 2 ;
regs - > VertSyncEnd / = 2 ;
regs - > VertDispEnd / = 2 ;
}
if ( regs - > multiplexing ) {
regs - > HorizTotal / = 2 ;
regs - > HorizSyncStart / = 2 ;
regs - > HorizSyncEnd / = 2 ;
regs - > HorizDispEnd / = 2 ;
}
return 0 ;
}
2007-10-16 12:29:08 +04:00
static void cirrusfb_set_mclk ( const struct cirrusfb_info * cinfo , int val ,
int div )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:29:08 +04:00
assert ( cinfo ! = NULL ) ;
2005-04-17 02:20:36 +04:00
if ( div = = 2 ) {
/* VCLK = MCLK/2 */
2007-10-16 12:29:08 +04:00
unsigned char old = vga_rseq ( cinfo - > regbase , CL_SEQR1E ) ;
vga_wseq ( cinfo - > regbase , CL_SEQR1E , old | 0x1 ) ;
vga_wseq ( cinfo - > regbase , CL_SEQR1F , 0x40 | ( val & 0x3f ) ) ;
2005-04-17 02:20:36 +04:00
} else if ( div = = 1 ) {
/* VCLK = MCLK */
2007-10-16 12:29:08 +04:00
unsigned char old = vga_rseq ( cinfo - > regbase , CL_SEQR1E ) ;
vga_wseq ( cinfo - > regbase , CL_SEQR1E , old & ~ 0x1 ) ;
vga_wseq ( cinfo - > regbase , CL_SEQR1F , 0x40 | ( val & 0x3f ) ) ;
2005-04-17 02:20:36 +04:00
} else {
2007-10-16 12:29:08 +04:00
vga_wseq ( cinfo - > regbase , CL_SEQR1F , val & 0x3f ) ;
2005-04-17 02:20:36 +04:00
}
}
/*************************************************************************
cirrusfb_set_par_foo ( )
actually writes the values for a new video mode into the hardware ,
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-16 12:29:08 +04:00
static int cirrusfb_set_par_foo ( struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
struct cirrusfb_info * cinfo = info - > par ;
struct fb_var_screeninfo * var = & info - > var ;
struct cirrusfb_regs regs ;
u8 __iomem * regbase = cinfo - > regbase ;
unsigned char tmp ;
int offset = 0 , err ;
const struct cirrusfb_board_info_rec * bi ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
DPRINTK ( " Requested mode: %dx%dx%d \n " ,
2005-04-17 02:20:36 +04:00
var - > xres , var - > yres , var - > bits_per_pixel ) ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " pixclock: %d \n " , var - > pixclock ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:12 +04:00
init_vgachip ( info ) ;
2005-04-17 02:20:36 +04:00
err = cirrusfb_decode_var ( var , & regs , info ) ;
2007-10-16 12:29:08 +04:00
if ( err ) {
2005-04-17 02:20:36 +04:00
/* should never happen */
DPRINTK ( " mode change aborted. invalid var. \n " ) ;
return - EINVAL ;
}
bi = & cirrusfb_board_info [ cinfo - > btype ] ;
/* unlock register VGA_CRTC_H_TOTAL..CRT7 */
2007-10-16 12:29:08 +04:00
vga_wcrt ( regbase , VGA_CRTC_V_SYNC_END , 0x20 ) ; /* previously: 0x00) */
2005-04-17 02:20:36 +04:00
/* if debugging is enabled, all parameters get output before writing */
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT0: %ld \n " , regs . HorizTotal ) ;
vga_wcrt ( regbase , VGA_CRTC_H_TOTAL , regs . HorizTotal ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT1: %ld \n " , regs . HorizDispEnd ) ;
vga_wcrt ( regbase , VGA_CRTC_H_DISP , regs . HorizDispEnd ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT2: %ld \n " , regs . HorizBlankStart ) ;
vga_wcrt ( regbase , VGA_CRTC_H_BLANK_START , regs . HorizBlankStart ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
/* + 128: Compatible read */
DPRINTK ( " CRT3: 128+%ld \n " , regs . HorizBlankEnd % 32 ) ;
vga_wcrt ( regbase , VGA_CRTC_H_BLANK_END ,
128 + ( regs . HorizBlankEnd % 32 ) ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT4: %ld \n " , regs . HorizSyncStart ) ;
vga_wcrt ( regbase , VGA_CRTC_H_SYNC_START , regs . HorizSyncStart ) ;
2005-04-17 02:20:36 +04:00
tmp = regs . HorizSyncEnd % 32 ;
if ( regs . HorizBlankEnd & 32 )
tmp + = 128 ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT5: %d \n " , tmp ) ;
vga_wcrt ( regbase , VGA_CRTC_H_SYNC_END , tmp ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT6: %ld \n " , regs . VertTotal & 0xff ) ;
vga_wcrt ( regbase , VGA_CRTC_V_TOTAL , ( regs . VertTotal & 0xff ) ) ;
2005-04-17 02:20:36 +04:00
tmp = 16 ; /* LineCompare bit #9 */
if ( regs . VertTotal & 256 )
tmp | = 1 ;
if ( regs . VertDispEnd & 256 )
tmp | = 2 ;
if ( regs . VertSyncStart & 256 )
tmp | = 4 ;
if ( regs . VertBlankStart & 256 )
tmp | = 8 ;
if ( regs . VertTotal & 512 )
tmp | = 32 ;
if ( regs . VertDispEnd & 512 )
tmp | = 64 ;
if ( regs . VertSyncStart & 512 )
tmp | = 128 ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT7: %d \n " , tmp ) ;
vga_wcrt ( regbase , VGA_CRTC_OVERFLOW , tmp ) ;
2005-04-17 02:20:36 +04:00
tmp = 0x40 ; /* LineCompare bit #8 */
if ( regs . VertBlankStart & 512 )
tmp | = 0x20 ;
if ( var - > vmode & FB_VMODE_DOUBLE )
tmp | = 0x80 ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT9: %d \n " , tmp ) ;
vga_wcrt ( regbase , VGA_CRTC_MAX_SCAN , tmp ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT10: %ld \n " , regs . VertSyncStart & 0xff ) ;
vga_wcrt ( regbase , VGA_CRTC_V_SYNC_START , regs . VertSyncStart & 0xff ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT11: 64+32+%ld \n " , regs . VertSyncEnd % 16 ) ;
vga_wcrt ( regbase , VGA_CRTC_V_SYNC_END , regs . VertSyncEnd % 16 + 64 + 32 ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT12: %ld \n " , regs . VertDispEnd & 0xff ) ;
vga_wcrt ( regbase , VGA_CRTC_V_DISP_END , regs . VertDispEnd & 0xff ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT15: %ld \n " , regs . VertBlankStart & 0xff ) ;
vga_wcrt ( regbase , VGA_CRTC_V_BLANK_START , regs . VertBlankStart & 0xff ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT16: %ld \n " , regs . VertBlankEnd & 0xff ) ;
vga_wcrt ( regbase , VGA_CRTC_V_BLANK_END , regs . VertBlankEnd & 0xff ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT18: 0xff \n " ) ;
vga_wcrt ( regbase , VGA_CRTC_LINE_COMPARE , 0xff ) ;
2005-04-17 02:20:36 +04:00
tmp = 0 ;
if ( var - > vmode & FB_VMODE_INTERLACED )
tmp | = 1 ;
if ( regs . HorizBlankEnd & 64 )
tmp | = 16 ;
if ( regs . HorizBlankEnd & 128 )
tmp | = 32 ;
if ( regs . VertBlankEnd & 256 )
tmp | = 64 ;
if ( regs . VertBlankEnd & 512 )
tmp | = 128 ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " CRT1a: %d \n " , tmp ) ;
vga_wcrt ( regbase , CL_CRT1A , tmp ) ;
2005-04-17 02:20:36 +04:00
/* set VCLK0 */
/* hardware RefClock: 14.31818 MHz */
/* formula: VClk = (OSC * N) / (D * (1+P)) */
/* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
2007-10-16 12:29:08 +04:00
vga_wseq ( regbase , CL_SEQRB , regs . nom ) ;
2005-04-17 02:20:36 +04:00
tmp = regs . den < < 1 ;
if ( regs . div ! = 0 )
tmp | = 1 ;
2007-10-16 12:29:08 +04:00
/* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
2005-04-17 02:20:36 +04:00
if ( ( cinfo - > btype = = BT_SD64 ) | |
( cinfo - > btype = = BT_ALPINE ) | |
( cinfo - > btype = = BT_GD5480 ) )
2007-10-16 12:29:08 +04:00
tmp | = 0x80 ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " CL_SEQR1B: %ld \n " , ( long ) tmp ) ;
vga_wseq ( regbase , CL_SEQR1B , tmp ) ;
2005-04-17 02:20:36 +04:00
if ( regs . VertRes > = 1024 )
/* 1280x1024 */
2007-10-16 12:29:08 +04:00
vga_wcrt ( regbase , VGA_CRTC_MODE , 0xc7 ) ;
2005-04-17 02:20:36 +04:00
else
/* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
* address wrap , no compat . */
2007-10-16 12:29:08 +04:00
vga_wcrt ( regbase , VGA_CRTC_MODE , 0xc3 ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
/* HAEH? vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);
* previously : 0x00 unlock VGA_CRTC_H_TOTAL . . CRT7 */
2005-04-17 02:20:36 +04:00
/* don't know if it would hurt to also program this if no interlaced */
/* mode is used, but I feel better this way.. :-) */
if ( var - > vmode & FB_VMODE_INTERLACED )
2007-10-16 12:29:08 +04:00
vga_wcrt ( regbase , VGA_CRTC_REGS , regs . HorizTotal / 2 ) ;
2005-04-17 02:20:36 +04:00
else
2007-10-16 12:29:08 +04:00
vga_wcrt ( regbase , VGA_CRTC_REGS , 0x00 ) ; /* interlace control */
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
vga_wseq ( regbase , VGA_SEQ_CHARACTER_MAP , 0 ) ;
2005-04-17 02:20:36 +04:00
/* adjust horizontal/vertical sync type (low/high) */
2007-10-16 12:29:08 +04:00
/* enable display memory & CRTC I/O address for color mode */
tmp = 0x03 ;
2005-04-17 02:20:36 +04:00
if ( var - > sync & FB_SYNC_HOR_HIGH_ACT )
tmp | = 0x40 ;
if ( var - > sync & FB_SYNC_VERT_HIGH_ACT )
tmp | = 0x80 ;
2007-10-16 12:29:08 +04:00
WGen ( cinfo , VGA_MIS_W , tmp ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
/* Screen A Preset Row-Scan register */
vga_wcrt ( regbase , VGA_CRTC_PRESET_ROW , 0 ) ;
/* text cursor on and start line */
vga_wcrt ( regbase , VGA_CRTC_CURSOR_START , 0 ) ;
/* text cursor end line */
vga_wcrt ( regbase , VGA_CRTC_CURSOR_END , 31 ) ;
2005-04-17 02:20:36 +04:00
/******************************************************
*
* 1 bpp
*
*/
/* programming for different color depths */
if ( var - > bits_per_pixel = = 1 ) {
2007-10-16 12:29:08 +04:00
DPRINTK ( " cirrusfb: preparing for 1 bit deep display \n " ) ;
vga_wgfx ( regbase , VGA_GFX_MODE , 0 ) ; /* mode register */
2005-04-17 02:20:36 +04:00
/* SR07 */
switch ( cinfo - > btype ) {
case BT_SD64 :
case BT_PICCOLO :
case BT_PICASSO :
case BT_SPECTRUM :
case BT_PICASSO4 :
case BT_ALPINE :
case BT_GD5480 :
2007-10-16 12:29:08 +04:00
DPRINTK ( " (for GD54xx) \n " ) ;
vga_wseq ( regbase , CL_SEQR7 ,
2005-04-17 02:20:36 +04:00
regs . multiplexing ?
bi - > sr07_1bpp_mux : bi - > sr07_1bpp ) ;
break ;
case BT_LAGUNA :
2007-10-16 12:29:08 +04:00
DPRINTK ( " (for GD546x) \n " ) ;
vga_wseq ( regbase , CL_SEQR7 ,
vga_rseq ( regbase , CL_SEQR7 ) & ~ 0x01 ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2007-10-16 12:29:08 +04:00
printk ( KERN_WARNING " cirrusfb: unknown Board \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
}
/* Extended Sequencer Mode */
switch ( cinfo - > btype ) {
case BT_SD64 :
2007-10-16 12:29:08 +04:00
/* setting the SEQRF on SD64 is not necessary
* ( only during init )
*/
DPRINTK ( " (for SD64) \n " ) ;
/* MCLK select */
vga_wseq ( regbase , CL_SEQR1F , 0x1a ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICCOLO :
2007-10-16 12:29:13 +04:00
case BT_SPECTRUM :
DPRINTK ( " (for Piccolo/Spectrum) \n " ) ;
2007-10-16 12:29:08 +04:00
/* ### ueberall 0x22? */
/* ##vorher 1c MCLK select */
vga_wseq ( regbase , CL_SEQR1F , 0x22 ) ;
/* evtl d0 bei 1 bit? avoid FIFO underruns..? */
vga_wseq ( regbase , CL_SEQRF , 0xb0 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICASSO :
2007-10-16 12:29:08 +04:00
DPRINTK ( " (for Picasso) \n " ) ;
/* ##vorher 22 MCLK select */
vga_wseq ( regbase , CL_SEQR1F , 0x22 ) ;
/* ## vorher d0 avoid FIFO underruns..? */
vga_wseq ( regbase , CL_SEQRF , 0xd0 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICASSO4 :
case BT_ALPINE :
case BT_GD5480 :
case BT_LAGUNA :
2007-10-16 12:29:08 +04:00
DPRINTK ( " (for GD54xx) \n " ) ;
2005-04-17 02:20:36 +04:00
/* do nothing */
break ;
default :
2007-10-16 12:29:08 +04:00
printk ( KERN_WARNING " cirrusfb: unknown Board \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2007-10-16 12:29:08 +04:00
/* pixel mask: pass-through for first plane */
WGen ( cinfo , VGA_PEL_MSK , 0x01 ) ;
2005-04-17 02:20:36 +04:00
if ( regs . multiplexing )
2007-10-16 12:29:08 +04:00
/* hidden dac reg: 1280x1024 */
WHDR ( cinfo , 0x4a ) ;
2005-04-17 02:20:36 +04:00
else
2007-10-16 12:29:08 +04:00
/* hidden dac: nothing */
WHDR ( cinfo , 0 ) ;
/* memory mode: odd/even, ext. memory */
vga_wseq ( regbase , VGA_SEQ_MEMORY_MODE , 0x06 ) ;
/* plane mask: only write to first plane */
vga_wseq ( regbase , VGA_SEQ_PLANE_WRITE , 0x01 ) ;
2005-04-17 02:20:36 +04:00
offset = var - > xres_virtual / 16 ;
}
/******************************************************
*
* 8 bpp
*
*/
else if ( var - > bits_per_pixel = = 8 ) {
2007-10-16 12:29:08 +04:00
DPRINTK ( " cirrusfb: preparing for 8 bit deep display \n " ) ;
2005-04-17 02:20:36 +04:00
switch ( cinfo - > btype ) {
case BT_SD64 :
case BT_PICCOLO :
case BT_PICASSO :
case BT_SPECTRUM :
case BT_PICASSO4 :
case BT_ALPINE :
case BT_GD5480 :
2007-10-16 12:29:08 +04:00
DPRINTK ( " (for GD54xx) \n " ) ;
vga_wseq ( regbase , CL_SEQR7 ,
2005-04-17 02:20:36 +04:00
regs . multiplexing ?
bi - > sr07_8bpp_mux : bi - > sr07_8bpp ) ;
break ;
case BT_LAGUNA :
2007-10-16 12:29:08 +04:00
DPRINTK ( " (for GD546x) \n " ) ;
vga_wseq ( regbase , CL_SEQR7 ,
vga_rseq ( regbase , CL_SEQR7 ) | 0x01 ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2007-10-16 12:29:08 +04:00
printk ( KERN_WARNING " cirrusfb: unknown Board \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
}
switch ( cinfo - > btype ) {
case BT_SD64 :
2007-10-16 12:29:08 +04:00
/* MCLK select */
vga_wseq ( regbase , CL_SEQR1F , 0x1d ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICCOLO :
case BT_PICASSO :
case BT_SPECTRUM :
2007-10-16 12:29:08 +04:00
/* ### vorher 1c MCLK select */
vga_wseq ( regbase , CL_SEQR1F , 0x22 ) ;
/* Fast Page-Mode writes */
vga_wseq ( regbase , CL_SEQRF , 0xb0 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICASSO4 :
# ifdef CONFIG_ZORRO
2007-10-16 12:29:08 +04:00
/* ### INCOMPLETE!! */
vga_wseq ( regbase , CL_SEQRF , 0xb8 ) ;
2005-04-17 02:20:36 +04:00
# endif
2007-10-16 12:29:08 +04:00
/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */
2005-04-17 02:20:36 +04:00
break ;
case BT_ALPINE :
2007-10-16 12:29:08 +04:00
DPRINTK ( " (for GD543x) \n " ) ;
cirrusfb_set_mclk ( cinfo , regs . mclk , regs . divMCLK ) ;
2005-04-17 02:20:36 +04:00
/* We already set SRF and SR1F */
break ;
case BT_GD5480 :
case BT_LAGUNA :
2007-10-16 12:29:08 +04:00
DPRINTK ( " (for GD54xx) \n " ) ;
2005-04-17 02:20:36 +04:00
/* do nothing */
break ;
default :
2007-10-16 12:29:08 +04:00
printk ( KERN_WARNING " cirrusfb: unknown Board \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2007-10-16 12:29:08 +04:00
/* mode register: 256 color mode */
vga_wgfx ( regbase , VGA_GFX_MODE , 64 ) ;
/* pixel mask: pass-through all planes */
WGen ( cinfo , VGA_PEL_MSK , 0xff ) ;
2005-04-17 02:20:36 +04:00
if ( regs . multiplexing )
2007-10-16 12:29:08 +04:00
/* hidden dac reg: 1280x1024 */
WHDR ( cinfo , 0x4a ) ;
2005-04-17 02:20:36 +04:00
else
2007-10-16 12:29:08 +04:00
/* hidden dac: nothing */
WHDR ( cinfo , 0 ) ;
/* memory mode: chain4, ext. memory */
vga_wseq ( regbase , VGA_SEQ_MEMORY_MODE , 0x0a ) ;
/* plane mask: enable writing to all 4 planes */
vga_wseq ( regbase , VGA_SEQ_PLANE_WRITE , 0xff ) ;
2005-04-17 02:20:36 +04:00
offset = var - > xres_virtual / 8 ;
}
/******************************************************
*
* 16 bpp
*
*/
else if ( var - > bits_per_pixel = = 16 ) {
2007-10-16 12:29:08 +04:00
DPRINTK ( " cirrusfb: preparing for 16 bit deep display \n " ) ;
2005-04-17 02:20:36 +04:00
switch ( cinfo - > btype ) {
case BT_SD64 :
2007-10-16 12:29:08 +04:00
/* Extended Sequencer Mode: 256c col. mode */
vga_wseq ( regbase , CL_SEQR7 , 0xf7 ) ;
/* MCLK select */
vga_wseq ( regbase , CL_SEQR1F , 0x1e ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICCOLO :
2007-10-16 12:29:13 +04:00
case BT_SPECTRUM :
2007-10-16 12:29:08 +04:00
vga_wseq ( regbase , CL_SEQR7 , 0x87 ) ;
/* Fast Page-Mode writes */
vga_wseq ( regbase , CL_SEQRF , 0xb0 ) ;
/* MCLK select */
vga_wseq ( regbase , CL_SEQR1F , 0x22 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICASSO :
2007-10-16 12:29:08 +04:00
vga_wseq ( regbase , CL_SEQR7 , 0x27 ) ;
/* Fast Page-Mode writes */
vga_wseq ( regbase , CL_SEQRF , 0xb0 ) ;
/* MCLK select */
vga_wseq ( regbase , CL_SEQR1F , 0x22 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICASSO4 :
2007-10-16 12:29:08 +04:00
vga_wseq ( regbase , CL_SEQR7 , 0x27 ) ;
/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */
2005-04-17 02:20:36 +04:00
break ;
case BT_ALPINE :
2007-10-16 12:29:08 +04:00
DPRINTK ( " (for GD543x) \n " ) ;
2005-04-17 02:20:36 +04:00
if ( regs . HorizRes > = 1024 )
2007-10-16 12:29:08 +04:00
vga_wseq ( regbase , CL_SEQR7 , 0xa7 ) ;
2005-04-17 02:20:36 +04:00
else
2007-10-16 12:29:08 +04:00
vga_wseq ( regbase , CL_SEQR7 , 0xa3 ) ;
cirrusfb_set_mclk ( cinfo , regs . mclk , regs . divMCLK ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_GD5480 :
2007-10-16 12:29:08 +04:00
DPRINTK ( " (for GD5480) \n " ) ;
vga_wseq ( regbase , CL_SEQR7 , 0x17 ) ;
2005-04-17 02:20:36 +04:00
/* We already set SRF and SR1F */
break ;
case BT_LAGUNA :
2007-10-16 12:29:08 +04:00
DPRINTK ( " (for GD546x) \n " ) ;
vga_wseq ( regbase , CL_SEQR7 ,
vga_rseq ( regbase , CL_SEQR7 ) & ~ 0x01 ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2007-10-16 12:29:08 +04:00
printk ( KERN_WARNING " CIRRUSFB: unknown Board \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2007-10-16 12:29:08 +04:00
/* mode register: 256 color mode */
vga_wgfx ( regbase , VGA_GFX_MODE , 64 ) ;
/* pixel mask: pass-through all planes */
WGen ( cinfo , VGA_PEL_MSK , 0xff ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_PCI
2007-10-16 12:29:08 +04:00
WHDR ( cinfo , 0xc0 ) ; /* Copy Xbh */
2005-04-17 02:20:36 +04:00
# elif defined(CONFIG_ZORRO)
/* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
2007-10-16 12:29:08 +04:00
WHDR ( cinfo , 0xa0 ) ; /* hidden dac reg: nothing special */
2005-04-17 02:20:36 +04:00
# endif
2007-10-16 12:29:08 +04:00
/* memory mode: chain4, ext. memory */
vga_wseq ( regbase , VGA_SEQ_MEMORY_MODE , 0x0a ) ;
/* plane mask: enable writing to all 4 planes */
vga_wseq ( regbase , VGA_SEQ_PLANE_WRITE , 0xff ) ;
2005-04-17 02:20:36 +04:00
offset = var - > xres_virtual / 4 ;
}
/******************************************************
*
* 32 bpp
*
*/
else if ( var - > bits_per_pixel = = 32 ) {
2007-10-16 12:29:08 +04:00
DPRINTK ( " cirrusfb: preparing for 24/32 bit deep display \n " ) ;
2005-04-17 02:20:36 +04:00
switch ( cinfo - > btype ) {
case BT_SD64 :
2007-10-16 12:29:08 +04:00
/* Extended Sequencer Mode: 256c col. mode */
vga_wseq ( regbase , CL_SEQR7 , 0xf9 ) ;
/* MCLK select */
vga_wseq ( regbase , CL_SEQR1F , 0x1e ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICCOLO :
2007-10-16 12:29:13 +04:00
case BT_SPECTRUM :
2007-10-16 12:29:08 +04:00
vga_wseq ( regbase , CL_SEQR7 , 0x85 ) ;
/* Fast Page-Mode writes */
vga_wseq ( regbase , CL_SEQRF , 0xb0 ) ;
/* MCLK select */
vga_wseq ( regbase , CL_SEQR1F , 0x22 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICASSO :
2007-10-16 12:29:08 +04:00
vga_wseq ( regbase , CL_SEQR7 , 0x25 ) ;
/* Fast Page-Mode writes */
vga_wseq ( regbase , CL_SEQRF , 0xb0 ) ;
/* MCLK select */
vga_wseq ( regbase , CL_SEQR1F , 0x22 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICASSO4 :
2007-10-16 12:29:08 +04:00
vga_wseq ( regbase , CL_SEQR7 , 0x25 ) ;
/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */
2005-04-17 02:20:36 +04:00
break ;
case BT_ALPINE :
2007-10-16 12:29:08 +04:00
DPRINTK ( " (for GD543x) \n " ) ;
vga_wseq ( regbase , CL_SEQR7 , 0xa9 ) ;
cirrusfb_set_mclk ( cinfo , regs . mclk , regs . divMCLK ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_GD5480 :
2007-10-16 12:29:08 +04:00
DPRINTK ( " (for GD5480) \n " ) ;
vga_wseq ( regbase , CL_SEQR7 , 0x19 ) ;
2005-04-17 02:20:36 +04:00
/* We already set SRF and SR1F */
break ;
case BT_LAGUNA :
2007-10-16 12:29:08 +04:00
DPRINTK ( " (for GD546x) \n " ) ;
vga_wseq ( regbase , CL_SEQR7 ,
vga_rseq ( regbase , CL_SEQR7 ) & ~ 0x01 ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2007-10-16 12:29:08 +04:00
printk ( KERN_WARNING " cirrusfb: unknown Board \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2007-10-16 12:29:08 +04:00
/* mode register: 256 color mode */
vga_wgfx ( regbase , VGA_GFX_MODE , 64 ) ;
/* pixel mask: pass-through all planes */
WGen ( cinfo , VGA_PEL_MSK , 0xff ) ;
/* hidden dac reg: 8-8-8 mode (24 or 32) */
WHDR ( cinfo , 0xc5 ) ;
/* memory mode: chain4, ext. memory */
vga_wseq ( regbase , VGA_SEQ_MEMORY_MODE , 0x0a ) ;
/* plane mask: enable writing to all 4 planes */
vga_wseq ( regbase , VGA_SEQ_PLANE_WRITE , 0xff ) ;
2005-04-17 02:20:36 +04:00
offset = var - > xres_virtual / 4 ;
}
/******************************************************
*
* unknown / unsupported bpp
*
*/
2007-10-16 12:29:08 +04:00
else
printk ( KERN_ERR " cirrusfb: What's this?? "
" requested color depth == %d. \n " ,
2005-04-17 02:20:36 +04:00
var - > bits_per_pixel ) ;
2007-10-16 12:29:08 +04:00
vga_wcrt ( regbase , VGA_CRTC_OFFSET , offset & 0xff ) ;
2005-04-17 02:20:36 +04:00
tmp = 0x22 ;
if ( offset & 0x100 )
tmp | = 0x10 ; /* offset overflow bit */
2007-10-16 12:29:08 +04:00
/* screen start addr #16-18, fastpagemode cycles */
vga_wcrt ( regbase , CL_CRT1B , tmp ) ;
2005-04-17 02:20:36 +04:00
if ( cinfo - > btype = = BT_SD64 | |
cinfo - > btype = = BT_PICASSO4 | |
cinfo - > btype = = BT_ALPINE | |
cinfo - > btype = = BT_GD5480 )
2007-10-16 12:29:08 +04:00
/* screen start address bit 19 */
vga_wcrt ( regbase , CL_CRT1D , 0x00 ) ;
/* text cursor location high */
vga_wcrt ( regbase , VGA_CRTC_CURSOR_HI , 0 ) ;
/* text cursor location low */
vga_wcrt ( regbase , VGA_CRTC_CURSOR_LO , 0 ) ;
/* underline row scanline = at very bottom */
vga_wcrt ( regbase , VGA_CRTC_UNDERLINE , 0 ) ;
/* controller mode */
vga_wattr ( regbase , VGA_ATC_MODE , 1 ) ;
/* overscan (border) color */
vga_wattr ( regbase , VGA_ATC_OVERSCAN , 0 ) ;
/* color plane enable */
vga_wattr ( regbase , VGA_ATC_PLANE_ENABLE , 15 ) ;
/* pixel panning */
vga_wattr ( regbase , CL_AR33 , 0 ) ;
/* color select */
vga_wattr ( regbase , VGA_ATC_COLOR_PAGE , 0 ) ;
2005-04-17 02:20:36 +04:00
/* [ EGS: SetOffset(); ] */
/* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
2007-10-16 12:29:08 +04:00
AttrOn ( cinfo ) ;
/* set/reset register */
vga_wgfx ( regbase , VGA_GFX_SR_VALUE , 0 ) ;
/* set/reset enable */
vga_wgfx ( regbase , VGA_GFX_SR_ENABLE , 0 ) ;
/* color compare */
vga_wgfx ( regbase , VGA_GFX_COMPARE_VALUE , 0 ) ;
/* data rotate */
vga_wgfx ( regbase , VGA_GFX_DATA_ROTATE , 0 ) ;
/* read map select */
vga_wgfx ( regbase , VGA_GFX_PLANE_READ , 0 ) ;
/* miscellaneous register */
vga_wgfx ( regbase , VGA_GFX_MISC , 1 ) ;
/* color don't care */
vga_wgfx ( regbase , VGA_GFX_COMPARE_MASK , 15 ) ;
/* bit mask */
vga_wgfx ( regbase , VGA_GFX_BIT_MASK , 255 ) ;
/* graphics cursor attributes: nothing special */
vga_wseq ( regbase , CL_SEQR12 , 0x0 ) ;
2005-04-17 02:20:36 +04:00
/* finally, turn on everything - turn off "FullBandwidth" bit */
/* also, set "DotClock%2" bit where requested */
tmp = 0x01 ;
/*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
if ( var - > vmode & FB_VMODE_CLOCK_HALVE )
tmp | = 0x08 ;
*/
2007-10-16 12:29:08 +04:00
vga_wseq ( regbase , VGA_SEQ_CLOCK_MODE , tmp ) ;
DPRINTK ( " CL_SEQR1: %d \n " , tmp ) ;
2005-04-17 02:20:36 +04:00
cinfo - > currentmode = regs ;
info - > fix . type = regs . type ;
info - > fix . visual = regs . visual ;
info - > fix . line_length = regs . line_length ;
/* pan to requested offset */
2007-10-16 12:29:08 +04:00
cirrusfb_pan_display ( var , info ) ;
2005-04-17 02:20:36 +04:00
# ifdef CIRRUSFB_DEBUG
2007-10-16 12:29:08 +04:00
cirrusfb_dump ( ) ;
2005-04-17 02:20:36 +04:00
# endif
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* for some reason incomprehensible to me, cirrusfb requires that you write
* the registers twice for the settings to take . . grr . - dte */
2007-10-16 12:29:08 +04:00
static int cirrusfb_set_par ( struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:29:08 +04:00
cirrusfb_set_par_foo ( info ) ;
return cirrusfb_set_par_foo ( info ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:29:08 +04:00
static int cirrusfb_setcolreg ( unsigned regno , unsigned red , unsigned green ,
unsigned blue , unsigned transp ,
struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
struct cirrusfb_info * cinfo = info - > par ;
if ( regno > 255 )
return - EINVAL ;
if ( info - > fix . visual = = FB_VISUAL_TRUECOLOR ) {
u32 v ;
red > > = ( 16 - info - > var . red . length ) ;
green > > = ( 16 - info - > var . green . length ) ;
blue > > = ( 16 - info - > var . blue . length ) ;
2007-10-16 12:29:08 +04:00
if ( regno > = 16 )
2005-04-17 02:20:36 +04:00
return 1 ;
v = ( red < < info - > var . red . offset ) |
( green < < info - > var . green . offset ) |
( blue < < info - > var . blue . offset ) ;
2007-10-16 12:29:13 +04:00
cinfo - > pseudo_palette [ regno ] = v ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-10-16 12:29:08 +04:00
if ( info - > var . bits_per_pixel = = 8 )
WClut ( cinfo , regno , red > > 10 , green > > 10 , blue > > 10 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*************************************************************************
cirrusfb_pan_display ( )
performs display panning - provided hardware permits this
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-16 12:29:08 +04:00
static int cirrusfb_pan_display ( struct fb_var_screeninfo * var ,
struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
int xoffset = 0 ;
int yoffset = 0 ;
unsigned long base ;
unsigned char tmp = 0 , tmp2 = 0 , xpix ;
struct cirrusfb_info * cinfo = info - > par ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
DPRINTK ( " virtual offset: (%d,%d) \n " , var - > xoffset , var - > yoffset ) ;
2005-04-17 02:20:36 +04:00
/* no range checks for xoffset and yoffset, */
/* as fb_pan_display has already done this */
if ( var - > vmode & FB_VMODE_YWRAP )
return - EINVAL ;
info - > var . xoffset = var - > xoffset ;
info - > var . yoffset = var - > yoffset ;
xoffset = var - > xoffset * info - > var . bits_per_pixel / 8 ;
yoffset = var - > yoffset ;
base = yoffset * cinfo - > currentmode . line_length + xoffset ;
if ( info - > var . bits_per_pixel = = 1 ) {
/* base is already correct */
xpix = ( unsigned char ) ( var - > xoffset % 8 ) ;
} else {
base / = 4 ;
xpix = ( unsigned char ) ( ( xoffset % 4 ) * 2 ) ;
}
2007-10-16 12:29:08 +04:00
cirrusfb_WaitBLT ( cinfo - > regbase ) ; /* make sure all the BLT's are done */
2005-04-17 02:20:36 +04:00
/* lower 8 + 8 bits of screen start address */
2007-10-16 12:29:08 +04:00
vga_wcrt ( cinfo - > regbase , VGA_CRTC_START_LO ,
( unsigned char ) ( base & 0xff ) ) ;
vga_wcrt ( cinfo - > regbase , VGA_CRTC_START_HI ,
( unsigned char ) ( base > > 8 ) ) ;
2005-04-17 02:20:36 +04:00
/* construct bits 16, 17 and 18 of screen start address */
if ( base & 0x10000 )
tmp | = 0x01 ;
if ( base & 0x20000 )
tmp | = 0x04 ;
if ( base & 0x40000 )
tmp | = 0x08 ;
2007-10-16 12:29:08 +04:00
/* 0xf2 is %11110010, exclude tmp bits */
tmp2 = ( vga_rcrt ( cinfo - > regbase , CL_CRT1B ) & 0xf2 ) | tmp ;
vga_wcrt ( cinfo - > regbase , CL_CRT1B , tmp2 ) ;
2005-04-17 02:20:36 +04:00
/* construct bit 19 of screen start address */
2007-10-16 12:29:13 +04:00
if ( cirrusfb_board_info [ cinfo - > btype ] . scrn_start_bit19 )
vga_wcrt ( cinfo - > regbase , CL_CRT1D , ( base > > 12 ) & 0x80 ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
/* write pixel panning value to AR33; this does not quite work in 8bpp
*
* # # # Piccolo . . ? Will this work ?
*/
2005-04-17 02:20:36 +04:00
if ( info - > var . bits_per_pixel = = 1 )
2007-10-16 12:29:08 +04:00
vga_wattr ( cinfo - > regbase , CL_AR33 , xpix ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
cirrusfb_WaitBLT ( cinfo - > regbase ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:29:08 +04:00
static int cirrusfb_blank ( int blank_mode , struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
/*
2007-10-16 12:29:08 +04:00
* Blank the screen if blank_mode ! = 0 , else unblank . If blank = = NULL
* then the caller blanks by setting the CLUT ( Color Look Up Table )
* to all black . Return 0 if blanking succeeded , ! = 0 if un - / blanking
* failed due to e . g . a video mode which doesn ' t support it .
* Implements VESA suspend and powerdown modes on hardware that
* supports disabling hsync / vsync :
* blank_mode = = 2 : suspend vsync
* blank_mode = = 3 : suspend hsync
* blank_mode = = 4 : powerdown
2005-04-17 02:20:36 +04:00
*/
unsigned char val ;
struct cirrusfb_info * cinfo = info - > par ;
int current_mode = cinfo - > blank_mode ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER, blank mode = %d \n " , blank_mode ) ;
2005-04-17 02:20:36 +04:00
if ( info - > state ! = FBINFO_STATE_RUNNING | |
current_mode = = blank_mode ) {
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT, returning 0 \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* Undo current */
if ( current_mode = = FB_BLANK_NORMAL | |
current_mode = = FB_BLANK_UNBLANK ) {
/* unblank the screen */
2007-10-16 12:29:08 +04:00
val = vga_rseq ( cinfo - > regbase , VGA_SEQ_CLOCK_MODE ) ;
/* clear "FullBandwidth" bit */
vga_wseq ( cinfo - > regbase , VGA_SEQ_CLOCK_MODE , val & 0xdf ) ;
2005-04-17 02:20:36 +04:00
/* and undo VESA suspend trickery */
2007-10-16 12:29:08 +04:00
vga_wgfx ( cinfo - > regbase , CL_GRE , 0x00 ) ;
2005-04-17 02:20:36 +04:00
}
/* set new */
2007-10-16 12:29:08 +04:00
if ( blank_mode > FB_BLANK_NORMAL ) {
2005-04-17 02:20:36 +04:00
/* blank the screen */
2007-10-16 12:29:08 +04:00
val = vga_rseq ( cinfo - > regbase , VGA_SEQ_CLOCK_MODE ) ;
/* set "FullBandwidth" bit */
vga_wseq ( cinfo - > regbase , VGA_SEQ_CLOCK_MODE , val | 0x20 ) ;
2005-04-17 02:20:36 +04:00
}
switch ( blank_mode ) {
case FB_BLANK_UNBLANK :
case FB_BLANK_NORMAL :
break ;
case FB_BLANK_VSYNC_SUSPEND :
2007-10-16 12:29:08 +04:00
vga_wgfx ( cinfo - > regbase , CL_GRE , 0x04 ) ;
2005-04-17 02:20:36 +04:00
break ;
case FB_BLANK_HSYNC_SUSPEND :
2007-10-16 12:29:08 +04:00
vga_wgfx ( cinfo - > regbase , CL_GRE , 0x02 ) ;
2005-04-17 02:20:36 +04:00
break ;
case FB_BLANK_POWERDOWN :
2007-10-16 12:29:08 +04:00
vga_wgfx ( cinfo - > regbase , CL_GRE , 0x06 ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT, returning 1 \n " ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
cinfo - > blank_mode = blank_mode ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT, returning 0 \n " ) ;
2005-04-17 02:20:36 +04:00
/* Let fbcon do a soft blank for us */
return ( blank_mode = = FB_BLANK_NORMAL ) ? 1 : 0 ;
}
/**** END Hardware specific Routines **************************************/
/****************************************************************************/
/**** BEGIN Internal Routines ***********************************************/
2007-10-16 12:29:12 +04:00
static void init_vgachip ( struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:29:12 +04:00
struct cirrusfb_info * cinfo = info - > par ;
2005-04-17 02:20:36 +04:00
const struct cirrusfb_board_info_rec * bi ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
assert ( cinfo ! = NULL ) ;
2005-04-17 02:20:36 +04:00
bi = & cirrusfb_board_info [ cinfo - > btype ] ;
/* reset board globally */
switch ( cinfo - > btype ) {
case BT_PICCOLO :
2007-10-16 12:29:08 +04:00
WSFR ( cinfo , 0x01 ) ;
udelay ( 500 ) ;
WSFR ( cinfo , 0x51 ) ;
udelay ( 500 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICASSO :
2007-10-16 12:29:08 +04:00
WSFR2 ( cinfo , 0xff ) ;
udelay ( 500 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_SD64 :
case BT_SPECTRUM :
2007-10-16 12:29:08 +04:00
WSFR ( cinfo , 0x1f ) ;
udelay ( 500 ) ;
WSFR ( cinfo , 0x4f ) ;
udelay ( 500 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICASSO4 :
2007-10-16 12:29:08 +04:00
/* disable flickerfixer */
vga_wcrt ( cinfo - > regbase , CL_CRT51 , 0x00 ) ;
mdelay ( 100 ) ;
/* from Klaus' NetBSD driver: */
vga_wgfx ( cinfo - > regbase , CL_GR2F , 0x00 ) ;
/* put blitter into 542x compat */
vga_wgfx ( cinfo - > regbase , CL_GR33 , 0x00 ) ;
/* mode */
vga_wgfx ( cinfo - > regbase , CL_GR31 , 0x00 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_GD5480 :
2007-10-16 12:29:08 +04:00
/* from Klaus' NetBSD driver: */
vga_wgfx ( cinfo - > regbase , CL_GR2F , 0x00 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_ALPINE :
/* Nothing to do to reset the board. */
break ;
default :
2007-10-16 12:29:08 +04:00
printk ( KERN_ERR " cirrusfb: Warning: Unknown board type \n " ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2007-10-16 12:29:12 +04:00
/* make sure RAM size set by this point */
assert ( info - > screen_size > 0 ) ;
2005-04-17 02:20:36 +04:00
/* the P4 is not fully initialized here; I rely on it having been */
/* inited under AmigaOS already, which seems to work just fine */
2007-10-16 12:29:08 +04:00
/* (Klaus advised to do it this way) */
2005-04-17 02:20:36 +04:00
if ( cinfo - > btype ! = BT_PICASSO4 ) {
2007-10-16 12:29:08 +04:00
WGen ( cinfo , CL_VSSM , 0x10 ) ; /* EGS: 0x16 */
WGen ( cinfo , CL_POS102 , 0x01 ) ;
WGen ( cinfo , CL_VSSM , 0x08 ) ; /* EGS: 0x0e */
2005-04-17 02:20:36 +04:00
if ( cinfo - > btype ! = BT_SD64 )
2007-10-16 12:29:08 +04:00
WGen ( cinfo , CL_VSSM2 , 0x01 ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
/* reset sequencer logic */
vga_wseq ( cinfo - > regbase , CL_SEQR0 , 0x03 ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
/* FullBandwidth (video off) and 8/9 dot clock */
vga_wseq ( cinfo - > regbase , VGA_SEQ_CLOCK_MODE , 0x21 ) ;
/* polarity (-/-), disable access to display memory,
* VGA_CRTC_START_HI base address : color
*/
WGen ( cinfo , VGA_MIS_W , 0xc1 ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
/* "magic cookie" - doesn't make any sense to me.. */
/* vga_wgfx(cinfo->regbase, CL_GRA, 0xce); */
/* unlock all extension registers */
vga_wseq ( cinfo - > regbase , CL_SEQR6 , 0x12 ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
/* reset blitter */
vga_wgfx ( cinfo - > regbase , CL_GR31 , 0x04 ) ;
2005-04-17 02:20:36 +04:00
switch ( cinfo - > btype ) {
case BT_GD5480 :
2007-10-16 12:29:08 +04:00
vga_wseq ( cinfo - > regbase , CL_SEQRF , 0x98 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_ALPINE :
break ;
case BT_SD64 :
2007-10-16 12:29:08 +04:00
vga_wseq ( cinfo - > regbase , CL_SEQRF , 0xb8 ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2007-10-16 12:29:08 +04:00
vga_wseq ( cinfo - > regbase , CL_SEQR16 , 0x0f ) ;
vga_wseq ( cinfo - > regbase , CL_SEQRF , 0xb0 ) ;
2005-04-17 02:20:36 +04:00
break ;
}
}
2007-10-16 12:29:08 +04:00
/* plane mask: nothing */
vga_wseq ( cinfo - > regbase , VGA_SEQ_PLANE_WRITE , 0xff ) ;
/* character map select: doesn't even matter in gx mode */
vga_wseq ( cinfo - > regbase , VGA_SEQ_CHARACTER_MAP , 0x00 ) ;
/* memory mode: chain-4, no odd/even, ext. memory */
vga_wseq ( cinfo - > regbase , VGA_SEQ_MEMORY_MODE , 0x0e ) ;
2005-04-17 02:20:36 +04:00
/* controller-internal base address of video memory */
if ( bi - > init_sr07 )
2007-10-16 12:29:08 +04:00
vga_wseq ( cinfo - > regbase , CL_SEQR7 , bi - > sr07 ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
/* vga_wseq(cinfo->regbase, CL_SEQR8, 0x00); */
/* EEPROM control: shouldn't be necessary to write to this at all.. */
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
/* graphics cursor X position (incomplete; position gives rem. 3 bits */
vga_wseq ( cinfo - > regbase , CL_SEQR10 , 0x00 ) ;
/* graphics cursor Y position (..."... ) */
vga_wseq ( cinfo - > regbase , CL_SEQR11 , 0x00 ) ;
/* graphics cursor attributes */
vga_wseq ( cinfo - > regbase , CL_SEQR12 , 0x00 ) ;
/* graphics cursor pattern address */
vga_wseq ( cinfo - > regbase , CL_SEQR13 , 0x00 ) ;
2005-04-17 02:20:36 +04:00
/* writing these on a P4 might give problems.. */
if ( cinfo - > btype ! = BT_PICASSO4 ) {
2007-10-16 12:29:08 +04:00
/* configuration readback and ext. color */
vga_wseq ( cinfo - > regbase , CL_SEQR17 , 0x00 ) ;
/* signature generator */
vga_wseq ( cinfo - > regbase , CL_SEQR18 , 0x02 ) ;
2005-04-17 02:20:36 +04:00
}
/* MCLK select etc. */
if ( bi - > init_sr1f )
2007-10-16 12:29:08 +04:00
vga_wseq ( cinfo - > regbase , CL_SEQR1F , bi - > sr1f ) ;
/* Screen A preset row scan: none */
vga_wcrt ( cinfo - > regbase , VGA_CRTC_PRESET_ROW , 0x00 ) ;
/* Text cursor start: disable text cursor */
vga_wcrt ( cinfo - > regbase , VGA_CRTC_CURSOR_START , 0x20 ) ;
/* Text cursor end: - */
vga_wcrt ( cinfo - > regbase , VGA_CRTC_CURSOR_END , 0x00 ) ;
/* Screen start address high: 0 */
vga_wcrt ( cinfo - > regbase , VGA_CRTC_START_HI , 0x00 ) ;
/* Screen start address low: 0 */
vga_wcrt ( cinfo - > regbase , VGA_CRTC_START_LO , 0x00 ) ;
/* text cursor location high: 0 */
vga_wcrt ( cinfo - > regbase , VGA_CRTC_CURSOR_HI , 0x00 ) ;
/* text cursor location low: 0 */
vga_wcrt ( cinfo - > regbase , VGA_CRTC_CURSOR_LO , 0x00 ) ;
/* Underline Row scanline: - */
vga_wcrt ( cinfo - > regbase , VGA_CRTC_UNDERLINE , 0x00 ) ;
/* mode control: timing enable, byte mode, no compat modes */
vga_wcrt ( cinfo - > regbase , VGA_CRTC_MODE , 0xc3 ) ;
/* Line Compare: not needed */
vga_wcrt ( cinfo - > regbase , VGA_CRTC_LINE_COMPARE , 0x00 ) ;
2005-04-17 02:20:36 +04:00
/* ### add 0x40 for text modes with > 30 MHz pixclock */
2007-10-16 12:29:08 +04:00
/* ext. display controls: ext.adr. wrap */
vga_wcrt ( cinfo - > regbase , CL_CRT1B , 0x02 ) ;
/* Set/Reset registes: - */
vga_wgfx ( cinfo - > regbase , VGA_GFX_SR_VALUE , 0x00 ) ;
/* Set/Reset enable: - */
vga_wgfx ( cinfo - > regbase , VGA_GFX_SR_ENABLE , 0x00 ) ;
/* Color Compare: - */
vga_wgfx ( cinfo - > regbase , VGA_GFX_COMPARE_VALUE , 0x00 ) ;
/* Data Rotate: - */
vga_wgfx ( cinfo - > regbase , VGA_GFX_DATA_ROTATE , 0x00 ) ;
/* Read Map Select: - */
vga_wgfx ( cinfo - > regbase , VGA_GFX_PLANE_READ , 0x00 ) ;
/* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
vga_wgfx ( cinfo - > regbase , VGA_GFX_MODE , 0x00 ) ;
/* Miscellaneous: memory map base address, graphics mode */
vga_wgfx ( cinfo - > regbase , VGA_GFX_MISC , 0x01 ) ;
/* Color Don't care: involve all planes */
vga_wgfx ( cinfo - > regbase , VGA_GFX_COMPARE_MASK , 0x0f ) ;
/* Bit Mask: no mask at all */
vga_wgfx ( cinfo - > regbase , VGA_GFX_BIT_MASK , 0xff ) ;
2005-04-17 02:20:36 +04:00
if ( cinfo - > btype = = BT_ALPINE )
2007-10-16 12:29:08 +04:00
/* (5434 can't have bit 3 set for bitblt) */
vga_wgfx ( cinfo - > regbase , CL_GRB , 0x20 ) ;
2005-04-17 02:20:36 +04:00
else
2007-10-16 12:29:08 +04:00
/* Graphics controller mode extensions: finer granularity,
* 8 byte data latches
*/
vga_wgfx ( cinfo - > regbase , CL_GRB , 0x28 ) ;
vga_wgfx ( cinfo - > regbase , CL_GRC , 0xff ) ; /* Color Key compare: - */
vga_wgfx ( cinfo - > regbase , CL_GRD , 0x00 ) ; /* Color Key compare mask: - */
vga_wgfx ( cinfo - > regbase , CL_GRE , 0x00 ) ; /* Miscellaneous control: - */
/* Background color byte 1: - */
/* vga_wgfx (cinfo->regbase, CL_GR10, 0x00); */
/* vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */
/* Attribute Controller palette registers: "identity mapping" */
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTE0 , 0x00 ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTE1 , 0x01 ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTE2 , 0x02 ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTE3 , 0x03 ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTE4 , 0x04 ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTE5 , 0x05 ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTE6 , 0x06 ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTE7 , 0x07 ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTE8 , 0x08 ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTE9 , 0x09 ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTEA , 0x0a ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTEB , 0x0b ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTEC , 0x0c ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTED , 0x0d ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTEE , 0x0e ) ;
vga_wattr ( cinfo - > regbase , VGA_ATC_PALETTEF , 0x0f ) ;
/* Attribute Controller mode: graphics mode */
vga_wattr ( cinfo - > regbase , VGA_ATC_MODE , 0x01 ) ;
/* Overscan color reg.: reg. 0 */
vga_wattr ( cinfo - > regbase , VGA_ATC_OVERSCAN , 0x00 ) ;
/* Color Plane enable: Enable all 4 planes */
vga_wattr ( cinfo - > regbase , VGA_ATC_PLANE_ENABLE , 0x0f ) ;
/* ### vga_wattr(cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */
/* Color Select: - */
vga_wattr ( cinfo - > regbase , VGA_ATC_COLOR_PAGE , 0x00 ) ;
WGen ( cinfo , VGA_PEL_MSK , 0xff ) ; /* Pixel mask: no mask */
2005-04-17 02:20:36 +04:00
if ( cinfo - > btype ! = BT_ALPINE & & cinfo - > btype ! = BT_GD5480 )
2007-10-16 12:29:08 +04:00
/* polarity (-/-), enable display mem,
* VGA_CRTC_START_HI i / o base = color
*/
WGen ( cinfo , VGA_MIS_W , 0xc3 ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
/* BLT Start/status: Blitter reset */
vga_wgfx ( cinfo - > regbase , CL_GR31 , 0x04 ) ;
/* - " - : "end-of-reset" */
vga_wgfx ( cinfo - > regbase , CL_GR31 , 0x00 ) ;
2005-04-17 02:20:36 +04:00
/* misc... */
2007-10-16 12:29:08 +04:00
WHDR ( cinfo , 0 ) ; /* Hidden DAC register: - */
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
printk ( KERN_DEBUG " cirrusfb: This board has %ld bytes of DRAM memory \n " ,
2007-10-16 12:29:12 +04:00
info - > screen_size ) ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2007-10-16 12:29:08 +04:00
static void switch_monitor ( struct cirrusfb_info * cinfo , int on )
2005-04-17 02:20:36 +04:00
{
# ifdef CONFIG_ZORRO /* only works on Zorro boards */
static int IsOn = 0 ; /* XXX not ok for multiple boards */
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
if ( cinfo - > btype = = BT_PICASSO4 )
return ; /* nothing to switch */
if ( cinfo - > btype = = BT_ALPINE )
return ; /* nothing to switch */
if ( cinfo - > btype = = BT_GD5480 )
return ; /* nothing to switch */
if ( cinfo - > btype = = BT_PICASSO ) {
if ( ( on & & ! IsOn ) | | ( ! on & & IsOn ) )
2007-10-16 12:29:08 +04:00
WSFR ( cinfo , 0xff ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
if ( on ) {
switch ( cinfo - > btype ) {
case BT_SD64 :
2007-10-16 12:29:08 +04:00
WSFR ( cinfo , cinfo - > SFR | 0x21 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICCOLO :
2007-10-16 12:29:08 +04:00
WSFR ( cinfo , cinfo - > SFR | 0x28 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_SPECTRUM :
2007-10-16 12:29:08 +04:00
WSFR ( cinfo , 0x6f ) ;
2005-04-17 02:20:36 +04:00
break ;
default : /* do nothing */ break ;
}
} else {
switch ( cinfo - > btype ) {
case BT_SD64 :
2007-10-16 12:29:08 +04:00
WSFR ( cinfo , cinfo - > SFR & 0xde ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_PICCOLO :
2007-10-16 12:29:08 +04:00
WSFR ( cinfo , cinfo - > SFR & 0xd7 ) ;
2005-04-17 02:20:36 +04:00
break ;
case BT_SPECTRUM :
2007-10-16 12:29:08 +04:00
WSFR ( cinfo , 0x4f ) ;
2005-04-17 02:20:36 +04:00
break ;
default : /* do nothing */ break ;
}
}
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
# endif /* CONFIG_ZORRO */
}
/******************************************/
/* Linux 2.6-style accelerated functions */
/******************************************/
2007-10-16 12:29:08 +04:00
static void cirrusfb_fillrect ( struct fb_info * info ,
const struct fb_fillrect * region )
2005-04-17 02:20:36 +04:00
{
struct fb_fillrect modded ;
int vxres , vyres ;
2007-10-16 12:29:13 +04:00
struct cirrusfb_info * cinfo = info - > par ;
int m = info - > var . bits_per_pixel ;
u32 color = ( info - > fix . visual = = FB_VISUAL_TRUECOLOR ) ?
cinfo - > pseudo_palette [ region - > color ] : region - > color ;
2005-04-17 02:20:36 +04:00
if ( info - > state ! = FBINFO_STATE_RUNNING )
return ;
if ( info - > flags & FBINFO_HWACCEL_DISABLED ) {
cfb_fillrect ( info , region ) ;
return ;
}
vxres = info - > var . xres_virtual ;
vyres = info - > var . yres_virtual ;
memcpy ( & modded , region , sizeof ( struct fb_fillrect ) ) ;
2007-10-16 12:29:08 +04:00
if ( ! modded . width | | ! modded . height | |
2005-04-17 02:20:36 +04:00
modded . dx > = vxres | | modded . dy > = vyres )
return ;
2007-10-16 12:29:08 +04:00
if ( modded . dx + modded . width > vxres )
modded . width = vxres - modded . dx ;
if ( modded . dy + modded . height > vyres )
modded . height = vyres - modded . dy ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:13 +04:00
cirrusfb_RectFill ( cinfo - > regbase ,
info - > var . bits_per_pixel ,
( region - > dx * m ) / 8 , region - > dy ,
( region - > width * m ) / 8 , region - > height ,
color ,
cinfo - > currentmode . line_length ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:29:08 +04:00
static void cirrusfb_copyarea ( struct fb_info * info ,
const struct fb_copyarea * area )
2005-04-17 02:20:36 +04:00
{
struct fb_copyarea modded ;
u32 vxres , vyres ;
2007-10-16 12:29:13 +04:00
struct cirrusfb_info * cinfo = info - > par ;
int m = info - > var . bits_per_pixel ;
2005-04-17 02:20:36 +04:00
if ( info - > state ! = FBINFO_STATE_RUNNING )
return ;
if ( info - > flags & FBINFO_HWACCEL_DISABLED ) {
cfb_copyarea ( info , area ) ;
return ;
}
vxres = info - > var . xres_virtual ;
vyres = info - > var . yres_virtual ;
2007-10-16 12:29:13 +04:00
memcpy ( & modded , area , sizeof ( struct fb_copyarea ) ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
if ( ! modded . width | | ! modded . height | |
2005-04-17 02:20:36 +04:00
modded . sx > = vxres | | modded . sy > = vyres | |
modded . dx > = vxres | | modded . dy > = vyres )
return ;
2007-10-16 12:29:08 +04:00
if ( modded . sx + modded . width > vxres )
modded . width = vxres - modded . sx ;
if ( modded . dx + modded . width > vxres )
modded . width = vxres - modded . dx ;
if ( modded . sy + modded . height > vyres )
modded . height = vyres - modded . sy ;
if ( modded . dy + modded . height > vyres )
modded . height = vyres - modded . dy ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:13 +04:00
cirrusfb_BitBLT ( cinfo - > regbase , info - > var . bits_per_pixel ,
( area - > sx * m ) / 8 , area - > sy ,
( area - > dx * m ) / 8 , area - > dy ,
( area - > width * m ) / 8 , area - > height ,
cinfo - > currentmode . line_length ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:29:08 +04:00
static void cirrusfb_imageblit ( struct fb_info * info ,
const struct fb_image * image )
2005-04-17 02:20:36 +04:00
{
struct cirrusfb_info * cinfo = info - > par ;
2007-10-16 12:29:08 +04:00
cirrusfb_WaitBLT ( cinfo - > regbase ) ;
2005-04-17 02:20:36 +04:00
cfb_imageblit ( info , image ) ;
}
# ifdef CONFIG_PPC_PREP
# define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000)
# define PREP_IO_BASE ((volatile unsigned char *) 0x80000000)
2007-10-16 12:29:08 +04:00
static void get_prep_addrs ( unsigned long * display , unsigned long * registers )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
* display = PREP_VIDEO_BASE ;
* registers = ( unsigned long ) PREP_IO_BASE ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
# endif /* CONFIG_PPC_PREP */
# ifdef CONFIG_PCI
2007-10-16 12:29:08 +04:00
static int release_io_ports ;
2005-04-17 02:20:36 +04:00
/* Pulled the logic from XFree86 Cirrus driver to get the memory size,
* based on the DRAM bandwidth bit and DRAM bank switching bit . This
* works with 1 MB , 2 MB and 4 MB configurations ( which the Motorola boards
* seem to have . */
2007-10-16 12:29:08 +04:00
static unsigned int cirrusfb_get_memsize ( u8 __iomem * regbase )
2005-04-17 02:20:36 +04:00
{
unsigned long mem ;
unsigned char SRF ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
SRF = vga_rseq ( regbase , CL_SEQRF ) ;
2005-04-17 02:20:36 +04:00
switch ( ( SRF & 0x18 ) ) {
2007-10-16 12:29:08 +04:00
case 0x08 :
mem = 512 * 1024 ;
break ;
case 0x10 :
mem = 1024 * 1024 ;
break ;
/* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory
* on the 5430.
*/
case 0x18 :
mem = 2048 * 1024 ;
break ;
default :
printk ( KERN_WARNING " CLgenfb: Unknown memory size! \n " ) ;
2005-04-17 02:20:36 +04:00
mem = 1024 * 1024 ;
}
2007-10-16 12:29:08 +04:00
if ( SRF & 0x80 )
/* If DRAM bank switching is enabled, there must be twice as much
* memory installed . ( 4 MB on the 5434 )
*/
2005-04-17 02:20:36 +04:00
mem * = 2 ;
2007-10-16 12:29:08 +04:00
2005-04-17 02:20:36 +04:00
/* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
return mem ;
}
2007-10-16 12:29:08 +04:00
static void get_pci_addrs ( const struct pci_dev * pdev ,
unsigned long * display , unsigned long * registers )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:29:08 +04:00
assert ( pdev ! = NULL ) ;
assert ( display ! = NULL ) ;
assert ( registers ! = NULL ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
* display = 0 ;
* registers = 0 ;
/* This is a best-guess for now */
if ( pci_resource_flags ( pdev , 0 ) & IORESOURCE_IO ) {
* display = pci_resource_start ( pdev , 1 ) ;
* registers = pci_resource_start ( pdev , 0 ) ;
} else {
* display = pci_resource_start ( pdev , 0 ) ;
* registers = pci_resource_start ( pdev , 1 ) ;
}
2007-10-16 12:29:08 +04:00
assert ( * display ! = 0 ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:29:12 +04:00
static void cirrusfb_pci_unmap ( struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:29:12 +04:00
struct cirrusfb_info * cinfo = info - > par ;
2005-04-17 02:20:36 +04:00
struct pci_dev * pdev = cinfo - > pdev ;
2007-10-16 12:29:12 +04:00
iounmap ( info - > screen_base ) ;
2005-04-17 02:20:36 +04:00
#if 0 /* if system didn't claim this region, we would... */
release_mem_region ( 0xA0000 , 65535 ) ;
# endif
if ( release_io_ports )
release_region ( 0x3C0 , 32 ) ;
pci_release_regions ( pdev ) ;
}
# endif /* CONFIG_PCI */
# ifdef CONFIG_ZORRO
2007-10-16 12:29:08 +04:00
static void __devexit cirrusfb_zorro_unmap ( struct cirrusfb_info * cinfo )
2005-04-17 02:20:36 +04:00
{
zorro_release_device ( cinfo - > zdev ) ;
if ( cinfo - > btype = = BT_PICASSO4 ) {
cinfo - > regbase - = 0x600000 ;
2007-10-16 12:29:08 +04:00
iounmap ( ( void * ) cinfo - > regbase ) ;
2007-10-16 12:29:12 +04:00
iounmap ( info - > screen_base ) ;
2005-04-17 02:20:36 +04:00
} else {
if ( zorro_resource_start ( cinfo - > zdev ) > 0x01000000 )
2007-10-16 12:29:12 +04:00
iounmap ( info - > screen_base ) ;
2005-04-17 02:20:36 +04:00
}
}
# endif /* CONFIG_ZORRO */
2007-10-16 12:29:12 +04:00
static int cirrusfb_set_fbinfo ( struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:29:12 +04:00
struct cirrusfb_info * cinfo = info - > par ;
2005-04-17 02:20:36 +04:00
struct fb_var_screeninfo * var = & info - > var ;
info - > pseudo_palette = cinfo - > pseudo_palette ;
info - > flags = FBINFO_DEFAULT
| FBINFO_HWACCEL_XPAN
| FBINFO_HWACCEL_YPAN
| FBINFO_HWACCEL_FILLRECT
| FBINFO_HWACCEL_COPYAREA ;
if ( noaccel )
info - > flags | = FBINFO_HWACCEL_DISABLED ;
info - > fbops = & cirrusfb_ops ;
if ( cinfo - > btype = = BT_GD5480 ) {
if ( var - > bits_per_pixel = = 16 )
info - > screen_base + = 1 * MB_ ;
if ( var - > bits_per_pixel = = 24 | | var - > bits_per_pixel = = 32 )
info - > screen_base + = 2 * MB_ ;
}
/* Fill fix common fields */
strlcpy ( info - > fix . id , cirrusfb_board_info [ cinfo - > btype ] . name ,
sizeof ( info - > fix . id ) ) ;
/* monochrome: only 1 memory plane */
/* 8 bit and above: Use whole memory area */
2007-10-16 12:29:12 +04:00
info - > fix . smem_len = info - > screen_size ;
if ( var - > bits_per_pixel = = 1 )
info - > fix . smem_len / = 4 ;
2005-04-17 02:20:36 +04:00
info - > fix . type = cinfo - > currentmode . type ;
info - > fix . type_aux = 0 ;
info - > fix . visual = cinfo - > currentmode . visual ;
info - > fix . xpanstep = 1 ;
info - > fix . ypanstep = 1 ;
info - > fix . ywrapstep = 0 ;
info - > fix . line_length = cinfo - > currentmode . line_length ;
/* FIXME: map region at 0xB8000 if available, fill in here */
info - > fix . mmio_len = 0 ;
info - > fix . accel = FB_ACCEL_NONE ;
fb_alloc_cmap ( & info - > cmap , 256 , 0 ) ;
return 0 ;
}
2007-10-16 12:29:12 +04:00
static int cirrusfb_register ( struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:29:12 +04:00
struct cirrusfb_info * cinfo = info - > par ;
2005-04-17 02:20:36 +04:00
int err ;
2007-10-16 12:29:11 +04:00
enum cirrus_board btype ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
printk ( KERN_INFO " cirrusfb: Driver for Cirrus Logic based "
" graphic boards, v " CIRRUSFB_VERSION " \n " ) ;
2005-04-17 02:20:36 +04:00
btype = cinfo - > btype ;
/* sanity checks */
2007-10-16 12:29:08 +04:00
assert ( btype ! = BT_NONE ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:12 +04:00
DPRINTK ( " cirrusfb: (RAM start set to: 0x%p) \n " , info - > screen_base ) ;
2005-04-17 02:20:36 +04:00
/* Make pretend we've set the var so our structures are in a "good" */
/* state, even though we haven't written the mode to the hw yet... */
info - > var = cirrusfb_predefined [ cirrusfb_def_mode ] . var ;
info - > var . activate = FB_ACTIVATE_NOW ;
err = cirrusfb_decode_var ( & info - > var , & cinfo - > currentmode , info ) ;
if ( err < 0 ) {
/* should never happen */
DPRINTK ( " choking on default var... umm, no good. \n " ) ;
goto err_unmap_cirrusfb ;
}
/* set all the vital stuff */
2007-10-16 12:29:12 +04:00
cirrusfb_set_fbinfo ( info ) ;
2005-04-17 02:20:36 +04:00
err = register_framebuffer ( info ) ;
if ( err < 0 ) {
2007-10-16 12:29:08 +04:00
printk ( KERN_ERR " cirrusfb: could not register "
" fb device; err = %d! \n " , err ) ;
2005-04-17 02:20:36 +04:00
goto err_dealloc_cmap ;
}
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT, returning 0 \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
err_dealloc_cmap :
fb_dealloc_cmap ( & info - > cmap ) ;
err_unmap_cirrusfb :
2007-10-16 12:29:12 +04:00
cinfo - > unmap ( info ) ;
2007-10-16 12:29:13 +04:00
framebuffer_release ( info ) ;
2005-04-17 02:20:36 +04:00
return err ;
}
2007-10-16 12:29:08 +04:00
static void __devexit cirrusfb_cleanup ( struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
struct cirrusfb_info * cinfo = info - > par ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
switch_monitor ( cinfo , 0 ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
unregister_framebuffer ( info ) ;
fb_dealloc_cmap ( & info - > cmap ) ;
printk ( " Framebuffer unregistered \n " ) ;
2007-10-16 12:29:12 +04:00
cinfo - > unmap ( info ) ;
2007-10-16 12:29:13 +04:00
framebuffer_release ( info ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
# ifdef CONFIG_PCI
2007-10-16 12:29:08 +04:00
static int cirrusfb_pci_register ( struct pci_dev * pdev ,
2005-04-17 02:20:36 +04:00
const struct pci_device_id * ent )
{
struct cirrusfb_info * cinfo ;
struct fb_info * info ;
2007-10-16 12:29:11 +04:00
enum cirrus_board btype ;
2005-04-17 02:20:36 +04:00
unsigned long board_addr , board_size ;
int ret ;
ret = pci_enable_device ( pdev ) ;
if ( ret < 0 ) {
printk ( KERN_ERR " cirrusfb: Cannot enable PCI device \n " ) ;
goto err_out ;
}
info = framebuffer_alloc ( sizeof ( struct cirrusfb_info ) , & pdev - > dev ) ;
if ( ! info ) {
printk ( KERN_ERR " cirrusfb: could not allocate memory \n " ) ;
ret = - ENOMEM ;
goto err_disable ;
}
cinfo = info - > par ;
cinfo - > pdev = pdev ;
2007-10-16 12:29:11 +04:00
cinfo - > btype = btype = ( enum cirrus_board ) ent - > driver_data ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:11 +04:00
DPRINTK ( " Found PCI device, base address 0 is 0x%x, btype set to %d \n " ,
2005-04-17 02:20:36 +04:00
pdev - > resource [ 0 ] . start , btype ) ;
2007-10-16 12:29:11 +04:00
DPRINTK ( " base address 1 is 0x%x \n " , pdev - > resource [ 1 ] . start ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
if ( isPReP ) {
pci_write_config_dword ( pdev , PCI_BASE_ADDRESS_0 , 0x00000000 ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_PPC_PREP
2007-10-16 12:29:12 +04:00
get_prep_addrs ( & board_addr , & info - > fix . mmio_start ) ;
2005-04-17 02:20:36 +04:00
# endif
2007-10-16 12:29:08 +04:00
/* PReP dies if we ioremap the IO registers, but it works w/out... */
2007-10-16 12:29:12 +04:00
cinfo - > regbase = ( char __iomem * ) info - > fix . mmio_start ;
2005-04-17 02:20:36 +04:00
} else {
2007-10-16 12:29:08 +04:00
DPRINTK ( " Attempt to get PCI info for Cirrus Graphics Card \n " ) ;
2007-10-16 12:29:12 +04:00
get_pci_addrs ( pdev , & board_addr , & info - > fix . mmio_start ) ;
2007-10-16 12:29:08 +04:00
/* FIXME: this forces VGA. alternatives? */
cinfo - > regbase = NULL ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:29:08 +04:00
DPRINTK ( " Board address: 0x%lx, register address: 0x%lx \n " ,
2007-10-16 12:29:12 +04:00
board_addr , info - > fix . mmio_start ) ;
2005-04-17 02:20:36 +04:00
board_size = ( btype = = BT_GD5480 ) ?
2007-10-16 12:29:08 +04:00
32 * MB_ : cirrusfb_get_memsize ( cinfo - > regbase ) ;
2005-04-17 02:20:36 +04:00
ret = pci_request_regions ( pdev , " cirrusfb " ) ;
2007-10-16 12:29:08 +04:00
if ( ret < 0 ) {
printk ( KERN_ERR " cirrusfb: cannot reserve region 0x%lx, "
" abort \n " ,
2005-04-17 02:20:36 +04:00
board_addr ) ;
goto err_release_fb ;
}
#if 0 /* if the system didn't claim this region, we would... */
if ( ! request_mem_region ( 0xA0000 , 65535 , " cirrusfb " ) ) {
printk ( KERN_ERR " cirrusfb: cannot reserve region 0x%lx, abort \n "
,
0xA0000L ) ;
ret = - EBUSY ;
goto err_release_regions ;
}
# endif
if ( request_region ( 0x3C0 , 32 , " cirrusfb " ) )
release_io_ports = 1 ;
2007-10-16 12:29:12 +04:00
info - > screen_base = ioremap ( board_addr , board_size ) ;
if ( ! info - > screen_base ) {
2005-04-17 02:20:36 +04:00
ret = - EIO ;
goto err_release_legacy ;
}
2007-10-16 12:29:12 +04:00
info - > fix . smem_start = board_addr ;
info - > screen_size = board_size ;
2005-04-17 02:20:36 +04:00
cinfo - > unmap = cirrusfb_pci_unmap ;
2007-10-16 12:29:08 +04:00
printk ( KERN_INFO " RAM (%lu kB) at 0xx%lx, " ,
2007-10-16 12:29:12 +04:00
info - > screen_size / KB_ , board_addr ) ;
2007-10-16 12:29:08 +04:00
printk ( KERN_INFO " Cirrus Logic chipset on PCI bus \n " ) ;
2005-04-17 02:20:36 +04:00
pci_set_drvdata ( pdev , info ) ;
2007-10-16 12:29:12 +04:00
ret = cirrusfb_register ( info ) ;
2006-12-08 13:40:13 +03:00
if ( ret )
2007-10-16 12:29:12 +04:00
iounmap ( info - > screen_base ) ;
2006-12-08 13:40:13 +03:00
return ret ;
2005-04-17 02:20:36 +04:00
err_release_legacy :
if ( release_io_ports )
release_region ( 0x3C0 , 32 ) ;
#if 0
release_mem_region ( 0xA0000 , 65535 ) ;
err_release_regions :
# endif
pci_release_regions ( pdev ) ;
err_release_fb :
framebuffer_release ( info ) ;
err_disable :
err_out :
return ret ;
}
2007-10-16 12:29:08 +04:00
static void __devexit cirrusfb_pci_unregister ( struct pci_dev * pdev )
2005-04-17 02:20:36 +04:00
{
struct fb_info * info = pci_get_drvdata ( pdev ) ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
cirrusfb_cleanup ( info ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
static struct pci_driver cirrusfb_pci_driver = {
. name = " cirrusfb " ,
. id_table = cirrusfb_pci_table ,
. probe = cirrusfb_pci_register ,
. remove = __devexit_p ( cirrusfb_pci_unregister ) ,
# ifdef CONFIG_PM
#if 0
. suspend = cirrusfb_pci_suspend ,
. resume = cirrusfb_pci_resume ,
# endif
# endif
} ;
# endif /* CONFIG_PCI */
# ifdef CONFIG_ZORRO
static int cirrusfb_zorro_register ( struct zorro_dev * z ,
const struct zorro_device_id * ent )
{
struct cirrusfb_info * cinfo ;
struct fb_info * info ;
2007-10-16 12:29:11 +04:00
enum cirrus_board btype ;
2005-04-17 02:20:36 +04:00
struct zorro_dev * z2 = NULL ;
unsigned long board_addr , board_size , size ;
int ret ;
btype = ent - > driver_data ;
if ( cirrusfb_zorro_table2 [ btype ] . id2 )
z2 = zorro_find_device ( cirrusfb_zorro_table2 [ btype ] . id2 , NULL ) ;
size = cirrusfb_zorro_table2 [ btype ] . size ;
printk ( KERN_INFO " cirrusfb: %s board detected; " ,
cirrusfb_board_info [ btype ] . name ) ;
info = framebuffer_alloc ( sizeof ( struct cirrusfb_info ) , & z - > dev ) ;
if ( ! info ) {
2007-10-16 12:29:08 +04:00
printk ( KERN_ERR " cirrusfb: could not allocate memory \n " ) ;
2005-04-17 02:20:36 +04:00
ret = - ENOMEM ;
goto err_out ;
}
cinfo = info - > par ;
cinfo - > info = info ;
cinfo - > btype = btype ;
2007-10-16 12:29:08 +04:00
assert ( z > 0 ) ;
assert ( z2 > = 0 ) ;
assert ( btype ! = BT_NONE ) ;
2005-04-17 02:20:36 +04:00
cinfo - > zdev = z ;
board_addr = zorro_resource_start ( z ) ;
board_size = zorro_resource_len ( z ) ;
2007-10-16 12:29:12 +04:00
info - > screen_size = size ;
2005-04-17 02:20:36 +04:00
if ( ! zorro_request_device ( z , " cirrusfb " ) ) {
2007-10-16 12:29:08 +04:00
printk ( KERN_ERR " cirrusfb: cannot reserve region 0x%lx, "
" abort \n " ,
2005-04-17 02:20:36 +04:00
board_addr ) ;
ret = - EBUSY ;
goto err_release_fb ;
}
2007-10-16 12:29:08 +04:00
printk ( " RAM (%lu MB) at $%lx, " , board_size / MB_ , board_addr ) ;
2005-04-17 02:20:36 +04:00
ret = - EIO ;
if ( btype = = BT_PICASSO4 ) {
2007-10-16 12:29:08 +04:00
printk ( KERN_INFO " REG at $%lx \n " , board_addr + 0x600000 ) ;
2005-04-17 02:20:36 +04:00
/* To be precise, for the P4 this is not the */
/* begin of the board, but the begin of RAM. */
/* for P4, map in its address space in 2 chunks (### TEST! ) */
/* (note the ugly hardcoded 16M number) */
2007-10-16 12:29:08 +04:00
cinfo - > regbase = ioremap ( board_addr , 16777216 ) ;
2005-04-17 02:20:36 +04:00
if ( ! cinfo - > regbase )
goto err_release_region ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " cirrusfb: Virtual address for board set to: $%p \n " ,
cinfo - > regbase ) ;
2005-04-17 02:20:36 +04:00
cinfo - > regbase + = 0x600000 ;
2007-10-16 12:29:12 +04:00
info - > fix . mmio_start = board_addr + 0x600000 ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:12 +04:00
info - > fix . smem_start = board_addr + 16777216 ;
info - > screen_base = ioremap ( info - > fix . smem_start , 16777216 ) ;
if ( ! info - > screen_base )
2005-04-17 02:20:36 +04:00
goto err_unmap_regbase ;
} else {
2007-10-16 12:29:08 +04:00
printk ( KERN_INFO " REG at $%lx \n " ,
( unsigned long ) z2 - > resource . start ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:12 +04:00
info - > fix . smem_start = board_addr ;
2005-04-17 02:20:36 +04:00
if ( board_addr > 0x01000000 )
2007-10-16 12:29:12 +04:00
info - > screen_base = ioremap ( board_addr , board_size ) ;
2005-04-17 02:20:36 +04:00
else
2007-10-16 12:29:12 +04:00
info - > screen_base = ( caddr_t ) ZTWO_VADDR ( board_addr ) ;
if ( ! info - > screen_base )
2005-04-17 02:20:36 +04:00
goto err_release_region ;
/* set address for REG area of board */
2007-10-16 12:29:08 +04:00
cinfo - > regbase = ( caddr_t ) ZTWO_VADDR ( z2 - > resource . start ) ;
2007-10-16 12:29:12 +04:00
info - > fix . mmio_start = z2 - > resource . start ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " cirrusfb: Virtual address for board set to: $%p \n " ,
cinfo - > regbase ) ;
2005-04-17 02:20:36 +04:00
}
cinfo - > unmap = cirrusfb_zorro_unmap ;
2007-10-16 12:29:08 +04:00
printk ( KERN_INFO " Cirrus Logic chipset on Zorro bus \n " ) ;
2005-04-17 02:20:36 +04:00
zorro_set_drvdata ( z , info ) ;
2006-12-08 13:40:13 +03:00
ret = cirrusfb_register ( cinfo ) ;
if ( ret ) {
if ( btype = = BT_PICASSO4 ) {
2007-10-16 12:29:12 +04:00
iounmap ( info - > screen_base ) ;
2006-12-08 13:40:13 +03:00
iounmap ( cinfo - > regbase - 0x600000 ) ;
} else if ( board_addr > 0x01000000 )
2007-10-16 12:29:12 +04:00
iounmap ( info - > screen_base ) ;
2006-12-08 13:40:13 +03:00
}
return ret ;
2005-04-17 02:20:36 +04:00
err_unmap_regbase :
/* Parental advisory: explicit hack */
iounmap ( cinfo - > regbase - 0x600000 ) ;
err_release_region :
release_region ( board_addr , board_size ) ;
err_release_fb :
framebuffer_release ( info ) ;
err_out :
return ret ;
}
void __devexit cirrusfb_zorro_unregister ( struct zorro_dev * z )
{
struct fb_info * info = zorro_get_drvdata ( z ) ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
cirrusfb_cleanup ( info ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
static struct zorro_driver cirrusfb_zorro_driver = {
. name = " cirrusfb " ,
. id_table = cirrusfb_zorro_table ,
. probe = cirrusfb_zorro_register ,
. remove = __devexit_p ( cirrusfb_zorro_unregister ) ,
} ;
# endif /* CONFIG_ZORRO */
static int __init cirrusfb_init ( void )
{
int error = 0 ;
# ifndef MODULE
char * option = NULL ;
if ( fb_get_options ( " cirrusfb " , & option ) )
return - ENODEV ;
cirrusfb_setup ( option ) ;
# endif
# ifdef CONFIG_ZORRO
2006-03-25 14:07:20 +03:00
error | = zorro_register_driver ( & cirrusfb_zorro_driver ) ;
2005-04-17 02:20:36 +04:00
# endif
# ifdef CONFIG_PCI
error | = pci_register_driver ( & cirrusfb_pci_driver ) ;
# endif
return error ;
}
# ifndef MODULE
static int __init cirrusfb_setup ( char * options ) {
char * this_opt , s [ 32 ] ;
int i ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
if ( ! options | | ! * options )
return 0 ;
2007-10-16 12:29:08 +04:00
while ( ( this_opt = strsep ( & options , " , " ) ) ! = NULL ) {
2005-04-17 02:20:36 +04:00
if ( ! * this_opt ) continue ;
DPRINTK ( " cirrusfb_setup: option '%s' \n " , this_opt ) ;
for ( i = 0 ; i < NUM_TOTAL_MODES ; i + + ) {
2007-10-16 12:29:08 +04:00
sprintf ( s , " mode:%s " , cirrusfb_predefined [ i ] . name ) ;
if ( strcmp ( this_opt , s ) = = 0 )
2005-04-17 02:20:36 +04:00
cirrusfb_def_mode = i ;
}
if ( ! strcmp ( this_opt , " noaccel " ) )
noaccel = 1 ;
}
return 0 ;
}
# endif
/*
* Modularization
*/
MODULE_AUTHOR ( " Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com> " ) ;
MODULE_DESCRIPTION ( " Accelerated FBDev driver for Cirrus Logic chips " ) ;
MODULE_LICENSE ( " GPL " ) ;
2007-10-16 12:29:08 +04:00
static void __exit cirrusfb_exit ( void )
2005-04-17 02:20:36 +04:00
{
# ifdef CONFIG_PCI
pci_unregister_driver ( & cirrusfb_pci_driver ) ;
# endif
# ifdef CONFIG_ZORRO
zorro_unregister_driver ( & cirrusfb_zorro_driver ) ;
# endif
}
module_init ( cirrusfb_init ) ;
# ifdef MODULE
module_exit ( cirrusfb_exit ) ;
# endif
/**********************************************************************/
/* about the following functions - I have used the same names for the */
/* functions as Markus Wild did in his Retina driver for NetBSD as */
/* they just made sense for this purpose. Apart from that, I wrote */
2007-10-16 12:29:08 +04:00
/* these functions myself. */
2005-04-17 02:20:36 +04:00
/**********************************************************************/
/*** WGen() - write into one of the external/general registers ***/
2007-10-16 12:29:08 +04:00
static void WGen ( const struct cirrusfb_info * cinfo ,
2005-04-17 02:20:36 +04:00
int regnum , unsigned char val )
{
unsigned long regofs = 0 ;
if ( cinfo - > btype = = BT_PICASSO ) {
/* Picasso II specific hack */
2007-10-16 12:29:08 +04:00
/* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
regnum = = CL_VSSM2 ) */
2005-04-17 02:20:36 +04:00
if ( regnum = = VGA_PEL_IR | | regnum = = VGA_PEL_D )
regofs = 0xfff ;
}
2007-10-16 12:29:08 +04:00
vga_w ( cinfo - > regbase , regofs + regnum , val ) ;
2005-04-17 02:20:36 +04:00
}
/*** RGen() - read out one of the external/general registers ***/
2007-10-16 12:29:08 +04:00
static unsigned char RGen ( const struct cirrusfb_info * cinfo , int regnum )
2005-04-17 02:20:36 +04:00
{
unsigned long regofs = 0 ;
if ( cinfo - > btype = = BT_PICASSO ) {
/* Picasso II specific hack */
2007-10-16 12:29:08 +04:00
/* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
regnum = = CL_VSSM2 ) */
2005-04-17 02:20:36 +04:00
if ( regnum = = VGA_PEL_IR | | regnum = = VGA_PEL_D )
regofs = 0xfff ;
}
2007-10-16 12:29:08 +04:00
return vga_r ( cinfo - > regbase , regofs + regnum ) ;
2005-04-17 02:20:36 +04:00
}
/*** AttrOn() - turn on VideoEnable for Attribute controller ***/
2007-10-16 12:29:08 +04:00
static void AttrOn ( const struct cirrusfb_info * cinfo )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:29:08 +04:00
assert ( cinfo ! = NULL ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
if ( vga_rcrt ( cinfo - > regbase , CL_CRT24 ) & 0x80 ) {
2005-04-17 02:20:36 +04:00
/* if we're just in "write value" mode, write back the */
/* same value as before to not modify anything */
2007-10-16 12:29:08 +04:00
vga_w ( cinfo - > regbase , VGA_ATT_IW ,
vga_r ( cinfo - > regbase , VGA_ATT_R ) ) ;
2005-04-17 02:20:36 +04:00
}
/* turn on video bit */
2007-10-16 12:29:08 +04:00
/* vga_w(cinfo->regbase, VGA_ATT_IW, 0x20); */
vga_w ( cinfo - > regbase , VGA_ATT_IW , 0x33 ) ;
2005-04-17 02:20:36 +04:00
/* dummy write on Reg0 to be on "write index" mode next time */
2007-10-16 12:29:08 +04:00
vga_w ( cinfo - > regbase , VGA_ATT_IW , 0x00 ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
/*** WHDR() - write into the Hidden DAC register ***/
/* as the HDR is the only extension register that requires special treatment
* ( the other extension registers are accessible just like the " ordinary "
* registers of their functional group ) here is a specialized routine for
* accessing the HDR
*/
2007-10-16 12:29:08 +04:00
static void WHDR ( const struct cirrusfb_info * cinfo , unsigned char val )
2005-04-17 02:20:36 +04:00
{
unsigned char dummy ;
if ( cinfo - > btype = = BT_PICASSO ) {
/* Klaus' hint for correct access to HDR on some boards */
/* first write 0 to pixel mask (3c6) */
2007-10-16 12:29:08 +04:00
WGen ( cinfo , VGA_PEL_MSK , 0x00 ) ;
udelay ( 200 ) ;
2005-04-17 02:20:36 +04:00
/* next read dummy from pixel address (3c8) */
2007-10-16 12:29:08 +04:00
dummy = RGen ( cinfo , VGA_PEL_IW ) ;
udelay ( 200 ) ;
2005-04-17 02:20:36 +04:00
}
/* now do the usual stuff to access the HDR */
2007-10-16 12:29:08 +04:00
dummy = RGen ( cinfo , VGA_PEL_MSK ) ;
udelay ( 200 ) ;
dummy = RGen ( cinfo , VGA_PEL_MSK ) ;
udelay ( 200 ) ;
dummy = RGen ( cinfo , VGA_PEL_MSK ) ;
udelay ( 200 ) ;
dummy = RGen ( cinfo , VGA_PEL_MSK ) ;
udelay ( 200 ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
WGen ( cinfo , VGA_PEL_MSK , val ) ;
udelay ( 200 ) ;
2005-04-17 02:20:36 +04:00
if ( cinfo - > btype = = BT_PICASSO ) {
/* now first reset HDR access counter */
2007-10-16 12:29:08 +04:00
dummy = RGen ( cinfo , VGA_PEL_IW ) ;
udelay ( 200 ) ;
2005-04-17 02:20:36 +04:00
/* and at the end, restore the mask value */
/* ## is this mask always 0xff? */
2007-10-16 12:29:08 +04:00
WGen ( cinfo , VGA_PEL_MSK , 0xff ) ;
udelay ( 200 ) ;
2005-04-17 02:20:36 +04:00
}
}
/*** WSFR() - write to the "special function register" (SFR) ***/
2007-10-16 12:29:08 +04:00
static void WSFR ( struct cirrusfb_info * cinfo , unsigned char val )
2005-04-17 02:20:36 +04:00
{
# ifdef CONFIG_ZORRO
2007-10-16 12:29:08 +04:00
assert ( cinfo - > regbase ! = NULL ) ;
2005-04-17 02:20:36 +04:00
cinfo - > SFR = val ;
2007-10-16 12:29:08 +04:00
z_writeb ( val , cinfo - > regbase + 0x8000 ) ;
2005-04-17 02:20:36 +04:00
# endif
}
/* The Picasso has a second register for switching the monitor bit */
2007-10-16 12:29:08 +04:00
static void WSFR2 ( struct cirrusfb_info * cinfo , unsigned char val )
2005-04-17 02:20:36 +04:00
{
# ifdef CONFIG_ZORRO
/* writing an arbitrary value to this one causes the monitor switcher */
/* to flip to Amiga display */
2007-10-16 12:29:08 +04:00
assert ( cinfo - > regbase ! = NULL ) ;
2005-04-17 02:20:36 +04:00
cinfo - > SFR = val ;
2007-10-16 12:29:08 +04:00
z_writeb ( val , cinfo - > regbase + 0x9000 ) ;
2005-04-17 02:20:36 +04:00
# endif
}
/*** WClut - set CLUT entry (range: 0..63) ***/
2007-10-16 12:29:08 +04:00
static void WClut ( struct cirrusfb_info * cinfo , unsigned char regnum , unsigned char red ,
2005-04-17 02:20:36 +04:00
unsigned char green , unsigned char blue )
{
unsigned int data = VGA_PEL_D ;
/* address write mode register is not translated.. */
2007-10-16 12:29:08 +04:00
vga_w ( cinfo - > regbase , VGA_PEL_IW , regnum ) ;
2005-04-17 02:20:36 +04:00
if ( cinfo - > btype = = BT_PICASSO | | cinfo - > btype = = BT_PICASSO4 | |
cinfo - > btype = = BT_ALPINE | | cinfo - > btype = = BT_GD5480 ) {
/* but DAC data register IS, at least for Picasso II */
if ( cinfo - > btype = = BT_PICASSO )
data + = 0xfff ;
2007-10-16 12:29:08 +04:00
vga_w ( cinfo - > regbase , data , red ) ;
vga_w ( cinfo - > regbase , data , green ) ;
vga_w ( cinfo - > regbase , data , blue ) ;
2005-04-17 02:20:36 +04:00
} else {
2007-10-16 12:29:08 +04:00
vga_w ( cinfo - > regbase , data , blue ) ;
vga_w ( cinfo - > regbase , data , green ) ;
vga_w ( cinfo - > regbase , data , red ) ;
2005-04-17 02:20:36 +04:00
}
}
#if 0
/*** RClut - read CLUT entry (range 0..63) ***/
2007-10-16 12:29:08 +04:00
static void RClut ( struct cirrusfb_info * cinfo , unsigned char regnum , unsigned char * red ,
2005-04-17 02:20:36 +04:00
unsigned char * green , unsigned char * blue )
{
unsigned int data = VGA_PEL_D ;
2007-10-16 12:29:08 +04:00
vga_w ( cinfo - > regbase , VGA_PEL_IR , regnum ) ;
2005-04-17 02:20:36 +04:00
if ( cinfo - > btype = = BT_PICASSO | | cinfo - > btype = = BT_PICASSO4 | |
cinfo - > btype = = BT_ALPINE | | cinfo - > btype = = BT_GD5480 ) {
if ( cinfo - > btype = = BT_PICASSO )
data + = 0xfff ;
2007-10-16 12:29:08 +04:00
* red = vga_r ( cinfo - > regbase , data ) ;
* green = vga_r ( cinfo - > regbase , data ) ;
* blue = vga_r ( cinfo - > regbase , data ) ;
2005-04-17 02:20:36 +04:00
} else {
2007-10-16 12:29:08 +04:00
* blue = vga_r ( cinfo - > regbase , data ) ;
* green = vga_r ( cinfo - > regbase , data ) ;
* red = vga_r ( cinfo - > regbase , data ) ;
2005-04-17 02:20:36 +04:00
}
}
# endif
/*******************************************************************
cirrusfb_WaitBLT ( )
Wait for the BitBLT engine to complete a possible earlier job
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* FIXME: use interrupts instead */
2007-10-16 12:29:08 +04:00
static void cirrusfb_WaitBLT ( u8 __iomem * regbase )
2005-04-17 02:20:36 +04:00
{
/* now busy-wait until we're done */
2007-10-16 12:29:08 +04:00
while ( vga_rgfx ( regbase , CL_GR31 ) & 0x08 )
2005-04-17 02:20:36 +04:00
/* do nothing */ ;
}
/*******************************************************************
cirrusfb_BitBLT ( )
perform accelerated " scrolling "
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-16 12:29:08 +04:00
static void cirrusfb_BitBLT ( u8 __iomem * regbase , int bits_per_pixel ,
u_short curx , u_short cury ,
u_short destx , u_short desty ,
u_short width , u_short height ,
u_short line_length )
2005-04-17 02:20:36 +04:00
{
u_short nwidth , nheight ;
u_long nsrc , ndest ;
u_char bltmode ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
nwidth = width - 1 ;
nheight = height - 1 ;
bltmode = 0x00 ;
/* if source adr < dest addr, do the Blt backwards */
if ( cury < = desty ) {
if ( cury = = desty ) {
/* if src and dest are on the same line, check x */
if ( curx < destx )
bltmode | = 0x01 ;
} else
bltmode | = 0x01 ;
}
if ( ! bltmode ) {
/* standard case: forward blitting */
nsrc = ( cury * line_length ) + curx ;
ndest = ( desty * line_length ) + destx ;
} else {
2007-10-16 12:29:08 +04:00
/* this means start addresses are at the end,
* counting backwards
*/
nsrc = cury * line_length + curx +
nheight * line_length + nwidth ;
ndest = desty * line_length + destx +
nheight * line_length + nwidth ;
2005-04-17 02:20:36 +04:00
}
/*
run - down of registers to be programmed :
destination pitch
source pitch
BLT width / height
source start
destination start
BLT mode
BLT ROP
VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE : " fill color "
start / stop
*/
2007-10-16 12:29:08 +04:00
cirrusfb_WaitBLT ( regbase ) ;
2005-04-17 02:20:36 +04:00
/* pitch: set to line_length */
2007-10-16 12:29:08 +04:00
/* dest pitch low */
vga_wgfx ( regbase , CL_GR24 , line_length & 0xff ) ;
/* dest pitch hi */
vga_wgfx ( regbase , CL_GR25 , line_length > > 8 ) ;
/* source pitch low */
vga_wgfx ( regbase , CL_GR26 , line_length & 0xff ) ;
/* source pitch hi */
vga_wgfx ( regbase , CL_GR27 , line_length > > 8 ) ;
2005-04-17 02:20:36 +04:00
/* BLT width: actual number of pixels - 1 */
2007-10-16 12:29:08 +04:00
/* BLT width low */
vga_wgfx ( regbase , CL_GR20 , nwidth & 0xff ) ;
/* BLT width hi */
vga_wgfx ( regbase , CL_GR21 , nwidth > > 8 ) ;
2005-04-17 02:20:36 +04:00
/* BLT height: actual number of lines -1 */
2007-10-16 12:29:08 +04:00
/* BLT height low */
vga_wgfx ( regbase , CL_GR22 , nheight & 0xff ) ;
/* BLT width hi */
vga_wgfx ( regbase , CL_GR23 , nheight > > 8 ) ;
2005-04-17 02:20:36 +04:00
/* BLT destination */
2007-10-16 12:29:08 +04:00
/* BLT dest low */
vga_wgfx ( regbase , CL_GR28 , ( u_char ) ( ndest & 0xff ) ) ;
/* BLT dest mid */
vga_wgfx ( regbase , CL_GR29 , ( u_char ) ( ndest > > 8 ) ) ;
/* BLT dest hi */
vga_wgfx ( regbase , CL_GR2A , ( u_char ) ( ndest > > 16 ) ) ;
2005-04-17 02:20:36 +04:00
/* BLT source */
2007-10-16 12:29:08 +04:00
/* BLT src low */
vga_wgfx ( regbase , CL_GR2C , ( u_char ) ( nsrc & 0xff ) ) ;
/* BLT src mid */
vga_wgfx ( regbase , CL_GR2D , ( u_char ) ( nsrc > > 8 ) ) ;
/* BLT src hi */
vga_wgfx ( regbase , CL_GR2E , ( u_char ) ( nsrc > > 16 ) ) ;
2005-04-17 02:20:36 +04:00
/* BLT mode */
2007-10-16 12:29:08 +04:00
vga_wgfx ( regbase , CL_GR30 , bltmode ) ; /* BLT mode */
2005-04-17 02:20:36 +04:00
/* BLT ROP: SrcCopy */
2007-10-16 12:29:08 +04:00
vga_wgfx ( regbase , CL_GR32 , 0x0d ) ; /* BLT ROP */
2005-04-17 02:20:36 +04:00
/* and finally: GO! */
2007-10-16 12:29:08 +04:00
vga_wgfx ( regbase , CL_GR31 , 0x02 ) ; /* BLT Start/status */
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
/*******************************************************************
cirrusfb_RectFill ( )
perform accelerated rectangle fill
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-16 12:29:08 +04:00
static void cirrusfb_RectFill ( u8 __iomem * regbase , int bits_per_pixel ,
2005-04-17 02:20:36 +04:00
u_short x , u_short y , u_short width , u_short height ,
u_char color , u_short line_length )
{
u_short nwidth , nheight ;
u_long ndest ;
u_char op ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
nwidth = width - 1 ;
nheight = height - 1 ;
ndest = ( y * line_length ) + x ;
2007-10-16 12:29:08 +04:00
cirrusfb_WaitBLT ( regbase ) ;
2005-04-17 02:20:36 +04:00
/* pitch: set to line_length */
2007-10-16 12:29:08 +04:00
vga_wgfx ( regbase , CL_GR24 , line_length & 0xff ) ; /* dest pitch low */
vga_wgfx ( regbase , CL_GR25 , line_length > > 8 ) ; /* dest pitch hi */
vga_wgfx ( regbase , CL_GR26 , line_length & 0xff ) ; /* source pitch low */
vga_wgfx ( regbase , CL_GR27 , line_length > > 8 ) ; /* source pitch hi */
2005-04-17 02:20:36 +04:00
/* BLT width: actual number of pixels - 1 */
2007-10-16 12:29:08 +04:00
vga_wgfx ( regbase , CL_GR20 , nwidth & 0xff ) ; /* BLT width low */
vga_wgfx ( regbase , CL_GR21 , nwidth > > 8 ) ; /* BLT width hi */
2005-04-17 02:20:36 +04:00
/* BLT height: actual number of lines -1 */
2007-10-16 12:29:08 +04:00
vga_wgfx ( regbase , CL_GR22 , nheight & 0xff ) ; /* BLT height low */
vga_wgfx ( regbase , CL_GR23 , nheight > > 8 ) ; /* BLT width hi */
2005-04-17 02:20:36 +04:00
/* BLT destination */
2007-10-16 12:29:08 +04:00
/* BLT dest low */
vga_wgfx ( regbase , CL_GR28 , ( u_char ) ( ndest & 0xff ) ) ;
/* BLT dest mid */
vga_wgfx ( regbase , CL_GR29 , ( u_char ) ( ndest > > 8 ) ) ;
/* BLT dest hi */
vga_wgfx ( regbase , CL_GR2A , ( u_char ) ( ndest > > 16 ) ) ;
2005-04-17 02:20:36 +04:00
/* BLT source: set to 0 (is a dummy here anyway) */
2007-10-16 12:29:08 +04:00
vga_wgfx ( regbase , CL_GR2C , 0x00 ) ; /* BLT src low */
vga_wgfx ( regbase , CL_GR2D , 0x00 ) ; /* BLT src mid */
vga_wgfx ( regbase , CL_GR2E , 0x00 ) ; /* BLT src hi */
2005-04-17 02:20:36 +04:00
/* This is a ColorExpand Blt, using the */
/* same color for foreground and background */
2007-10-16 12:29:08 +04:00
vga_wgfx ( regbase , VGA_GFX_SR_VALUE , color ) ; /* foreground color */
vga_wgfx ( regbase , VGA_GFX_SR_ENABLE , color ) ; /* background color */
2005-04-17 02:20:36 +04:00
op = 0xc0 ;
if ( bits_per_pixel = = 16 ) {
2007-10-16 12:29:08 +04:00
vga_wgfx ( regbase , CL_GR10 , color ) ; /* foreground color */
vga_wgfx ( regbase , CL_GR11 , color ) ; /* background color */
2005-04-17 02:20:36 +04:00
op = 0x50 ;
op = 0xd0 ;
} else if ( bits_per_pixel = = 32 ) {
2007-10-16 12:29:08 +04:00
vga_wgfx ( regbase , CL_GR10 , color ) ; /* foreground color */
vga_wgfx ( regbase , CL_GR11 , color ) ; /* background color */
vga_wgfx ( regbase , CL_GR12 , color ) ; /* foreground color */
vga_wgfx ( regbase , CL_GR13 , color ) ; /* background color */
vga_wgfx ( regbase , CL_GR14 , 0 ) ; /* foreground color */
vga_wgfx ( regbase , CL_GR15 , 0 ) ; /* background color */
2005-04-17 02:20:36 +04:00
op = 0x50 ;
op = 0xf0 ;
}
/* BLT mode: color expand, Enable 8x8 copy (faster?) */
2007-10-16 12:29:08 +04:00
vga_wgfx ( regbase , CL_GR30 , op ) ; /* BLT mode */
2005-04-17 02:20:36 +04:00
/* BLT ROP: SrcCopy */
2007-10-16 12:29:08 +04:00
vga_wgfx ( regbase , CL_GR32 , 0x0d ) ; /* BLT ROP */
2005-04-17 02:20:36 +04:00
/* and finally: GO! */
2007-10-16 12:29:08 +04:00
vga_wgfx ( regbase , CL_GR31 , 0x02 ) ; /* BLT Start/status */
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
/**************************************************************************
* bestclock ( ) - determine closest possible clock lower ( ? ) than the
* desired pixel clock
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-16 12:29:08 +04:00
static void bestclock ( long freq , long * best , long * nom ,
2005-04-17 02:20:36 +04:00
long * den , long * div , long maxfreq )
{
long n , h , d , f ;
2007-10-16 12:29:08 +04:00
assert ( best ! = NULL ) ;
assert ( nom ! = NULL ) ;
assert ( den ! = NULL ) ;
assert ( div ! = NULL ) ;
assert ( maxfreq > 0 ) ;
2005-04-17 02:20:36 +04:00
* nom = 0 ;
* den = 0 ;
* div = 0 ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " ENTER \n " ) ;
2005-04-17 02:20:36 +04:00
if ( freq < 8000 )
freq = 8000 ;
if ( freq > maxfreq )
freq = maxfreq ;
* best = 0 ;
f = freq * 10 ;
for ( n = 32 ; n < 128 ; n + + ) {
d = ( 143181 * n ) / f ;
if ( ( d > = 7 ) & & ( d < = 63 ) ) {
if ( d > 31 )
d = ( d / 2 ) * 2 ;
h = ( 14318 * n ) / d ;
2007-10-16 12:29:08 +04:00
if ( abs ( h - freq ) < abs ( * best - freq ) ) {
2005-04-17 02:20:36 +04:00
* best = h ;
* nom = n ;
if ( d < 32 ) {
* den = d ;
* div = 0 ;
} else {
* den = d / 2 ;
* div = 1 ;
}
}
}
d = ( ( 143181 * n ) + f - 1 ) / f ;
if ( ( d > = 7 ) & & ( d < = 63 ) ) {
if ( d > 31 )
d = ( d / 2 ) * 2 ;
h = ( 14318 * n ) / d ;
2007-10-16 12:29:08 +04:00
if ( abs ( h - freq ) < abs ( * best - freq ) ) {
2005-04-17 02:20:36 +04:00
* best = h ;
* nom = n ;
if ( d < 32 ) {
* den = d ;
* div = 0 ;
} else {
* den = d / 2 ;
* div = 1 ;
}
}
}
}
2007-10-16 12:29:08 +04:00
DPRINTK ( " Best possible values for given frequency: \n " ) ;
DPRINTK ( " best: %ld kHz nom: %ld den: %ld div: %ld \n " ,
freq , * nom , * den , * div ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
}
/* -------------------------------------------------------------------------
*
* debugging functions
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
# ifdef CIRRUSFB_DEBUG
/**
* cirrusfb_dbg_print_byte
* @ name : name associated with byte value to be displayed
* @ val : byte value to be displayed
*
* DESCRIPTION :
* Display an indented string , along with a hexidecimal byte value , and
* its decoded bits . Bits 7 through 0 are listed in left - to - right
* order .
*/
static
2007-10-16 12:29:08 +04:00
void cirrusfb_dbg_print_byte ( const char * name , unsigned char val )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:29:08 +04:00
DPRINTK ( " %8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c) \n " ,
name , val ,
val & 0x80 ? ' 1 ' : ' 0 ' ,
val & 0x40 ? ' 1 ' : ' 0 ' ,
val & 0x20 ? ' 1 ' : ' 0 ' ,
val & 0x10 ? ' 1 ' : ' 0 ' ,
val & 0x08 ? ' 1 ' : ' 0 ' ,
val & 0x04 ? ' 1 ' : ' 0 ' ,
val & 0x02 ? ' 1 ' : ' 0 ' ,
val & 0x01 ? ' 1 ' : ' 0 ' ) ;
2005-04-17 02:20:36 +04:00
}
/**
* cirrusfb_dbg_print_regs
* @ base : If using newmmio , the newmmio base address , otherwise % NULL
* @ reg_class : type of registers to read : % CRT , or % SEQ
*
* DESCRIPTION :
* Dumps the given list of VGA CRTC registers . If @ base is % NULL ,
* old - style I / O ports are queried for information , otherwise MMIO is
* used at the given @ base address to query the information .
*/
static
2007-10-16 12:29:08 +04:00
void cirrusfb_dbg_print_regs ( caddr_t regbase ,
2007-10-16 12:29:11 +04:00
enum cirrusfb_dbg_reg_class reg_class , . . . )
2005-04-17 02:20:36 +04:00
{
va_list list ;
unsigned char val = 0 ;
unsigned reg ;
char * name ;
2007-10-16 12:29:08 +04:00
va_start ( list , reg_class ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
name = va_arg ( list , char * ) ;
2005-04-17 02:20:36 +04:00
while ( name ! = NULL ) {
2007-10-16 12:29:08 +04:00
reg = va_arg ( list , int ) ;
2005-04-17 02:20:36 +04:00
switch ( reg_class ) {
case CRT :
2007-10-16 12:29:08 +04:00
val = vga_rcrt ( regbase , ( unsigned char ) reg ) ;
2005-04-17 02:20:36 +04:00
break ;
case SEQ :
2007-10-16 12:29:08 +04:00
val = vga_rseq ( regbase , ( unsigned char ) reg ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
/* should never occur */
2007-05-08 11:38:29 +04:00
assert ( false ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2007-10-16 12:29:08 +04:00
cirrusfb_dbg_print_byte ( name , val ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
name = va_arg ( list , char * ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:29:08 +04:00
va_end ( list ) ;
2005-04-17 02:20:36 +04:00
}
/**
* cirrusfb_dump
* @ cirrusfbinfo :
*
* DESCRIPTION :
*/
2007-10-16 12:29:08 +04:00
static void cirrusfb_dump ( void )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:29:08 +04:00
cirrusfb_dbg_reg_dump ( NULL ) ;
2005-04-17 02:20:36 +04:00
}
/**
* cirrusfb_dbg_reg_dump
* @ base : If using newmmio , the newmmio base address , otherwise % NULL
*
* DESCRIPTION :
* Dumps a list of interesting VGA and CIRRUSFB registers . If @ base is % NULL ,
* old - style I / O ports are queried for information , otherwise MMIO is
* used at the given @ base address to query the information .
*/
static
2007-10-16 12:29:08 +04:00
void cirrusfb_dbg_reg_dump ( caddr_t regbase )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:29:08 +04:00
DPRINTK ( " CIRRUSFB VGA CRTC register dump: \n " ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
cirrusfb_dbg_print_regs ( regbase , CRT ,
2005-04-17 02:20:36 +04:00
" CR00 " , 0x00 ,
" CR01 " , 0x01 ,
" CR02 " , 0x02 ,
" CR03 " , 0x03 ,
" CR04 " , 0x04 ,
" CR05 " , 0x05 ,
" CR06 " , 0x06 ,
" CR07 " , 0x07 ,
" CR08 " , 0x08 ,
" CR09 " , 0x09 ,
" CR0A " , 0x0A ,
" CR0B " , 0x0B ,
" CR0C " , 0x0C ,
" CR0D " , 0x0D ,
" CR0E " , 0x0E ,
" CR0F " , 0x0F ,
" CR10 " , 0x10 ,
" CR11 " , 0x11 ,
" CR12 " , 0x12 ,
" CR13 " , 0x13 ,
" CR14 " , 0x14 ,
" CR15 " , 0x15 ,
" CR16 " , 0x16 ,
" CR17 " , 0x17 ,
" CR18 " , 0x18 ,
" CR22 " , 0x22 ,
" CR24 " , 0x24 ,
" CR26 " , 0x26 ,
" CR2D " , 0x2D ,
" CR2E " , 0x2E ,
" CR2F " , 0x2F ,
" CR30 " , 0x30 ,
" CR31 " , 0x31 ,
" CR32 " , 0x32 ,
" CR33 " , 0x33 ,
" CR34 " , 0x34 ,
" CR35 " , 0x35 ,
" CR36 " , 0x36 ,
" CR37 " , 0x37 ,
" CR38 " , 0x38 ,
" CR39 " , 0x39 ,
" CR3A " , 0x3A ,
" CR3B " , 0x3B ,
" CR3C " , 0x3C ,
" CR3D " , 0x3D ,
" CR3E " , 0x3E ,
" CR3F " , 0x3F ,
NULL ) ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " \n " ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
DPRINTK ( " CIRRUSFB VGA SEQ register dump: \n " ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:29:08 +04:00
cirrusfb_dbg_print_regs ( regbase , SEQ ,
2005-04-17 02:20:36 +04:00
" SR00 " , 0x00 ,
" SR01 " , 0x01 ,
" SR02 " , 0x02 ,
" SR03 " , 0x03 ,
" SR04 " , 0x04 ,
" SR08 " , 0x08 ,
" SR09 " , 0x09 ,
" SR0A " , 0x0A ,
" SR0B " , 0x0B ,
" SR0D " , 0x0D ,
" SR10 " , 0x10 ,
" SR11 " , 0x11 ,
" SR12 " , 0x12 ,
" SR13 " , 0x13 ,
" SR14 " , 0x14 ,
" SR15 " , 0x15 ,
" SR16 " , 0x16 ,
" SR17 " , 0x17 ,
" SR18 " , 0x18 ,
" SR19 " , 0x19 ,
" SR1A " , 0x1A ,
" SR1B " , 0x1B ,
" SR1C " , 0x1C ,
" SR1D " , 0x1D ,
" SR1E " , 0x1E ,
" SR1F " , 0x1F ,
NULL ) ;
2007-10-16 12:29:08 +04:00
DPRINTK ( " \n " ) ;
2005-04-17 02:20:36 +04:00
}
# endif /* CIRRUSFB_DEBUG */