2005-04-17 02:20:36 +04:00
/*
* linux / drivers / video / atafb . c - - Atari builtin chipset frame buffer device
*
* Copyright ( C ) 1994 Martin Schaller & Roman Hodek
2007-05-02 00:32:39 +04:00
*
2005-04-17 02:20:36 +04:00
* 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 .
*
* History :
* - 03 Jan 95 : Original version by Martin Schaller : The TT driver and
* all the device independent stuff
* - 09 Jan 95 : Roman : I ' ve added the hardware abstraction ( hw_switch )
* and wrote the Falcon , ST ( E ) , and External drivers
* based on the original TT driver .
* - 07 May 95 : Martin : Added colormap operations for the external driver
* - 21 May 95 : Martin : Added support for overscan
* Andreas : some bug fixes for this
* - Jul 95 : Guenther Kelleter < guenther @ pool . informatik . rwth - aachen . de > :
* Programmable Falcon video modes
* ( thanks to Christian Cartus for documentation
* of VIDEL registers ) .
* - 27 Dec 95 : Guenther : Implemented user definable video modes " user[0-7] "
* on minor 24. . .31 . " user0 " may be set on commandline by
* " R<x>;<y>;<depth> " . ( Makes sense only on Falcon )
* Video mode switch on Falcon now done at next VBL interrupt
* to avoid the annoying right shift of the screen .
* - 23 Sep 97 : Juergen : added xres_virtual for cards like ProMST
* The external - part is legacy , therefore hardware - specific
* functions like panning / hardwarescrolling / blanking isn ' t
* supported .
* - 29 Sep 97 : Juergen : added Romans suggestion for pan_display
* ( var - > xoffset was changed even if no set_screen_base avail . )
* - 05 Oct 97 : Juergen : extfb ( PACKED_PIXEL ) is FB_PSEUDOCOLOR ' cause
* we know how to set the colors
* ext_ * palette : read from ext_colors ( former MV300_colors )
* write to ext_colors and RAMDAC
*
* To do :
* - For the Falcon it is not possible to set random video modes on
* SM124 and SC / TV , only the bootup resolution is supported .
*
*/
# define ATAFB_TT
# define ATAFB_STE
# define ATAFB_EXT
# define ATAFB_FALCON
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/string.h>
# include <linux/mm.h>
# include <linux/delay.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <asm/setup.h>
2007-10-16 12:29:04 +04:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <asm/pgtable.h>
# include <asm/irq.h>
# include <asm/io.h>
# include <asm/atarihw.h>
# include <asm/atariints.h>
# include <asm/atari_stram.h>
# include <linux/fb.h>
# include <asm/atarikb.h>
2007-05-02 00:32:39 +04:00
# include "c2p.h"
# include "atafb.h"
2005-04-17 02:20:36 +04:00
# define SWITCH_ACIA 0x01 /* modes for switch on OverScan */
# define SWITCH_SND6 0x40
# define SWITCH_SND7 0x80
# define SWITCH_NONE 0x00
# define up(x, r) (((x) + (r) - 1) & ~((r)-1))
2007-05-02 00:32:39 +04:00
/*
* Interface to the world
*/
static int atafb_check_var ( struct fb_var_screeninfo * var , struct fb_info * info ) ;
static int atafb_set_par ( struct fb_info * info ) ;
static int atafb_setcolreg ( unsigned int regno , unsigned int red , unsigned int green ,
unsigned int blue , unsigned int transp ,
struct fb_info * info ) ;
static int atafb_blank ( int blank , struct fb_info * info ) ;
static int atafb_pan_display ( struct fb_var_screeninfo * var ,
struct fb_info * info ) ;
static void atafb_fillrect ( struct fb_info * info ,
const struct fb_fillrect * rect ) ;
static void atafb_copyarea ( struct fb_info * info ,
const struct fb_copyarea * region ) ;
static void atafb_imageblit ( struct fb_info * info , const struct fb_image * image ) ;
static int atafb_ioctl ( struct fb_info * info , unsigned int cmd ,
unsigned long arg ) ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
static int default_par ; /* default resolution (0=none) */
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
static unsigned long default_mem_req ;
static int hwscroll = - 1 ;
2005-04-17 02:20:36 +04:00
static int use_hwscroll = 1 ;
2007-05-02 00:32:39 +04:00
static int sttt_xres = 640 , st_yres = 400 , tt_yres = 480 ;
static int sttt_xres_virtual = 640 , sttt_yres_virtual = 400 ;
static int ovsc_offset , ovsc_addlen ;
/*
* Hardware parameters for current mode
*/
2005-04-17 02:20:36 +04:00
static struct atafb_par {
void * screen_base ;
int yres_virtual ;
2007-05-02 00:32:39 +04:00
u_long next_line ;
2005-04-17 02:20:36 +04:00
# if defined ATAFB_TT || defined ATAFB_STE
union {
struct {
int mode ;
int sync ;
} tt , st ;
# endif
# ifdef ATAFB_FALCON
struct falcon_hw {
/* Here are fields for storing a video mode, as direct
* parameters for the hardware .
*/
short sync ;
short line_width ;
short line_offset ;
short st_shift ;
short f_shift ;
short vid_control ;
short vid_mode ;
short xoffset ;
short hht , hbb , hbe , hdb , hde , hss ;
short vft , vbb , vbe , vdb , vde , vss ;
/* auxiliary information */
short mono ;
short ste_mode ;
short bpp ;
2008-11-18 23:13:01 +03:00
u32 pseudo_palette [ 16 ] ;
2005-04-17 02:20:36 +04:00
} falcon ;
# endif
/* Nothing needed for external mode */
} hw ;
} current_par ;
/* Don't calculate an own resolution, and thus don't change the one found when
* booting ( currently used for the Falcon to keep settings for internal video
* hardware extensions ( e . g . ScreenBlaster ) */
2007-05-02 00:32:39 +04:00
static int DontCalcRes = 0 ;
2005-04-17 02:20:36 +04:00
# ifdef ATAFB_FALCON
# define HHT hw.falcon.hht
# define HBB hw.falcon.hbb
# define HBE hw.falcon.hbe
# define HDB hw.falcon.hdb
# define HDE hw.falcon.hde
# define HSS hw.falcon.hss
# define VFT hw.falcon.vft
# define VBB hw.falcon.vbb
# define VBE hw.falcon.vbe
# define VDB hw.falcon.vdb
# define VDE hw.falcon.vde
# define VSS hw.falcon.vss
# define VCO_CLOCK25 0x04
# define VCO_CSYPOS 0x10
# define VCO_VSYPOS 0x20
# define VCO_HSYPOS 0x40
# define VCO_SHORTOFFS 0x100
# define VMO_DOUBLE 0x01
# define VMO_INTER 0x02
# define VMO_PREMASK 0x0c
# endif
2007-05-02 00:32:39 +04:00
static struct fb_info fb_info = {
. fix = {
. id = " Atari " ,
. visual = FB_VISUAL_PSEUDOCOLOR ,
. accel = FB_ACCEL_NONE ,
}
} ;
2005-04-17 02:20:36 +04:00
static void * screen_base ; /* base address of screen */
static void * real_screen_base ; /* (only for Overscan) */
static int screen_len ;
2007-05-02 00:32:39 +04:00
static int current_par_valid ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
static int mono_moni ;
2005-04-17 02:20:36 +04:00
# ifdef ATAFB_EXT
2007-05-02 00:32:39 +04:00
/* external video handling */
static unsigned int external_xres ;
static unsigned int external_xres_virtual ;
static unsigned int external_yres ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
/*
* not needed - atafb will never support panning / hardwarescroll with external
* static unsigned int external_yres_virtual ;
*/
static unsigned int external_depth ;
static int external_pmode ;
static void * external_addr ;
static unsigned long external_len ;
static unsigned long external_vgaiobase ;
static unsigned int external_bitspercol = 6 ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
/*
* JOE < joe @ amber . dinoco . de > :
* added card type for external driver , is only needed for
* colormap handling .
*/
2005-04-17 02:20:36 +04:00
enum cardtype { IS_VGA , IS_MV300 } ;
static enum cardtype external_card_type = IS_VGA ;
/*
2007-05-02 00:32:39 +04:00
* The MV300 mixes the color registers . So we need an array of munged
* indices in order to access the correct reg .
*/
static int MV300_reg_1bit [ 2 ] = {
0 , 1
} ;
static int MV300_reg_4bit [ 16 ] = {
0 , 8 , 4 , 12 , 2 , 10 , 6 , 14 , 1 , 9 , 5 , 13 , 3 , 11 , 7 , 15
} ;
static int MV300_reg_8bit [ 256 ] = {
0 , 128 , 64 , 192 , 32 , 160 , 96 , 224 , 16 , 144 , 80 , 208 , 48 , 176 , 112 , 240 ,
8 , 136 , 72 , 200 , 40 , 168 , 104 , 232 , 24 , 152 , 88 , 216 , 56 , 184 , 120 , 248 ,
4 , 132 , 68 , 196 , 36 , 164 , 100 , 228 , 20 , 148 , 84 , 212 , 52 , 180 , 116 , 244 ,
12 , 140 , 76 , 204 , 44 , 172 , 108 , 236 , 28 , 156 , 92 , 220 , 60 , 188 , 124 , 252 ,
2 , 130 , 66 , 194 , 34 , 162 , 98 , 226 , 18 , 146 , 82 , 210 , 50 , 178 , 114 , 242 ,
10 , 138 , 74 , 202 , 42 , 170 , 106 , 234 , 26 , 154 , 90 , 218 , 58 , 186 , 122 , 250 ,
6 , 134 , 70 , 198 , 38 , 166 , 102 , 230 , 22 , 150 , 86 , 214 , 54 , 182 , 118 , 246 ,
14 , 142 , 78 , 206 , 46 , 174 , 110 , 238 , 30 , 158 , 94 , 222 , 62 , 190 , 126 , 254 ,
1 , 129 , 65 , 193 , 33 , 161 , 97 , 225 , 17 , 145 , 81 , 209 , 49 , 177 , 113 , 241 ,
9 , 137 , 73 , 201 , 41 , 169 , 105 , 233 , 25 , 153 , 89 , 217 , 57 , 185 , 121 , 249 ,
5 , 133 , 69 , 197 , 37 , 165 , 101 , 229 , 21 , 149 , 85 , 213 , 53 , 181 , 117 , 245 ,
13 , 141 , 77 , 205 , 45 , 173 , 109 , 237 , 29 , 157 , 93 , 221 , 61 , 189 , 125 , 253 ,
3 , 131 , 67 , 195 , 35 , 163 , 99 , 227 , 19 , 147 , 83 , 211 , 51 , 179 , 115 , 243 ,
11 , 139 , 75 , 203 , 43 , 171 , 107 , 235 , 27 , 155 , 91 , 219 , 59 , 187 , 123 , 251 ,
7 , 135 , 71 , 199 , 39 , 167 , 103 , 231 , 23 , 151 , 87 , 215 , 55 , 183 , 119 , 247 ,
15 , 143 , 79 , 207 , 47 , 175 , 111 , 239 , 31 , 159 , 95 , 223 , 63 , 191 , 127 , 255
} ;
2005-04-17 02:20:36 +04:00
static int * MV300_reg = MV300_reg_8bit ;
# endif /* ATAFB_EXT */
2007-05-02 00:32:39 +04:00
static int inverse ;
2005-04-17 02:20:36 +04:00
extern int fontheight_8x8 ;
extern int fontwidth_8x8 ;
extern unsigned char fontdata_8x8 [ ] ;
extern int fontheight_8x16 ;
extern int fontwidth_8x16 ;
extern unsigned char fontdata_8x16 [ ] ;
2007-05-02 00:32:39 +04:00
/*
* struct fb_ops {
* * open / release and usage marking
* struct module * owner ;
* int ( * fb_open ) ( struct fb_info * info , int user ) ;
* int ( * fb_release ) ( struct fb_info * info , int user ) ;
*
* * For framebuffers with strange non linear layouts or that do not
* * work with normal memory mapped access
* ssize_t ( * fb_read ) ( struct file * file , char __user * buf , size_t count , loff_t * ppos ) ;
* ssize_t ( * fb_write ) ( struct file * file , const char __user * buf , size_t count , loff_t * ppos ) ;
*
* * checks var and eventually tweaks it to something supported ,
* * DOES NOT MODIFY PAR *
* int ( * fb_check_var ) ( struct fb_var_screeninfo * var , struct fb_info * info ) ;
*
* * set the video mode according to info - > var *
* int ( * fb_set_par ) ( struct fb_info * info ) ;
*
* * set color register *
* int ( * fb_setcolreg ) ( unsigned int regno , unsigned int red , unsigned int green ,
* unsigned int blue , unsigned int transp , struct fb_info * info ) ;
*
* * set color registers in batch *
* int ( * fb_setcmap ) ( struct fb_cmap * cmap , struct fb_info * info ) ;
*
* * blank display *
* int ( * fb_blank ) ( int blank , struct fb_info * info ) ;
*
* * pan display *
* int ( * fb_pan_display ) ( struct fb_var_screeninfo * var , struct fb_info * info ) ;
*
* * * * The meat of the drawing engine * * *
* * Draws a rectangle *
* void ( * fb_fillrect ) ( struct fb_info * info , const struct fb_fillrect * rect ) ;
* * Copy data from area to another *
* void ( * fb_copyarea ) ( struct fb_info * info , const struct fb_copyarea * region ) ;
* * Draws a image to the display *
* void ( * fb_imageblit ) ( struct fb_info * info , const struct fb_image * image ) ;
*
* * Draws cursor *
* int ( * fb_cursor ) ( struct fb_info * info , struct fb_cursor * cursor ) ;
*
* * Rotates the display *
* void ( * fb_rotate ) ( struct fb_info * info , int angle ) ;
*
* * wait for blit idle , optional *
* int ( * fb_sync ) ( struct fb_info * info ) ;
*
* * perform fb specific ioctl ( optional ) *
* int ( * fb_ioctl ) ( struct fb_info * info , unsigned int cmd ,
* unsigned long arg ) ;
*
* * Handle 32 bit compat ioctl ( optional ) *
* int ( * fb_compat_ioctl ) ( struct fb_info * info , unsigned int cmd ,
* unsigned long arg ) ;
*
* * perform fb specific mmap *
* int ( * fb_mmap ) ( struct fb_info * info , struct vm_area_struct * vma ) ;
* } ;
*/
2005-04-17 02:20:36 +04:00
/* ++roman: This structure abstracts from the underlying hardware (ST(e),
* TT , or Falcon .
*
2007-05-02 00:32:39 +04:00
* int ( * detect ) ( void )
2005-04-17 02:20:36 +04:00
* This function should detect the current video mode settings and
* store them in atafb_predefined [ 0 ] for later reference by the
* user . Return the index + 1 of an equivalent predefined mode or 0
* if there is no such .
2007-05-02 00:32:39 +04:00
*
* int ( * encode_fix ) ( struct fb_fix_screeninfo * fix ,
* struct atafb_par * par )
2005-04-17 02:20:36 +04:00
* This function should fill in the ' fix ' structure based on the
* values in the ' par ' structure .
2007-05-02 00:32:39 +04:00
* ! ! ! Obsolete , perhaps ! ! !
*
* int ( * decode_var ) ( struct fb_var_screeninfo * var ,
* struct atafb_par * par )
2005-04-17 02:20:36 +04:00
* Get the video params out of ' var ' . If a value doesn ' t fit , round
* it up , if it ' s too big , return EINVAL .
2007-05-02 00:32:39 +04:00
* Round up in the following order : bits_per_pixel , xres , yres ,
* xres_virtual , yres_virtual , xoffset , yoffset , grayscale , bitfields ,
2005-04-17 02:20:36 +04:00
* horizontal timing , vertical timing .
*
2007-05-02 00:32:39 +04:00
* int ( * encode_var ) ( struct fb_var_screeninfo * var ,
* struct atafb_par * par ) ;
2005-04-17 02:20:36 +04:00
* Fill the ' var ' structure based on the values in ' par ' and maybe
* other values read out of the hardware .
2007-05-02 00:32:39 +04:00
*
* void ( * get_par ) ( struct atafb_par * par )
2005-04-17 02:20:36 +04:00
* Fill the hardware ' s ' par ' structure .
2007-05-02 00:32:39 +04:00
* ! ! ! Used only by detect ( ) ! ! !
*
* void ( * set_par ) ( struct atafb_par * par )
2005-04-17 02:20:36 +04:00
* Set the hardware according to ' par ' .
*
* void ( * set_screen_base ) ( void * s_base )
* Set the base address of the displayed frame buffer . Only called
* if yres_virtual > yres or xres_virtual > xres .
*
2007-05-02 00:32:39 +04:00
* int ( * blank ) ( int blank_mode )
* Blank the screen if blank_mode ! = 0 , else unblank . If blank = = NULL then
2005-04-17 02:20:36 +04:00
* the caller blanks by setting the CLUT 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 :
2007-05-02 00:32:39 +04:00
* blank_mode = = 2 : suspend vsync , 3 : suspend hsync , 4 : powerdown .
2005-04-17 02:20:36 +04:00
*/
static struct fb_hwswitch {
2007-05-02 00:32:39 +04:00
int ( * detect ) ( void ) ;
int ( * encode_fix ) ( struct fb_fix_screeninfo * fix ,
struct atafb_par * par ) ;
int ( * decode_var ) ( struct fb_var_screeninfo * var ,
struct atafb_par * par ) ;
int ( * encode_var ) ( struct fb_var_screeninfo * var ,
struct atafb_par * par ) ;
void ( * get_par ) ( struct atafb_par * par ) ;
void ( * set_par ) ( struct atafb_par * par ) ;
2005-04-17 02:20:36 +04:00
void ( * set_screen_base ) ( void * s_base ) ;
2007-05-02 00:32:39 +04:00
int ( * blank ) ( int blank_mode ) ;
int ( * pan_display ) ( struct fb_var_screeninfo * var ,
struct fb_info * info ) ;
2005-04-17 02:20:36 +04:00
} * fbhw ;
2007-05-02 00:32:39 +04:00
static char * autodetect_names [ ] = { " autodetect " , NULL } ;
static char * stlow_names [ ] = { " stlow " , NULL } ;
static char * stmid_names [ ] = { " stmid " , " default5 " , NULL } ;
static char * sthigh_names [ ] = { " sthigh " , " default4 " , NULL } ;
static char * ttlow_names [ ] = { " ttlow " , NULL } ;
static char * ttmid_names [ ] = { " ttmid " , " default1 " , NULL } ;
static char * tthigh_names [ ] = { " tthigh " , " default2 " , NULL } ;
static char * vga2_names [ ] = { " vga2 " , NULL } ;
static char * vga4_names [ ] = { " vga4 " , NULL } ;
static char * vga16_names [ ] = { " vga16 " , " default3 " , NULL } ;
static char * vga256_names [ ] = { " vga256 " , NULL } ;
static char * falh2_names [ ] = { " falh2 " , NULL } ;
static char * falh16_names [ ] = { " falh16 " , NULL } ;
2005-04-17 02:20:36 +04:00
static char * * fb_var_names [ ] = {
autodetect_names ,
stlow_names ,
stmid_names ,
sthigh_names ,
ttlow_names ,
ttmid_names ,
tthigh_names ,
vga2_names ,
vga4_names ,
vga16_names ,
vga256_names ,
falh2_names ,
falh16_names ,
NULL
} ;
static struct fb_var_screeninfo atafb_predefined [ ] = {
2007-05-02 00:32:39 +04:00
/*
* yres_virtual = = 0 means use hw - scrolling if possible , else yres
*/
{ /* autodetect */
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , /* xres-grayscale */
{ 0 , 0 , 0 } , { 0 , 0 , 0 } , { 0 , 0 , 0 } , { 0 , 0 , 0 } , /* red green blue tran*/
2005-04-17 02:20:36 +04:00
0 , 0 , - 1 , - 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
2007-05-02 00:32:39 +04:00
{ /* st low */
2005-04-17 02:20:36 +04:00
320 , 200 , 320 , 0 , 0 , 0 , 4 , 0 ,
{ 0 , 4 , 0 } , { 0 , 4 , 0 } , { 0 , 4 , 0 } , { 0 , 0 , 0 } ,
0 , 0 , - 1 , - 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ /* st mid */
640 , 200 , 640 , 0 , 0 , 0 , 2 , 0 ,
{ 0 , 4 , 0 } , { 0 , 4 , 0 } , { 0 , 4 , 0 } , { 0 , 0 , 0 } ,
0 , 0 , - 1 , - 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ /* st high */
640 , 400 , 640 , 0 , 0 , 0 , 1 , 0 ,
{ 0 , 4 , 0 } , { 0 , 4 , 0 } , { 0 , 4 , 0 } , { 0 , 0 , 0 } ,
0 , 0 , - 1 , - 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ /* tt low */
320 , 480 , 320 , 0 , 0 , 0 , 8 , 0 ,
{ 0 , 4 , 0 } , { 0 , 4 , 0 } , { 0 , 4 , 0 } , { 0 , 0 , 0 } ,
0 , 0 , - 1 , - 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ /* tt mid */
640 , 480 , 640 , 0 , 0 , 0 , 4 , 0 ,
{ 0 , 4 , 0 } , { 0 , 4 , 0 } , { 0 , 4 , 0 } , { 0 , 0 , 0 } ,
0 , 0 , - 1 , - 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ /* tt high */
1280 , 960 , 1280 , 0 , 0 , 0 , 1 , 0 ,
{ 0 , 4 , 0 } , { 0 , 4 , 0 } , { 0 , 4 , 0 } , { 0 , 0 , 0 } ,
0 , 0 , - 1 , - 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ /* vga2 */
640 , 480 , 640 , 0 , 0 , 0 , 1 , 0 ,
{ 0 , 6 , 0 } , { 0 , 6 , 0 } , { 0 , 6 , 0 } , { 0 , 0 , 0 } ,
0 , 0 , - 1 , - 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ /* vga4 */
640 , 480 , 640 , 0 , 0 , 0 , 2 , 0 ,
{ 0 , 4 , 0 } , { 0 , 4 , 0 } , { 0 , 4 , 0 } , { 0 , 0 , 0 } ,
0 , 0 , - 1 , - 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ /* vga16 */
640 , 480 , 640 , 0 , 0 , 0 , 4 , 0 ,
{ 0 , 6 , 0 } , { 0 , 6 , 0 } , { 0 , 6 , 0 } , { 0 , 0 , 0 } ,
0 , 0 , - 1 , - 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ /* vga256 */
640 , 480 , 640 , 0 , 0 , 0 , 8 , 0 ,
{ 0 , 6 , 0 } , { 0 , 6 , 0 } , { 0 , 6 , 0 } , { 0 , 0 , 0 } ,
0 , 0 , - 1 , - 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ /* falh2 */
896 , 608 , 896 , 0 , 0 , 0 , 1 , 0 ,
{ 0 , 6 , 0 } , { 0 , 6 , 0 } , { 0 , 6 , 0 } , { 0 , 0 , 0 } ,
0 , 0 , - 1 , - 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
{ /* falh16 */
896 , 608 , 896 , 0 , 0 , 0 , 4 , 0 ,
{ 0 , 6 , 0 } , { 0 , 6 , 0 } , { 0 , 6 , 0 } , { 0 , 0 , 0 } ,
0 , 0 , - 1 , - 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ,
} ;
2007-05-02 00:32:39 +04:00
static int num_atafb_predefined = ARRAY_SIZE ( atafb_predefined ) ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
static struct fb_videomode atafb_modedb [ ] __initdata = {
/*
* Atari Video Modes
*
* If you change these , make sure to update DEFMODE_ * as well !
*/
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
/*
* ST / TT Video Modes
*/
{
/* 320x200, 15 kHz, 60 Hz (ST low) */
" st-low " , 60 , 320 , 200 , 32000 , 32 , 16 , 31 , 14 , 96 , 4 ,
0 , FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
} , {
/* 640x200, 15 kHz, 60 Hz (ST medium) */
" st-mid " , 60 , 640 , 200 , 32000 , 32 , 16 , 31 , 14 , 96 , 4 ,
0 , FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
} , {
/* 640x400, 30.25 kHz, 63.5 Hz (ST high) */
" st-high " , 63 , 640 , 400 , 32000 , 128 , 0 , 40 , 14 , 128 , 4 ,
0 , FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
} , {
/* 320x480, 15 kHz, 60 Hz (TT low) */
" tt-low " , 60 , 320 , 480 , 31041 , 120 , 100 , 8 , 16 , 140 , 30 ,
0 , FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
} , {
/* 640x480, 29 kHz, 57 Hz (TT medium) */
" tt-mid " , 60 , 640 , 480 , 31041 , 120 , 100 , 8 , 16 , 140 , 30 ,
0 , FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
} , {
/* 1280x960, 29 kHz, 60 Hz (TT high) */
" tt-high " , 57 , 640 , 960 , 31041 , 120 , 100 , 8 , 16 , 140 , 30 ,
0 , FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
} ,
/*
* VGA Video Modes
*/
{
/* 640x480, 31 kHz, 60 Hz (VGA) */
" vga " , 63.5 , 640 , 480 , 32000 , 18 , 42 , 31 , 11 , 96 , 3 ,
0 , FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
} , {
/* 640x400, 31 kHz, 70 Hz (VGA) */
" vga70 " , 70 , 640 , 400 , 32000 , 18 , 42 , 31 , 11 , 96 , 3 ,
FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT , FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
} ,
/*
* Falcon HiRes Video Modes
*/
{
/* 896x608, 31 kHz, 60 Hz (Falcon High) */
" falh " , 60 , 896 , 608 , 32000 , 18 , 42 , 31 , 1 , 96 , 3 ,
0 , FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
} ,
} ;
# define NUM_TOTAL_MODES ARRAY_SIZE(atafb_modedb)
static char * mode_option __initdata = NULL ;
/* default modes */
# define DEFMODE_TT 5 /* "tt-high" for TT */
# define DEFMODE_F30 7 /* "vga70" for Falcon */
# define DEFMODE_STE 2 /* "st-high" for ST/E */
# define DEFMODE_EXT 6 /* "vga" for external */
static int get_video_mode ( char * vname )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
char * * * name_list ;
char * * name ;
int i ;
name_list = fb_var_names ;
for ( i = 0 ; i < num_atafb_predefined ; i + + ) {
name = * name_list + + ;
if ( ! name | | ! * name )
break ;
while ( * name ) {
if ( ! strcmp ( vname , * name ) )
return i + 1 ;
name + + ;
}
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/* ------------------- TT specific functions ---------------------- */
# ifdef ATAFB_TT
2007-05-02 00:32:39 +04:00
static int tt_encode_fix ( struct fb_fix_screeninfo * fix , struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
int mode ;
2007-05-02 00:32:39 +04:00
strcpy ( fix - > id , " Atari Builtin " ) ;
2005-04-17 02:20:36 +04:00
fix - > smem_start = ( unsigned long ) real_screen_base ;
fix - > smem_len = screen_len ;
2007-05-02 00:32:39 +04:00
fix - > type = FB_TYPE_INTERLEAVED_PLANES ;
fix - > type_aux = 2 ;
fix - > visual = FB_VISUAL_PSEUDOCOLOR ;
2005-04-17 02:20:36 +04:00
mode = par - > hw . tt . mode & TT_SHIFTER_MODEMASK ;
if ( mode = = TT_SHIFTER_TTHIGH | | mode = = TT_SHIFTER_STHIGH ) {
2007-05-02 00:32:39 +04:00
fix - > type = FB_TYPE_PACKED_PIXELS ;
fix - > type_aux = 0 ;
2005-04-17 02:20:36 +04:00
if ( mode = = TT_SHIFTER_TTHIGH )
2007-05-02 00:32:39 +04:00
fix - > visual = FB_VISUAL_MONO01 ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
fix - > xpanstep = 0 ;
fix - > ypanstep = 1 ;
fix - > ywrapstep = 0 ;
2008-11-18 23:13:01 +03:00
fix - > line_length = par - > next_line ;
2005-04-17 02:20:36 +04:00
fix - > accel = FB_ACCEL_ATARIBLITT ;
return 0 ;
}
2007-05-02 00:32:39 +04:00
static int tt_decode_var ( struct fb_var_screeninfo * var , struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
int xres = var - > xres ;
int yres = var - > yres ;
int bpp = var - > bits_per_pixel ;
2005-04-17 02:20:36 +04:00
int linelen ;
int yres_virtual = var - > yres_virtual ;
if ( mono_moni ) {
2007-05-02 00:32:39 +04:00
if ( bpp > 1 | | xres > sttt_xres * 2 | | yres > tt_yres * 2 )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-05-02 00:32:39 +04:00
par - > hw . tt . mode = TT_SHIFTER_TTHIGH ;
xres = sttt_xres * 2 ;
yres = tt_yres * 2 ;
bpp = 1 ;
2005-04-17 02:20:36 +04:00
} else {
if ( bpp > 8 | | xres > sttt_xres | | yres > tt_yres )
return - EINVAL ;
if ( bpp > 4 ) {
2007-05-02 00:32:39 +04:00
if ( xres > sttt_xres / 2 | | yres > tt_yres )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-05-02 00:32:39 +04:00
par - > hw . tt . mode = TT_SHIFTER_TTLOW ;
xres = sttt_xres / 2 ;
yres = tt_yres ;
bpp = 8 ;
} else if ( bpp > 2 ) {
2005-04-17 02:20:36 +04:00
if ( xres > sttt_xres | | yres > tt_yres )
return - EINVAL ;
2007-05-02 00:32:39 +04:00
if ( xres > sttt_xres / 2 | | yres > st_yres / 2 ) {
par - > hw . tt . mode = TT_SHIFTER_TTMID ;
xres = sttt_xres ;
yres = tt_yres ;
bpp = 4 ;
} else {
par - > hw . tt . mode = TT_SHIFTER_STLOW ;
xres = sttt_xres / 2 ;
yres = st_yres / 2 ;
bpp = 4 ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
} else if ( bpp > 1 ) {
if ( xres > sttt_xres | | yres > st_yres / 2 )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-05-02 00:32:39 +04:00
par - > hw . tt . mode = TT_SHIFTER_STMID ;
xres = sttt_xres ;
yres = st_yres / 2 ;
bpp = 2 ;
} else if ( var - > xres > sttt_xres | | var - > yres > st_yres ) {
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-05-02 00:32:39 +04:00
} else {
par - > hw . tt . mode = TT_SHIFTER_STHIGH ;
xres = sttt_xres ;
yres = st_yres ;
bpp = 1 ;
2005-04-17 02:20:36 +04:00
}
}
if ( yres_virtual < = 0 )
yres_virtual = 0 ;
else if ( yres_virtual < yres )
yres_virtual = yres ;
if ( var - > sync & FB_SYNC_EXT )
2007-05-02 00:32:39 +04:00
par - > hw . tt . sync = 0 ;
2005-04-17 02:20:36 +04:00
else
2007-05-02 00:32:39 +04:00
par - > hw . tt . sync = 1 ;
linelen = xres * bpp / 8 ;
2005-04-17 02:20:36 +04:00
if ( yres_virtual * linelen > screen_len & & screen_len )
return - EINVAL ;
if ( yres * linelen > screen_len & & screen_len )
return - EINVAL ;
if ( var - > yoffset + yres > yres_virtual & & yres_virtual )
return - EINVAL ;
par - > yres_virtual = yres_virtual ;
par - > screen_base = screen_base + var - > yoffset * linelen ;
2008-11-18 23:13:01 +03:00
par - > next_line = linelen ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-05-02 00:32:39 +04:00
static int tt_encode_var ( struct fb_var_screeninfo * var , struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
int linelen ;
memset ( var , 0 , sizeof ( struct fb_var_screeninfo ) ) ;
2007-05-02 00:32:39 +04:00
var - > red . offset = 0 ;
var - > red . length = 4 ;
var - > red . msb_right = 0 ;
var - > grayscale = 0 ;
var - > pixclock = 31041 ;
var - > left_margin = 120 ; /* these may be incorrect */
var - > right_margin = 100 ;
var - > upper_margin = 8 ;
var - > lower_margin = 16 ;
var - > hsync_len = 140 ;
var - > vsync_len = 30 ;
var - > height = - 1 ;
var - > width = - 1 ;
2005-04-17 02:20:36 +04:00
if ( par - > hw . tt . sync & 1 )
2007-05-02 00:32:39 +04:00
var - > sync = 0 ;
2005-04-17 02:20:36 +04:00
else
2007-05-02 00:32:39 +04:00
var - > sync = FB_SYNC_EXT ;
2005-04-17 02:20:36 +04:00
switch ( par - > hw . tt . mode & TT_SHIFTER_MODEMASK ) {
case TT_SHIFTER_STLOW :
2007-05-02 00:32:39 +04:00
var - > xres = sttt_xres / 2 ;
var - > xres_virtual = sttt_xres_virtual / 2 ;
var - > yres = st_yres / 2 ;
var - > bits_per_pixel = 4 ;
2005-04-17 02:20:36 +04:00
break ;
case TT_SHIFTER_STMID :
2007-05-02 00:32:39 +04:00
var - > xres = sttt_xres ;
var - > xres_virtual = sttt_xres_virtual ;
var - > yres = st_yres / 2 ;
var - > bits_per_pixel = 2 ;
2005-04-17 02:20:36 +04:00
break ;
case TT_SHIFTER_STHIGH :
2007-05-02 00:32:39 +04:00
var - > xres = sttt_xres ;
var - > xres_virtual = sttt_xres_virtual ;
var - > yres = st_yres ;
var - > bits_per_pixel = 1 ;
2005-04-17 02:20:36 +04:00
break ;
case TT_SHIFTER_TTLOW :
2007-05-02 00:32:39 +04:00
var - > xres = sttt_xres / 2 ;
var - > xres_virtual = sttt_xres_virtual / 2 ;
var - > yres = tt_yres ;
var - > bits_per_pixel = 8 ;
2005-04-17 02:20:36 +04:00
break ;
case TT_SHIFTER_TTMID :
2007-05-02 00:32:39 +04:00
var - > xres = sttt_xres ;
var - > xres_virtual = sttt_xres_virtual ;
var - > yres = tt_yres ;
var - > bits_per_pixel = 4 ;
2005-04-17 02:20:36 +04:00
break ;
case TT_SHIFTER_TTHIGH :
2007-05-02 00:32:39 +04:00
var - > red . length = 0 ;
var - > xres = sttt_xres * 2 ;
var - > xres_virtual = sttt_xres_virtual * 2 ;
var - > yres = tt_yres * 2 ;
var - > bits_per_pixel = 1 ;
2005-04-17 02:20:36 +04:00
break ;
2007-05-02 00:32:39 +04:00
}
var - > blue = var - > green = var - > red ;
var - > transp . offset = 0 ;
var - > transp . length = 0 ;
var - > transp . msb_right = 0 ;
linelen = var - > xres_virtual * var - > bits_per_pixel / 8 ;
if ( ! use_hwscroll )
var - > yres_virtual = var - > yres ;
2005-04-17 02:20:36 +04:00
else if ( screen_len ) {
if ( par - > yres_virtual )
var - > yres_virtual = par - > yres_virtual ;
else
2007-05-02 00:32:39 +04:00
/* yres_virtual == 0 means use maximum */
2005-04-17 02:20:36 +04:00
var - > yres_virtual = screen_len / linelen ;
} else {
if ( hwscroll < 0 )
var - > yres_virtual = 2 * var - > yres ;
else
2007-05-02 00:32:39 +04:00
var - > yres_virtual = var - > yres + hwscroll * 16 ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
var - > xoffset = 0 ;
2005-04-17 02:20:36 +04:00
if ( screen_base )
2007-05-02 00:32:39 +04:00
var - > yoffset = ( par - > screen_base - screen_base ) / linelen ;
2005-04-17 02:20:36 +04:00
else
2007-05-02 00:32:39 +04:00
var - > yoffset = 0 ;
var - > nonstd = 0 ;
var - > activate = 0 ;
var - > vmode = FB_VMODE_NONINTERLACED ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-05-02 00:32:39 +04:00
static void tt_get_par ( struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
unsigned long addr ;
2007-05-02 00:32:39 +04:00
par - > hw . tt . mode = shifter_tt . tt_shiftmode ;
par - > hw . tt . sync = shifter . syncmode ;
2005-04-17 02:20:36 +04:00
addr = ( ( shifter . bas_hi & 0xff ) < < 16 ) |
( ( shifter . bas_md & 0xff ) < < 8 ) |
( ( shifter . bas_lo & 0xff ) ) ;
par - > screen_base = phys_to_virt ( addr ) ;
}
2007-05-02 00:32:39 +04:00
static void tt_set_par ( struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
shifter_tt . tt_shiftmode = par - > hw . tt . mode ;
shifter . syncmode = par - > hw . tt . sync ;
2005-04-17 02:20:36 +04:00
/* only set screen_base if really necessary */
if ( current_par . screen_base ! = par - > screen_base )
fbhw - > set_screen_base ( par - > screen_base ) ;
}
2007-05-02 00:32:39 +04:00
static int tt_setcolreg ( unsigned int regno , unsigned int red ,
unsigned int green , unsigned int blue ,
unsigned int transp , struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
if ( ( shifter_tt . tt_shiftmode & TT_SHIFTER_MODEMASK ) = = TT_SHIFTER_STHIGH )
regno + = 254 ;
if ( regno > 255 )
return 1 ;
tt_palette [ regno ] = ( ( ( red > > 12 ) < < 8 ) | ( ( green > > 12 ) < < 4 ) |
( blue > > 12 ) ) ;
if ( ( shifter_tt . tt_shiftmode & TT_SHIFTER_MODEMASK ) = =
2007-05-02 00:32:39 +04:00
TT_SHIFTER_STHIGH & & regno = = 254 )
2005-04-17 02:20:36 +04:00
tt_palette [ 0 ] = 0 ;
return 0 ;
}
2007-05-02 00:32:39 +04:00
static int tt_detect ( void )
{
struct atafb_par par ;
2005-04-17 02:20:36 +04:00
/* Determine the connected monitor: The DMA sound must be
* disabled before reading the MFP GPIP , because the Sound
* Done Signal and the Monochrome Detect are XORed together !
*
* Even on a TT , we should look if there is a DMA sound . It was
* announced that the Eagle is TT compatible , but only the PCM is
* missing . . .
*/
2007-05-02 00:32:39 +04:00
if ( ATARIHW_PRESENT ( PCM_8BIT ) ) {
2005-04-17 02:20:36 +04:00
tt_dmasnd . ctrl = DMASND_CTRL_OFF ;
2007-05-02 00:32:39 +04:00
udelay ( 20 ) ; /* wait a while for things to settle down */
2005-04-17 02:20:36 +04:00
}
2009-02-22 11:38:47 +03:00
mono_moni = ( st_mfp . par_dt_reg & 0x80 ) = = 0 ;
2005-04-17 02:20:36 +04:00
tt_get_par ( & par ) ;
tt_encode_var ( & atafb_predefined [ 0 ] , & par ) ;
return 1 ;
}
# endif /* ATAFB_TT */
/* ------------------- Falcon specific functions ---------------------- */
# ifdef ATAFB_FALCON
static int mon_type ; /* Falcon connected monitor */
static int f030_bus_width ; /* Falcon ram bus width (for vid_control) */
# define F_MON_SM 0
# define F_MON_SC 1
# define F_MON_VGA 2
# define F_MON_TV 3
static struct pixel_clock {
unsigned long f ; /* f/[Hz] */
unsigned long t ; /* t/[ps] (=1/f) */
int right , hsync , left ; /* standard timing in clock cycles, not pixel */
2007-05-02 00:32:39 +04:00
/* hsync initialized in falcon_detect() */
2005-04-17 02:20:36 +04:00
int sync_mask ; /* or-mask for hw.falcon.sync to set this clock */
int control_mask ; /* ditto, for hw.falcon.vid_control */
2007-05-02 00:32:39 +04:00
} f25 = {
25175000 , 39721 , 18 , 0 , 42 , 0x0 , VCO_CLOCK25
} , f32 = {
32000000 , 31250 , 18 , 0 , 42 , 0x0 , 0
} , fext = {
0 , 0 , 18 , 0 , 42 , 0x1 , 0
} ;
2005-04-17 02:20:36 +04:00
/* VIDEL-prescale values [mon_type][pixel_length from VCO] */
2007-05-02 00:32:39 +04:00
static int vdl_prescale [ 4 ] [ 3 ] = {
{ 4 , 2 , 1 } , { 4 , 2 , 1 } , { 4 , 2 , 2 } , { 4 , 2 , 1 }
} ;
2005-04-17 02:20:36 +04:00
/* Default hsync timing [mon_type] in picoseconds */
2007-05-02 00:32:39 +04:00
static long h_syncs [ 4 ] = { 3000000 , 4875000 , 4000000 , 4875000 } ;
2005-04-17 02:20:36 +04:00
static inline int hxx_prescale ( struct falcon_hw * hw )
{
2007-05-02 00:32:39 +04:00
return hw - > ste_mode ? 16
: vdl_prescale [ mon_type ] [ hw - > vid_mode > > 2 & 0x3 ] ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
static int falcon_encode_fix ( struct fb_fix_screeninfo * fix ,
struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
strcpy ( fix - > id , " Atari Builtin " ) ;
fix - > smem_start = ( unsigned long ) real_screen_base ;
fix - > smem_len = screen_len ;
fix - > type = FB_TYPE_INTERLEAVED_PLANES ;
fix - > type_aux = 2 ;
fix - > visual = FB_VISUAL_PSEUDOCOLOR ;
fix - > xpanstep = 1 ;
fix - > ypanstep = 1 ;
fix - > ywrapstep = 0 ;
if ( par - > hw . falcon . mono ) {
fix - > type = FB_TYPE_PACKED_PIXELS ;
fix - > type_aux = 0 ;
/* no smooth scrolling with longword aligned video mem */
fix - > xpanstep = 32 ;
2007-05-02 00:32:39 +04:00
} else if ( par - > hw . falcon . f_shift & 0x100 ) {
2005-04-17 02:20:36 +04:00
fix - > type = FB_TYPE_PACKED_PIXELS ;
fix - > type_aux = 0 ;
/* Is this ok or should it be DIRECTCOLOR? */
fix - > visual = FB_VISUAL_TRUECOLOR ;
fix - > xpanstep = 2 ;
}
2008-11-18 23:13:01 +03:00
fix - > line_length = par - > next_line ;
2005-04-17 02:20:36 +04:00
fix - > accel = FB_ACCEL_ATARIBLITT ;
return 0 ;
}
2007-05-02 00:32:39 +04:00
static int falcon_decode_var ( struct fb_var_screeninfo * var ,
struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
int bpp = var - > bits_per_pixel ;
int xres = var - > xres ;
int yres = var - > yres ;
int xres_virtual = var - > xres_virtual ;
int yres_virtual = var - > yres_virtual ;
int left_margin , right_margin , hsync_len ;
int upper_margin , lower_margin , vsync_len ;
int linelen ;
int interlace = 0 , doubleline = 0 ;
struct pixel_clock * pclock ;
2007-05-02 00:32:39 +04:00
int plen ; /* width of pixel in clock cycles */
2005-04-17 02:20:36 +04:00
int xstretch ;
int prescale ;
int longoffset = 0 ;
int hfreq , vfreq ;
2007-05-02 00:32:39 +04:00
int hdb_off , hde_off , base_off ;
int gstart , gend1 , gend2 , align ;
2005-04-17 02:20:36 +04:00
/*
Get the video params out of ' var ' . If a value doesn ' t fit , round
it up , if it ' s too big , return EINVAL .
2007-05-02 00:32:39 +04:00
Round up in the following order : bits_per_pixel , xres , yres ,
xres_virtual , yres_virtual , xoffset , yoffset , grayscale , bitfields ,
2005-04-17 02:20:36 +04:00
horizontal timing , vertical timing .
There is a maximum of screen resolution determined by pixelclock
and minimum frame rate - - ( X + hmarg . ) * ( Y + vmarg . ) * vfmin < = pixelclock .
In interlace mode this is " * " * vfmin < = pixelclock .
Additional constraints : hfreq .
Frequency range for multisync monitors is given via command line .
For TV and SM124 both frequencies are fixed .
2007-05-02 00:32:39 +04:00
X % 16 = = 0 to fit 8 x ? ? font ( except 1 bitplane modes must use X % 32 = = 0 )
2005-04-17 02:20:36 +04:00
Y % 16 = = 0 to fit 8 x16 font
Y % 8 = = 0 if Y < 400
2007-05-02 00:32:39 +04:00
Currently interlace and doubleline mode in var are ignored .
2005-04-17 02:20:36 +04:00
On SM124 and TV only the standard resolutions can be used .
*/
/* Reject uninitialized mode */
if ( ! xres | | ! yres | | ! bpp )
return - EINVAL ;
2007-05-02 00:32:39 +04:00
if ( mon_type = = F_MON_SM & & bpp ! = 1 )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-05-02 00:32:39 +04:00
if ( bpp < = 1 ) {
2005-04-17 02:20:36 +04:00
bpp = 1 ;
par - > hw . falcon . f_shift = 0x400 ;
par - > hw . falcon . st_shift = 0x200 ;
2007-05-02 00:32:39 +04:00
} else if ( bpp < = 2 ) {
2005-04-17 02:20:36 +04:00
bpp = 2 ;
par - > hw . falcon . f_shift = 0x000 ;
par - > hw . falcon . st_shift = 0x100 ;
2007-05-02 00:32:39 +04:00
} else if ( bpp < = 4 ) {
2005-04-17 02:20:36 +04:00
bpp = 4 ;
par - > hw . falcon . f_shift = 0x000 ;
par - > hw . falcon . st_shift = 0x000 ;
2007-05-02 00:32:39 +04:00
} else if ( bpp < = 8 ) {
2005-04-17 02:20:36 +04:00
bpp = 8 ;
par - > hw . falcon . f_shift = 0x010 ;
2007-05-02 00:32:39 +04:00
} else if ( bpp < = 16 ) {
bpp = 16 ; /* packed pixel mode */
par - > hw . falcon . f_shift = 0x100 ; /* hicolor, no overlay */
} else
2005-04-17 02:20:36 +04:00
return - EINVAL ;
par - > hw . falcon . bpp = bpp ;
if ( mon_type = = F_MON_SM | | DontCalcRes ) {
/* Skip all calculations. VGA/TV/SC1224 only supported. */
struct fb_var_screeninfo * myvar = & atafb_predefined [ 0 ] ;
2007-05-02 00:32:39 +04:00
2005-04-17 02:20:36 +04:00
if ( bpp > myvar - > bits_per_pixel | |
2007-05-02 00:32:39 +04:00
var - > xres > myvar - > xres | |
var - > yres > myvar - > yres )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
fbhw - > get_par ( par ) ; /* Current par will be new par */
goto set_screen_base ; /* Don't forget this */
}
/* Only some fixed resolutions < 640x400 */
if ( xres < = 320 )
xres = 320 ;
else if ( xres < = 640 & & bpp ! = 16 )
xres = 640 ;
if ( yres < = 200 )
yres = 200 ;
else if ( yres < = 240 )
yres = 240 ;
else if ( yres < = 400 )
yres = 400 ;
/* 2 planes must use STE compatibility mode */
2007-05-02 00:32:39 +04:00
par - > hw . falcon . ste_mode = bpp = = 2 ;
par - > hw . falcon . mono = bpp = = 1 ;
2005-04-17 02:20:36 +04:00
/* Total and visible scanline length must be a multiple of one longword,
* this and the console fontwidth yields the alignment for xres and
* xres_virtual .
* TODO : this way " odd " fontheights are not supported
*
* Special case in STE mode : blank and graphic positions don ' t align ,
* avoid trash at right margin
*/
if ( par - > hw . falcon . ste_mode )
xres = ( xres + 63 ) & ~ 63 ;
else if ( bpp = = 1 )
xres = ( xres + 31 ) & ~ 31 ;
else
xres = ( xres + 15 ) & ~ 15 ;
if ( yres > = 400 )
yres = ( yres + 15 ) & ~ 15 ;
else
yres = ( yres + 7 ) & ~ 7 ;
if ( xres_virtual < xres )
xres_virtual = xres ;
else if ( bpp = = 1 )
xres_virtual = ( xres_virtual + 31 ) & ~ 31 ;
else
xres_virtual = ( xres_virtual + 15 ) & ~ 15 ;
if ( yres_virtual < = 0 )
yres_virtual = 0 ;
else if ( yres_virtual < yres )
yres_virtual = yres ;
/* backward bug-compatibility */
if ( var - > pixclock > 1 )
var - > pixclock - = 1 ;
par - > hw . falcon . line_width = bpp * xres / 16 ;
par - > hw . falcon . line_offset = bpp * ( xres_virtual - xres ) / 16 ;
/* single or double pixel width */
xstretch = ( xres < 640 ) ? 2 : 1 ;
#if 0 /* SM124 supports only 640x400, this is rejected above */
if ( mon_type = = F_MON_SM ) {
if ( xres ! = 640 & & yres ! = 400 )
return - EINVAL ;
plen = 1 ;
pclock = & f32 ;
/* SM124-mode is special */
par - > hw . falcon . ste_mode = 1 ;
par - > hw . falcon . f_shift = 0x000 ;
par - > hw . falcon . st_shift = 0x200 ;
left_margin = hsync_len = 128 / plen ;
right_margin = 0 ;
/* TODO set all margins */
2007-05-02 00:32:39 +04:00
} else
2005-04-17 02:20:36 +04:00
# endif
if ( mon_type = = F_MON_SC | | mon_type = = F_MON_TV ) {
plen = 2 * xstretch ;
if ( var - > pixclock > f32 . t * plen )
return - EINVAL ;
pclock = & f32 ;
if ( yres > 240 )
interlace = 1 ;
if ( var - > pixclock = = 0 ) {
/* set some minimal margins which center the screen */
left_margin = 32 ;
right_margin = 18 ;
hsync_len = pclock - > hsync / plen ;
upper_margin = 31 ;
lower_margin = 14 ;
vsync_len = interlace ? 3 : 4 ;
} else {
left_margin = var - > left_margin ;
right_margin = var - > right_margin ;
hsync_len = var - > hsync_len ;
upper_margin = var - > upper_margin ;
lower_margin = var - > lower_margin ;
vsync_len = var - > vsync_len ;
if ( var - > vmode & FB_VMODE_INTERLACED ) {
upper_margin = ( upper_margin + 1 ) / 2 ;
lower_margin = ( lower_margin + 1 ) / 2 ;
vsync_len = ( vsync_len + 1 ) / 2 ;
} else if ( var - > vmode & FB_VMODE_DOUBLE ) {
upper_margin * = 2 ;
lower_margin * = 2 ;
vsync_len * = 2 ;
}
}
2007-05-02 00:32:39 +04:00
} else { /* F_MON_VGA */
2005-04-17 02:20:36 +04:00
if ( bpp = = 16 )
2007-05-02 00:32:39 +04:00
xstretch = 2 ; /* Double pixel width only for hicolor */
2005-04-17 02:20:36 +04:00
/* Default values are used for vert./hor. timing if no pixelclock given. */
if ( var - > pixclock = = 0 ) {
int linesize ;
/* Choose master pixelclock depending on hor. timing */
plen = 1 * xstretch ;
2007-05-02 00:32:39 +04:00
if ( ( plen * xres + f25 . right + f25 . hsync + f25 . left ) *
2005-04-17 02:20:36 +04:00
fb_info . monspecs . hfmin < f25 . f )
pclock = & f25 ;
2007-05-02 00:32:39 +04:00
else if ( ( plen * xres + f32 . right + f32 . hsync +
f32 . left ) * fb_info . monspecs . hfmin < f32 . f )
2005-04-17 02:20:36 +04:00
pclock = & f32 ;
2007-05-02 00:32:39 +04:00
else if ( ( plen * xres + fext . right + fext . hsync +
fext . left ) * fb_info . monspecs . hfmin < fext . f & &
fext . f )
2005-04-17 02:20:36 +04:00
pclock = & fext ;
else
return - EINVAL ;
left_margin = pclock - > left / plen ;
right_margin = pclock - > right / plen ;
hsync_len = pclock - > hsync / plen ;
linesize = left_margin + xres + right_margin + hsync_len ;
upper_margin = 31 ;
lower_margin = 11 ;
vsync_len = 3 ;
2007-05-02 00:32:39 +04:00
} else {
2005-04-17 02:20:36 +04:00
/* Choose largest pixelclock <= wanted clock */
int i ;
unsigned long pcl = ULONG_MAX ;
pclock = 0 ;
2007-05-02 00:32:39 +04:00
for ( i = 1 ; i < = 4 ; i * = 2 ) {
if ( f25 . t * i > = var - > pixclock & &
f25 . t * i < pcl ) {
2005-04-17 02:20:36 +04:00
pcl = f25 . t * i ;
pclock = & f25 ;
}
2007-05-02 00:32:39 +04:00
if ( f32 . t * i > = var - > pixclock & &
f32 . t * i < pcl ) {
2005-04-17 02:20:36 +04:00
pcl = f32 . t * i ;
pclock = & f32 ;
}
2007-05-02 00:32:39 +04:00
if ( fext . t & & fext . t * i > = var - > pixclock & &
fext . t * i < pcl ) {
2005-04-17 02:20:36 +04:00
pcl = fext . t * i ;
pclock = & fext ;
}
}
if ( ! pclock )
return - EINVAL ;
plen = pcl / pclock - > t ;
left_margin = var - > left_margin ;
right_margin = var - > right_margin ;
hsync_len = var - > hsync_len ;
upper_margin = var - > upper_margin ;
lower_margin = var - > lower_margin ;
vsync_len = var - > vsync_len ;
/* Internal unit is [single lines per (half-)frame] */
if ( var - > vmode & FB_VMODE_INTERLACED ) {
/* # lines in half frame */
/* External unit is [lines per full frame] */
upper_margin = ( upper_margin + 1 ) / 2 ;
lower_margin = ( lower_margin + 1 ) / 2 ;
vsync_len = ( vsync_len + 1 ) / 2 ;
2007-05-02 00:32:39 +04:00
} else if ( var - > vmode & FB_VMODE_DOUBLE ) {
2005-04-17 02:20:36 +04:00
/* External unit is [double lines per frame] */
upper_margin * = 2 ;
lower_margin * = 2 ;
vsync_len * = 2 ;
}
}
if ( pclock = = & fext )
2007-05-02 00:32:39 +04:00
longoffset = 1 ; /* VIDEL doesn't synchronize on short offset */
2005-04-17 02:20:36 +04:00
}
/* Is video bus bandwidth (32MB/s) too low for this resolution? */
/* this is definitely wrong if bus clock != 32MHz */
if ( pclock - > f / plen / 8 * bpp > 32000000L )
return - EINVAL ;
if ( vsync_len < 1 )
vsync_len = 1 ;
/* include sync lengths in right/lower margin for all calculations */
right_margin + = hsync_len ;
lower_margin + = vsync_len ;
/* ! In all calculations of margins we use # of lines in half frame
* ( which is a full frame in non - interlace mode ) , so we can switch
* between interlace and non - interlace without messing around
* with these .
*/
2007-05-02 00:32:39 +04:00
again :
2005-04-17 02:20:36 +04:00
/* Set base_offset 128 and video bus width */
par - > hw . falcon . vid_control = mon_type | f030_bus_width ;
if ( ! longoffset )
par - > hw . falcon . vid_control | = VCO_SHORTOFFS ; /* base_offset 64 */
if ( var - > sync & FB_SYNC_HOR_HIGH_ACT )
par - > hw . falcon . vid_control | = VCO_HSYPOS ;
if ( var - > sync & FB_SYNC_VERT_HIGH_ACT )
par - > hw . falcon . vid_control | = VCO_VSYPOS ;
/* Pixelclock */
par - > hw . falcon . vid_control | = pclock - > control_mask ;
/* External or internal clock */
par - > hw . falcon . sync = pclock - > sync_mask | 0x2 ;
/* Pixellength and prescale */
2007-05-02 00:32:39 +04:00
par - > hw . falcon . vid_mode = ( 2 / plen ) < < 2 ;
2005-04-17 02:20:36 +04:00
if ( doubleline )
par - > hw . falcon . vid_mode | = VMO_DOUBLE ;
if ( interlace )
par - > hw . falcon . vid_mode | = VMO_INTER ;
/*********************
2007-05-02 00:32:39 +04:00
* Horizontal timing : unit = [ master clock cycles ]
* unit of hxx - registers : [ master clock cycles * prescale ]
* Hxx - registers are 9 bit wide
*
* 1 line = ( ( hht + 2 ) * 2 * prescale ) clock cycles
*
* graphic output = hdb & 0x200 ?
* ( ( hht + 2 ) * 2 - hdb + hde ) * prescale - hdboff + hdeoff :
* ( hht + 2 - hdb + hde ) * prescale - hdboff + hdeoff
* ( this must be a multiple of plen * 128 / bpp , on VGA pixels
* to the right may be cut off with a bigger right margin )
*
* start of graphics relative to start of 1 st halfline = hdb & 0x200 ?
* ( hdb - hht - 2 ) * prescale + hdboff :
* hdb * prescale + hdboff
*
* end of graphics relative to start of 1 st halfline =
* ( hde + hht + 2 ) * prescale + hdeoff
* * * * * * * * * * * * * * * * * * * * */
2005-04-17 02:20:36 +04:00
/* Calculate VIDEL registers */
2007-05-02 00:32:39 +04:00
{
2005-04-17 02:20:36 +04:00
prescale = hxx_prescale ( & par - > hw . falcon ) ;
base_off = par - > hw . falcon . vid_control & VCO_SHORTOFFS ? 64 : 128 ;
/* Offsets depend on video mode */
/* Offsets are in clock cycles, divide by prescale to
* calculate hd [ be ] - registers
*/
if ( par - > hw . falcon . f_shift & 0x100 ) {
align = 1 ;
hde_off = 0 ;
hdb_off = ( base_off + 16 * plen ) + prescale ;
2007-05-02 00:32:39 +04:00
} else {
2005-04-17 02:20:36 +04:00
align = 128 / bpp ;
hde_off = ( ( 128 / bpp + 2 ) * plen ) ;
if ( par - > hw . falcon . ste_mode )
hdb_off = ( 64 + base_off + ( 128 / bpp + 2 ) * plen ) + prescale ;
else
hdb_off = ( base_off + ( 128 / bpp + 18 ) * plen ) + prescale ;
}
2007-05-02 00:32:39 +04:00
gstart = ( prescale / 2 + plen * left_margin ) / prescale ;
2005-04-17 02:20:36 +04:00
/* gend1 is for hde (gend-gstart multiple of align), shifter's xres */
2008-04-28 13:14:51 +04:00
gend1 = gstart + roundup ( xres , align ) * plen / prescale ;
2005-04-17 02:20:36 +04:00
/* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */
gend2 = gstart + xres * plen / prescale ;
par - > HHT = plen * ( left_margin + xres + right_margin ) /
( 2 * prescale ) - 2 ;
/* par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/
2007-05-02 00:32:39 +04:00
par - > HDB = gstart - hdb_off / prescale ;
2005-04-17 02:20:36 +04:00
par - > HBE = gstart ;
2007-05-02 00:32:39 +04:00
if ( par - > HDB < 0 )
par - > HDB + = par - > HHT + 2 + 0x200 ;
par - > HDE = gend1 - par - > HHT - 2 - hde_off / prescale ;
2005-04-17 02:20:36 +04:00
par - > HBB = gend2 - par - > HHT - 2 ;
#if 0
/* One more Videl constraint: data fetch of two lines must not overlap */
2007-05-02 00:32:39 +04:00
if ( ( par - > HDB & 0x200 ) & & ( par - > HDB & ~ 0x200 ) - par - > HDE < = 5 ) {
2005-04-17 02:20:36 +04:00
/* if this happens increase margins, decrease hfreq. */
}
# endif
if ( hde_off % prescale )
par - > HBB + + ; /* compensate for non matching hde and hbb */
par - > HSS = par - > HHT + 2 - plen * hsync_len / prescale ;
if ( par - > HSS < par - > HBB )
par - > HSS = par - > HBB ;
2007-05-02 00:32:39 +04:00
}
2005-04-17 02:20:36 +04:00
/* check hor. frequency */
2007-05-02 00:32:39 +04:00
hfreq = pclock - > f / ( ( par - > HHT + 2 ) * prescale * 2 ) ;
if ( hfreq > fb_info . monspecs . hfmax & & mon_type ! = F_MON_VGA ) {
2005-04-17 02:20:36 +04:00
/* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */
/* Too high -> enlarge margin */
left_margin + = 1 ;
right_margin + = 1 ;
goto again ;
}
if ( hfreq > fb_info . monspecs . hfmax | | hfreq < fb_info . monspecs . hfmin )
return - EINVAL ;
/* Vxx-registers */
/* All Vxx must be odd in non-interlace, since frame starts in the middle
* of the first displayed line !
* One frame consists of VFT + 1 half lines . VFT + 1 must be even in
* non - interlace , odd in interlace mode for synchronisation .
* Vxx - registers are 11 bit wide
*/
par - > VBE = ( upper_margin * 2 + 1 ) ; /* must begin on odd halfline */
par - > VDB = par - > VBE ;
par - > VDE = yres ;
2007-05-02 00:32:39 +04:00
if ( ! interlace )
par - > VDE < < = 1 ;
if ( doubleline )
par - > VDE < < = 1 ; /* VDE now half lines per (half-)frame */
2005-04-17 02:20:36 +04:00
par - > VDE + = par - > VDB ;
par - > VBB = par - > VDE ;
par - > VFT = par - > VBB + ( lower_margin * 2 - 1 ) - 1 ;
2007-05-02 00:32:39 +04:00
par - > VSS = par - > VFT + 1 - ( vsync_len * 2 - 1 ) ;
2005-04-17 02:20:36 +04:00
/* vbb,vss,vft must be even in interlace mode */
if ( interlace ) {
par - > VBB + + ;
par - > VSS + + ;
par - > VFT + + ;
}
/* V-frequency check, hope I didn't create any loop here. */
/* Interlace and doubleline are mutually exclusive. */
vfreq = ( hfreq * 2 ) / ( par - > VFT + 1 ) ;
2007-05-02 00:32:39 +04:00
if ( vfreq > fb_info . monspecs . vfmax & & ! doubleline & & ! interlace ) {
2005-04-17 02:20:36 +04:00
/* Too high -> try again with doubleline */
doubleline = 1 ;
goto again ;
2007-05-02 00:32:39 +04:00
} else if ( vfreq < fb_info . monspecs . vfmin & & ! interlace & & ! doubleline ) {
2005-04-17 02:20:36 +04:00
/* Too low -> try again with interlace */
interlace = 1 ;
goto again ;
2007-05-02 00:32:39 +04:00
} else if ( vfreq < fb_info . monspecs . vfmin & & doubleline ) {
2005-04-17 02:20:36 +04:00
/* Doubleline too low -> clear doubleline and enlarge margins */
int lines ;
doubleline = 0 ;
2007-05-02 00:32:39 +04:00
for ( lines = 0 ;
( hfreq * 2 ) / ( par - > VFT + 1 + 4 * lines - 2 * yres ) >
fb_info . monspecs . vfmax ;
2005-04-17 02:20:36 +04:00
lines + + )
;
upper_margin + = lines ;
lower_margin + = lines ;
goto again ;
2007-05-02 00:32:39 +04:00
} else if ( vfreq > fb_info . monspecs . vfmax & & doubleline ) {
2005-04-17 02:20:36 +04:00
/* Doubleline too high -> enlarge margins */
int lines ;
2007-05-02 00:32:39 +04:00
for ( lines = 0 ;
( hfreq * 2 ) / ( par - > VFT + 1 + 4 * lines ) >
fb_info . monspecs . vfmax ;
lines + = 2 )
2005-04-17 02:20:36 +04:00
;
upper_margin + = lines ;
lower_margin + = lines ;
goto again ;
2007-05-02 00:32:39 +04:00
} else if ( vfreq > fb_info . monspecs . vfmax & & interlace ) {
2005-04-17 02:20:36 +04:00
/* Interlace, too high -> enlarge margins */
int lines ;
2007-05-02 00:32:39 +04:00
for ( lines = 0 ;
( hfreq * 2 ) / ( par - > VFT + 1 + 4 * lines ) >
fb_info . monspecs . vfmax ;
2005-04-17 02:20:36 +04:00
lines + + )
;
upper_margin + = lines ;
lower_margin + = lines ;
goto again ;
2007-05-02 00:32:39 +04:00
} else if ( vfreq < fb_info . monspecs . vfmin | |
vfreq > fb_info . monspecs . vfmax )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-05-02 00:32:39 +04:00
set_screen_base :
2005-04-17 02:20:36 +04:00
linelen = xres_virtual * bpp / 8 ;
if ( yres_virtual * linelen > screen_len & & screen_len )
return - EINVAL ;
if ( yres * linelen > screen_len & & screen_len )
return - EINVAL ;
if ( var - > yoffset + yres > yres_virtual & & yres_virtual )
return - EINVAL ;
par - > yres_virtual = yres_virtual ;
par - > screen_base = screen_base + var - > yoffset * linelen ;
par - > hw . falcon . xoffset = 0 ;
2007-05-02 00:32:39 +04:00
par - > next_line = linelen ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-05-02 00:32:39 +04:00
static int falcon_encode_var ( struct fb_var_screeninfo * var ,
struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
/* !!! only for VGA !!! */
int linelen ;
int prescale , plen ;
int hdb_off , hde_off , base_off ;
struct falcon_hw * hw = & par - > hw . falcon ;
memset ( var , 0 , sizeof ( struct fb_var_screeninfo ) ) ;
/* possible frequencies: 25.175 or 32MHz */
var - > pixclock = hw - > sync & 0x1 ? fext . t :
hw - > vid_control & VCO_CLOCK25 ? f25 . t : f32 . t ;
2007-05-02 00:32:39 +04:00
var - > height = - 1 ;
var - > width = - 1 ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
var - > sync = 0 ;
2005-04-17 02:20:36 +04:00
if ( hw - > vid_control & VCO_HSYPOS )
var - > sync | = FB_SYNC_HOR_HIGH_ACT ;
if ( hw - > vid_control & VCO_VSYPOS )
var - > sync | = FB_SYNC_VERT_HIGH_ACT ;
var - > vmode = FB_VMODE_NONINTERLACED ;
if ( hw - > vid_mode & VMO_INTER )
var - > vmode | = FB_VMODE_INTERLACED ;
if ( hw - > vid_mode & VMO_DOUBLE )
var - > vmode | = FB_VMODE_DOUBLE ;
2007-05-02 00:32:39 +04:00
2005-04-17 02:20:36 +04:00
/* visible y resolution:
* Graphics display starts at line VDB and ends at line
* VDE . If interlace mode off unit of VC - registers is
* half lines , else lines .
*/
var - > yres = hw - > vde - hw - > vdb ;
if ( ! ( var - > vmode & FB_VMODE_INTERLACED ) )
var - > yres > > = 1 ;
if ( var - > vmode & FB_VMODE_DOUBLE )
var - > yres > > = 1 ;
2007-05-02 00:32:39 +04:00
/*
* to get bpp , we must examine f_shift and st_shift .
2005-04-17 02:20:36 +04:00
* f_shift is valid if any of bits no . 10 , 8 or 4
* is set . Priority in f_shift is : 10 " > " 8 " > " 4 , i . e .
* if bit 10 set then bit 8 and bit 4 don ' t care . . .
* If all these bits are 0 get display depth from st_shift
* ( as for ST and STE )
*/
2007-05-02 00:32:39 +04:00
if ( hw - > f_shift & 0x400 ) /* 2 colors */
2005-04-17 02:20:36 +04:00
var - > bits_per_pixel = 1 ;
else if ( hw - > f_shift & 0x100 ) /* hicolor */
var - > bits_per_pixel = 16 ;
else if ( hw - > f_shift & 0x010 ) /* 8 bitplanes */
var - > bits_per_pixel = 8 ;
else if ( hw - > st_shift = = 0 )
var - > bits_per_pixel = 4 ;
else if ( hw - > st_shift = = 0x100 )
var - > bits_per_pixel = 2 ;
2007-05-02 00:32:39 +04:00
else /* if (hw->st_shift == 0x200) */
2005-04-17 02:20:36 +04:00
var - > bits_per_pixel = 1 ;
var - > xres = hw - > line_width * 16 / var - > bits_per_pixel ;
var - > xres_virtual = var - > xres + hw - > line_offset * 16 / var - > bits_per_pixel ;
if ( hw - > xoffset )
var - > xres_virtual + = 16 ;
if ( var - > bits_per_pixel = = 16 ) {
2007-05-02 00:32:39 +04:00
var - > red . offset = 11 ;
var - > red . length = 5 ;
var - > red . msb_right = 0 ;
var - > green . offset = 5 ;
var - > green . length = 6 ;
var - > green . msb_right = 0 ;
var - > blue . offset = 0 ;
var - > blue . length = 5 ;
var - > blue . msb_right = 0 ;
} else {
var - > red . offset = 0 ;
2005-04-17 02:20:36 +04:00
var - > red . length = hw - > ste_mode ? 4 : 6 ;
2007-05-02 00:32:39 +04:00
if ( var - > red . length > var - > bits_per_pixel )
var - > red . length = var - > bits_per_pixel ;
var - > red . msb_right = 0 ;
var - > grayscale = 0 ;
var - > blue = var - > green = var - > red ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
var - > transp . offset = 0 ;
var - > transp . length = 0 ;
var - > transp . msb_right = 0 ;
2005-04-17 02:20:36 +04:00
linelen = var - > xres_virtual * var - > bits_per_pixel / 8 ;
if ( screen_len ) {
if ( par - > yres_virtual )
var - > yres_virtual = par - > yres_virtual ;
else
2007-05-02 00:32:39 +04:00
/* yres_virtual == 0 means use maximum */
2005-04-17 02:20:36 +04:00
var - > yres_virtual = screen_len / linelen ;
2007-05-02 00:32:39 +04:00
} else {
2005-04-17 02:20:36 +04:00
if ( hwscroll < 0 )
var - > yres_virtual = 2 * var - > yres ;
else
2007-05-02 00:32:39 +04:00
var - > yres_virtual = var - > yres + hwscroll * 16 ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
var - > xoffset = 0 ; /* TODO change this */
2005-04-17 02:20:36 +04:00
/* hdX-offsets */
prescale = hxx_prescale ( hw ) ;
plen = 4 > > ( hw - > vid_mode > > 2 & 0x3 ) ;
base_off = hw - > vid_control & VCO_SHORTOFFS ? 64 : 128 ;
if ( hw - > f_shift & 0x100 ) {
hde_off = 0 ;
hdb_off = ( base_off + 16 * plen ) + prescale ;
2007-05-02 00:32:39 +04:00
} else {
2005-04-17 02:20:36 +04:00
hde_off = ( ( 128 / var - > bits_per_pixel + 2 ) * plen ) ;
if ( hw - > ste_mode )
hdb_off = ( 64 + base_off + ( 128 / var - > bits_per_pixel + 2 ) * plen )
+ prescale ;
else
hdb_off = ( base_off + ( 128 / var - > bits_per_pixel + 18 ) * plen )
+ prescale ;
}
/* Right margin includes hsync */
var - > left_margin = hdb_off + prescale * ( ( hw - > hdb & 0x1ff ) -
2007-05-02 00:32:39 +04:00
( hw - > hdb & 0x200 ? 2 + hw - > hht : 0 ) ) ;
if ( hw - > ste_mode | | mon_type ! = F_MON_VGA )
2005-04-17 02:20:36 +04:00
var - > right_margin = prescale * ( hw - > hht + 2 - hw - > hde ) - hde_off ;
else
/* can't use this in ste_mode, because hbb is +1 off */
var - > right_margin = prescale * ( hw - > hht + 2 - hw - > hbb ) ;
var - > hsync_len = prescale * ( hw - > hht + 2 - hw - > hss ) ;
/* Lower margin includes vsync */
2007-05-02 00:32:39 +04:00
var - > upper_margin = hw - > vdb / 2 ; /* round down to full lines */
var - > lower_margin = ( hw - > vft + 1 - hw - > vde + 1 ) / 2 ; /* round up */
var - > vsync_len = ( hw - > vft + 1 - hw - > vss + 1 ) / 2 ; /* round up */
2005-04-17 02:20:36 +04:00
if ( var - > vmode & FB_VMODE_INTERLACED ) {
var - > upper_margin * = 2 ;
var - > lower_margin * = 2 ;
var - > vsync_len * = 2 ;
2007-05-02 00:32:39 +04:00
} else if ( var - > vmode & FB_VMODE_DOUBLE ) {
2005-04-17 02:20:36 +04:00
var - > upper_margin = ( var - > upper_margin + 1 ) / 2 ;
var - > lower_margin = ( var - > lower_margin + 1 ) / 2 ;
var - > vsync_len = ( var - > vsync_len + 1 ) / 2 ;
}
var - > pixclock * = plen ;
var - > left_margin / = plen ;
var - > right_margin / = plen ;
var - > hsync_len / = plen ;
var - > right_margin - = var - > hsync_len ;
var - > lower_margin - = var - > vsync_len ;
if ( screen_base )
2007-05-02 00:32:39 +04:00
var - > yoffset = ( par - > screen_base - screen_base ) / linelen ;
2005-04-17 02:20:36 +04:00
else
2007-05-02 00:32:39 +04:00
var - > yoffset = 0 ;
var - > nonstd = 0 ; /* what is this for? */
var - > activate = 0 ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-05-02 00:32:39 +04:00
static int f_change_mode ;
2005-04-17 02:20:36 +04:00
static struct falcon_hw f_new_mode ;
2007-05-02 00:32:39 +04:00
static int f_pan_display ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
static void falcon_get_par ( struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
unsigned long addr ;
struct falcon_hw * hw = & par - > hw . falcon ;
hw - > line_width = shifter_f030 . scn_width ;
hw - > line_offset = shifter_f030 . off_next ;
hw - > st_shift = videl . st_shift & 0x300 ;
hw - > f_shift = videl . f_shift ;
hw - > vid_control = videl . control ;
hw - > vid_mode = videl . mode ;
hw - > sync = shifter . syncmode & 0x1 ;
hw - > xoffset = videl . xoffset & 0xf ;
hw - > hht = videl . hht ;
hw - > hbb = videl . hbb ;
hw - > hbe = videl . hbe ;
hw - > hdb = videl . hdb ;
hw - > hde = videl . hde ;
hw - > hss = videl . hss ;
hw - > vft = videl . vft ;
hw - > vbb = videl . vbb ;
hw - > vbe = videl . vbe ;
hw - > vdb = videl . vdb ;
hw - > vde = videl . vde ;
hw - > vss = videl . vss ;
addr = ( shifter . bas_hi & 0xff ) < < 16 |
( shifter . bas_md & 0xff ) < < 8 |
( shifter . bas_lo & 0xff ) ;
par - > screen_base = phys_to_virt ( addr ) ;
/* derived parameters */
2007-05-02 00:32:39 +04:00
hw - > ste_mode = ( hw - > f_shift & 0x510 ) = = 0 & & hw - > st_shift = = 0x100 ;
2005-04-17 02:20:36 +04:00
hw - > mono = ( hw - > f_shift & 0x400 ) | |
2007-05-02 00:32:39 +04:00
( ( hw - > f_shift & 0x510 ) = = 0 & & hw - > st_shift = = 0x200 ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
static void falcon_set_par ( struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
f_change_mode = 0 ;
/* only set screen_base if really necessary */
if ( current_par . screen_base ! = par - > screen_base )
fbhw - > set_screen_base ( par - > screen_base ) ;
/* Don't touch any other registers if we keep the default resolution */
if ( DontCalcRes )
return ;
/* Tell vbl-handler to change video mode.
* We change modes only on next VBL , to avoid desynchronisation
* ( a shift to the right and wrap around by a random number of pixels
* in all monochrome modes ) .
* This seems to work on my Falcon .
*/
f_new_mode = par - > hw . falcon ;
f_change_mode = 1 ;
}
2007-05-02 00:32:39 +04:00
static irqreturn_t falcon_vbl_switcher ( int irq , void * dummy )
2005-04-17 02:20:36 +04:00
{
struct falcon_hw * hw = & f_new_mode ;
if ( f_change_mode ) {
f_change_mode = 0 ;
if ( hw - > sync & 0x1 ) {
/* Enable external pixelclock. This code only for ScreenWonder */
2007-05-02 00:32:39 +04:00
* ( volatile unsigned short * ) 0xffff9202 = 0xffbf ;
} else {
2005-04-17 02:20:36 +04:00
/* Turn off external clocks. Read sets all output bits to 1. */
2007-05-02 00:32:39 +04:00
* ( volatile unsigned short * ) 0xffff9202 ;
2005-04-17 02:20:36 +04:00
}
shifter . syncmode = hw - > sync ;
videl . hht = hw - > hht ;
videl . hbb = hw - > hbb ;
videl . hbe = hw - > hbe ;
videl . hdb = hw - > hdb ;
videl . hde = hw - > hde ;
videl . hss = hw - > hss ;
videl . vft = hw - > vft ;
videl . vbb = hw - > vbb ;
videl . vbe = hw - > vbe ;
videl . vdb = hw - > vdb ;
videl . vde = hw - > vde ;
videl . vss = hw - > vss ;
2007-05-02 00:32:39 +04:00
videl . f_shift = 0 ; /* write enables Falcon palette, 0: 4 planes */
2005-04-17 02:20:36 +04:00
if ( hw - > ste_mode ) {
2007-05-02 00:32:39 +04:00
videl . st_shift = hw - > st_shift ; /* write enables STE palette */
} else {
2005-04-17 02:20:36 +04:00
/* IMPORTANT:
2007-05-02 00:32:39 +04:00
* set st_shift 0 , so we can tell the screen - depth if f_shift = = 0.
2005-04-17 02:20:36 +04:00
* Writing 0 to f_shift enables 4 plane Falcon mode but
2007-05-02 00:32:39 +04:00
* doesn ' t set st_shift . st_shift ! = 0 ( ! = 4 planes ) is impossible
2005-04-17 02:20:36 +04:00
* with Falcon palette .
*/
videl . st_shift = 0 ;
/* now back to Falcon palette mode */
videl . f_shift = hw - > f_shift ;
}
/* writing to st_shift changed scn_width and vid_mode */
videl . xoffset = hw - > xoffset ;
shifter_f030 . scn_width = hw - > line_width ;
shifter_f030 . off_next = hw - > line_offset ;
videl . control = hw - > vid_control ;
videl . mode = hw - > vid_mode ;
}
if ( f_pan_display ) {
f_pan_display = 0 ;
videl . xoffset = current_par . hw . falcon . xoffset ;
shifter_f030 . off_next = current_par . hw . falcon . line_offset ;
}
return IRQ_HANDLED ;
}
2007-05-02 00:32:39 +04:00
static int falcon_pan_display ( struct fb_var_screeninfo * var ,
struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
struct atafb_par * par = ( struct atafb_par * ) info - > par ;
2005-04-17 02:20:36 +04:00
int xoffset ;
2007-05-02 00:32:39 +04:00
int bpp = info - > var . bits_per_pixel ;
2005-04-17 02:20:36 +04:00
if ( bpp = = 1 )
var - > xoffset = up ( var - > xoffset , 32 ) ;
if ( bpp ! = 16 )
par - > hw . falcon . xoffset = var - > xoffset & 15 ;
else {
par - > hw . falcon . xoffset = 0 ;
var - > xoffset = up ( var - > xoffset , 2 ) ;
}
par - > hw . falcon . line_offset = bpp *
2007-05-02 00:32:39 +04:00
( info - > var . xres_virtual - info - > var . xres ) / 16 ;
2005-04-17 02:20:36 +04:00
if ( par - > hw . falcon . xoffset )
par - > hw . falcon . line_offset - = bpp ;
xoffset = var - > xoffset - par - > hw . falcon . xoffset ;
par - > screen_base = screen_base +
2007-05-02 00:32:39 +04:00
( var - > yoffset * info - > var . xres_virtual + xoffset ) * bpp / 8 ;
2005-04-17 02:20:36 +04:00
if ( fbhw - > set_screen_base )
2007-05-02 00:32:39 +04:00
fbhw - > set_screen_base ( par - > screen_base ) ;
2005-04-17 02:20:36 +04:00
else
2007-05-02 00:32:39 +04:00
return - EINVAL ; /* shouldn't happen */
2005-04-17 02:20:36 +04:00
f_pan_display = 1 ;
return 0 ;
}
2007-05-02 00:32:39 +04:00
static int falcon_setcolreg ( unsigned int regno , unsigned int red ,
unsigned int green , unsigned int blue ,
unsigned int transp , struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
if ( regno > 255 )
return 1 ;
f030_col [ regno ] = ( ( ( red & 0xfc00 ) < < 16 ) |
( ( green & 0xfc00 ) < < 8 ) |
( ( blue & 0xfc00 ) > > 8 ) ) ;
if ( regno < 16 ) {
shifter_tt . color_reg [ regno ] =
( ( ( red & 0xe000 ) > > 13 ) | ( ( red & 0x1000 ) > > 12 ) < < 8 ) |
( ( ( green & 0xe000 ) > > 13 ) | ( ( green & 0x1000 ) > > 12 ) < < 4 ) |
( ( blue & 0xe000 ) > > 13 ) | ( ( blue & 0x1000 ) > > 12 ) ;
2008-11-18 23:13:01 +03:00
# ifdef ATAFB_FALCON
( ( u32 * ) info - > pseudo_palette ) [ regno ] = ( ( red & 0xf800 ) |
( ( green & 0xfc00 ) > > 5 ) |
( ( blue & 0xf800 ) > > 11 ) ) ;
2005-04-17 02:20:36 +04:00
# endif
}
return 0 ;
}
2007-05-02 00:32:39 +04:00
static int falcon_blank ( int blank_mode )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
/* ++guenther: we can switch off graphics by changing VDB and VDE,
* so VIDEL doesn ' t hog the bus while saving .
* ( this may affect usleep ( ) ) .
*/
2005-04-17 02:20:36 +04:00
int vdb , vss , hbe , hss ;
if ( mon_type = = F_MON_SM ) /* this doesn't work on SM124 */
return 1 ;
vdb = current_par . VDB ;
vss = current_par . VSS ;
hbe = current_par . HBE ;
hss = current_par . HSS ;
if ( blank_mode > = 1 ) {
/* disable graphics output (this speeds up the CPU) ... */
vdb = current_par . VFT + 1 ;
/* ... and blank all lines */
hbe = current_par . HHT + 2 ;
}
/* use VESA suspend modes on VGA monitors */
if ( mon_type = = F_MON_VGA ) {
if ( blank_mode = = 2 | | blank_mode = = 4 )
vss = current_par . VFT + 1 ;
if ( blank_mode = = 3 | | blank_mode = = 4 )
hss = current_par . HHT + 2 ;
}
videl . vdb = vdb ;
videl . vss = vss ;
videl . hbe = hbe ;
videl . hss = hss ;
return 0 ;
}
2007-05-02 00:32:39 +04:00
static int falcon_detect ( void )
2005-04-17 02:20:36 +04:00
{
struct atafb_par par ;
unsigned char fhw ;
/* Determine connected monitor and set monitor parameters */
2007-05-02 00:32:39 +04:00
fhw = * ( unsigned char * ) 0xffff8006 ;
2005-04-17 02:20:36 +04:00
mon_type = fhw > > 6 & 0x3 ;
/* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */
f030_bus_width = fhw < < 6 & 0x80 ;
switch ( mon_type ) {
case F_MON_SM :
fb_info . monspecs . vfmin = 70 ;
fb_info . monspecs . vfmax = 72 ;
fb_info . monspecs . hfmin = 35713 ;
fb_info . monspecs . hfmax = 35715 ;
break ;
case F_MON_SC :
case F_MON_TV :
/* PAL...NTSC */
2007-05-02 00:32:39 +04:00
fb_info . monspecs . vfmin = 49 ; /* not 50, since TOS defaults to 49.9x Hz */
2005-04-17 02:20:36 +04:00
fb_info . monspecs . vfmax = 60 ;
fb_info . monspecs . hfmin = 15620 ;
fb_info . monspecs . hfmax = 15755 ;
break ;
}
/* initialize hsync-len */
f25 . hsync = h_syncs [ mon_type ] / f25 . t ;
f32 . hsync = h_syncs [ mon_type ] / f32 . t ;
if ( fext . t )
fext . hsync = h_syncs [ mon_type ] / fext . t ;
falcon_get_par ( & par ) ;
falcon_encode_var ( & atafb_predefined [ 0 ] , & par ) ;
/* Detected mode is always the "autodetect" slot */
return 1 ;
}
# endif /* ATAFB_FALCON */
/* ------------------- ST(E) specific functions ---------------------- */
# ifdef ATAFB_STE
2007-05-02 00:32:39 +04:00
static int stste_encode_fix ( struct fb_fix_screeninfo * fix ,
struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
int mode ;
2007-05-02 00:32:39 +04:00
strcpy ( fix - > id , " Atari Builtin " ) ;
2005-04-17 02:20:36 +04:00
fix - > smem_start = ( unsigned long ) real_screen_base ;
fix - > smem_len = screen_len ;
fix - > type = FB_TYPE_INTERLEAVED_PLANES ;
fix - > type_aux = 2 ;
fix - > visual = FB_VISUAL_PSEUDOCOLOR ;
mode = par - > hw . st . mode & 3 ;
if ( mode = = ST_HIGH ) {
fix - > type = FB_TYPE_PACKED_PIXELS ;
fix - > type_aux = 0 ;
fix - > visual = FB_VISUAL_MONO10 ;
}
if ( ATARIHW_PRESENT ( EXTD_SHIFTER ) ) {
fix - > xpanstep = 16 ;
fix - > ypanstep = 1 ;
} else {
fix - > xpanstep = 0 ;
fix - > ypanstep = 0 ;
}
fix - > ywrapstep = 0 ;
2008-11-18 23:13:01 +03:00
fix - > line_length = par - > next_line ;
2005-04-17 02:20:36 +04:00
fix - > accel = FB_ACCEL_ATARIBLITT ;
return 0 ;
}
2007-05-02 00:32:39 +04:00
static int stste_decode_var ( struct fb_var_screeninfo * var ,
struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
int xres = var - > xres ;
int yres = var - > yres ;
int bpp = var - > bits_per_pixel ;
2005-04-17 02:20:36 +04:00
int linelen ;
int yres_virtual = var - > yres_virtual ;
if ( mono_moni ) {
if ( bpp > 1 | | xres > sttt_xres | | yres > st_yres )
return - EINVAL ;
2007-05-02 00:32:39 +04:00
par - > hw . st . mode = ST_HIGH ;
xres = sttt_xres ;
yres = st_yres ;
bpp = 1 ;
2005-04-17 02:20:36 +04:00
} else {
if ( bpp > 4 | | xres > sttt_xres | | yres > st_yres )
return - EINVAL ;
if ( bpp > 2 ) {
2007-05-02 00:32:39 +04:00
if ( xres > sttt_xres / 2 | | yres > st_yres / 2 )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-05-02 00:32:39 +04:00
par - > hw . st . mode = ST_LOW ;
xres = sttt_xres / 2 ;
yres = st_yres / 2 ;
bpp = 4 ;
} else if ( bpp > 1 ) {
if ( xres > sttt_xres | | yres > st_yres / 2 )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-05-02 00:32:39 +04:00
par - > hw . st . mode = ST_MID ;
xres = sttt_xres ;
yres = st_yres / 2 ;
bpp = 2 ;
} else
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
if ( yres_virtual < = 0 )
yres_virtual = 0 ;
else if ( yres_virtual < yres )
yres_virtual = yres ;
if ( var - > sync & FB_SYNC_EXT )
2007-05-02 00:32:39 +04:00
par - > hw . st . sync = ( par - > hw . st . sync & ~ 1 ) | 1 ;
2005-04-17 02:20:36 +04:00
else
2007-05-02 00:32:39 +04:00
par - > hw . st . sync = ( par - > hw . st . sync & ~ 1 ) ;
linelen = xres * bpp / 8 ;
2005-04-17 02:20:36 +04:00
if ( yres_virtual * linelen > screen_len & & screen_len )
return - EINVAL ;
if ( yres * linelen > screen_len & & screen_len )
return - EINVAL ;
if ( var - > yoffset + yres > yres_virtual & & yres_virtual )
return - EINVAL ;
par - > yres_virtual = yres_virtual ;
2007-05-02 00:32:39 +04:00
par - > screen_base = screen_base + var - > yoffset * linelen ;
2008-11-18 23:13:01 +03:00
par - > next_line = linelen ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-05-02 00:32:39 +04:00
static int stste_encode_var ( struct fb_var_screeninfo * var ,
struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
int linelen ;
memset ( var , 0 , sizeof ( struct fb_var_screeninfo ) ) ;
2007-05-02 00:32:39 +04:00
var - > red . offset = 0 ;
2005-04-17 02:20:36 +04:00
var - > red . length = ATARIHW_PRESENT ( EXTD_SHIFTER ) ? 4 : 3 ;
2007-05-02 00:32:39 +04:00
var - > red . msb_right = 0 ;
var - > grayscale = 0 ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
var - > pixclock = 31041 ;
var - > left_margin = 120 ; /* these are incorrect */
var - > right_margin = 100 ;
var - > upper_margin = 8 ;
var - > lower_margin = 16 ;
var - > hsync_len = 140 ;
var - > vsync_len = 30 ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
var - > height = - 1 ;
var - > width = - 1 ;
2005-04-17 02:20:36 +04:00
if ( ! ( par - > hw . st . sync & 1 ) )
2007-05-02 00:32:39 +04:00
var - > sync = 0 ;
2005-04-17 02:20:36 +04:00
else
2007-05-02 00:32:39 +04:00
var - > sync = FB_SYNC_EXT ;
2005-04-17 02:20:36 +04:00
switch ( par - > hw . st . mode & 3 ) {
case ST_LOW :
2007-05-02 00:32:39 +04:00
var - > xres = sttt_xres / 2 ;
var - > yres = st_yres / 2 ;
var - > bits_per_pixel = 4 ;
2005-04-17 02:20:36 +04:00
break ;
case ST_MID :
2007-05-02 00:32:39 +04:00
var - > xres = sttt_xres ;
var - > yres = st_yres / 2 ;
var - > bits_per_pixel = 2 ;
2005-04-17 02:20:36 +04:00
break ;
case ST_HIGH :
2007-05-02 00:32:39 +04:00
var - > xres = sttt_xres ;
var - > yres = st_yres ;
var - > bits_per_pixel = 1 ;
2005-04-17 02:20:36 +04:00
break ;
2007-05-02 00:32:39 +04:00
}
var - > blue = var - > green = var - > red ;
var - > transp . offset = 0 ;
var - > transp . length = 0 ;
var - > transp . msb_right = 0 ;
var - > xres_virtual = sttt_xres_virtual ;
linelen = var - > xres_virtual * var - > bits_per_pixel / 8 ;
ovsc_addlen = linelen * ( sttt_yres_virtual - st_yres ) ;
if ( ! use_hwscroll )
var - > yres_virtual = var - > yres ;
2005-04-17 02:20:36 +04:00
else if ( screen_len ) {
if ( par - > yres_virtual )
var - > yres_virtual = par - > yres_virtual ;
else
2007-05-02 00:32:39 +04:00
/* yres_virtual == 0 means use maximum */
2005-04-17 02:20:36 +04:00
var - > yres_virtual = screen_len / linelen ;
2007-05-02 00:32:39 +04:00
} else {
2005-04-17 02:20:36 +04:00
if ( hwscroll < 0 )
var - > yres_virtual = 2 * var - > yres ;
else
2007-05-02 00:32:39 +04:00
var - > yres_virtual = var - > yres + hwscroll * 16 ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
var - > xoffset = 0 ;
2005-04-17 02:20:36 +04:00
if ( screen_base )
2007-05-02 00:32:39 +04:00
var - > yoffset = ( par - > screen_base - screen_base ) / linelen ;
2005-04-17 02:20:36 +04:00
else
2007-05-02 00:32:39 +04:00
var - > yoffset = 0 ;
var - > nonstd = 0 ;
var - > activate = 0 ;
var - > vmode = FB_VMODE_NONINTERLACED ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-05-02 00:32:39 +04:00
static void stste_get_par ( struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
unsigned long addr ;
2007-05-02 00:32:39 +04:00
par - > hw . st . mode = shifter_tt . st_shiftmode ;
par - > hw . st . sync = shifter . syncmode ;
2005-04-17 02:20:36 +04:00
addr = ( ( shifter . bas_hi & 0xff ) < < 16 ) |
( ( shifter . bas_md & 0xff ) < < 8 ) ;
if ( ATARIHW_PRESENT ( EXTD_SHIFTER ) )
addr | = ( shifter . bas_lo & 0xff ) ;
par - > screen_base = phys_to_virt ( addr ) ;
}
2007-05-02 00:32:39 +04:00
static void stste_set_par ( struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
shifter_tt . st_shiftmode = par - > hw . st . mode ;
shifter . syncmode = par - > hw . st . sync ;
2005-04-17 02:20:36 +04:00
/* only set screen_base if really necessary */
if ( current_par . screen_base ! = par - > screen_base )
fbhw - > set_screen_base ( par - > screen_base ) ;
}
2007-05-02 00:32:39 +04:00
static int stste_setcolreg ( unsigned int regno , unsigned int red ,
unsigned int green , unsigned int blue ,
unsigned int transp , struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
if ( regno > 15 )
return 1 ;
red > > = 12 ;
blue > > = 12 ;
green > > = 12 ;
if ( ATARIHW_PRESENT ( EXTD_SHIFTER ) )
shifter_tt . color_reg [ regno ] =
( ( ( red & 0xe ) > > 1 ) | ( ( red & 1 ) < < 3 ) < < 8 ) |
( ( ( green & 0xe ) > > 1 ) | ( ( green & 1 ) < < 3 ) < < 4 ) |
( ( blue & 0xe ) > > 1 ) | ( ( blue & 1 ) < < 3 ) ;
else
shifter_tt . color_reg [ regno ] =
( ( red & 0xe ) < < 7 ) |
( ( green & 0xe ) < < 3 ) |
( ( blue & 0xe ) > > 1 ) ;
return 0 ;
}
2007-05-02 00:32:39 +04:00
static int stste_detect ( void )
{
struct atafb_par par ;
2005-04-17 02:20:36 +04:00
/* Determine the connected monitor: The DMA sound must be
* disabled before reading the MFP GPIP , because the Sound
* Done Signal and the Monochrome Detect are XORed together !
*/
if ( ATARIHW_PRESENT ( PCM_8BIT ) ) {
tt_dmasnd . ctrl = DMASND_CTRL_OFF ;
2007-05-02 00:32:39 +04:00
udelay ( 20 ) ; /* wait a while for things to settle down */
2005-04-17 02:20:36 +04:00
}
2009-02-22 11:38:47 +03:00
mono_moni = ( st_mfp . par_dt_reg & 0x80 ) = = 0 ;
2005-04-17 02:20:36 +04:00
stste_get_par ( & par ) ;
stste_encode_var ( & atafb_predefined [ 0 ] , & par ) ;
if ( ! ATARIHW_PRESENT ( EXTD_SHIFTER ) )
use_hwscroll = 0 ;
return 1 ;
}
static void stste_set_screen_base ( void * s_base )
{
unsigned long addr ;
2007-05-02 00:32:39 +04:00
addr = virt_to_phys ( s_base ) ;
2005-04-17 02:20:36 +04:00
/* Setup Screen Memory */
2007-05-02 00:32:39 +04:00
shifter . bas_hi = ( unsigned char ) ( ( addr & 0xff0000 ) > > 16 ) ;
shifter . bas_md = ( unsigned char ) ( ( addr & 0x00ff00 ) > > 8 ) ;
2005-04-17 02:20:36 +04:00
if ( ATARIHW_PRESENT ( EXTD_SHIFTER ) )
2007-05-02 00:32:39 +04:00
shifter . bas_lo = ( unsigned char ) ( addr & 0x0000ff ) ;
2005-04-17 02:20:36 +04:00
}
# endif /* ATAFB_STE */
/* Switching the screen size should be done during vsync, otherwise
* the margins may get messed up . This is a well known problem of
* the ST ' s video system .
*
* Unfortunately there is hardly any way to find the vsync , as the
* vertical blank interrupt is no longer in time on machines with
* overscan type modifications .
*
* We can , however , use Timer B to safely detect the black shoulder ,
* but then we ' ve got to guess an appropriate delay to find the vsync .
* This might not work on every machine .
*
* martin_rogge @ ki . maus . de , 8 th Aug 1995
*/
# define LINE_DELAY (mono_moni ? 30 : 70)
# define SYNC_DELAY (mono_moni ? 1500 : 2000)
/* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */
static void st_ovsc_switch ( void )
{
2007-05-02 00:32:39 +04:00
unsigned long flags ;
register unsigned char old , new ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
if ( ! ( atari_switches & ATARI_SWITCH_OVSC_MASK ) )
return ;
local_irq_save ( flags ) ;
2009-02-22 11:38:47 +03:00
st_mfp . tim_ct_b = 0x10 ;
st_mfp . active_edge | = 8 ;
st_mfp . tim_ct_b = 0 ;
st_mfp . tim_dt_b = 0xf0 ;
st_mfp . tim_ct_b = 8 ;
while ( st_mfp . tim_dt_b > 1 ) /* TOS does it this way, don't ask why */
2007-05-02 00:32:39 +04:00
;
2009-02-22 11:38:47 +03:00
new = st_mfp . tim_dt_b ;
2007-05-02 00:32:39 +04:00
do {
udelay ( LINE_DELAY ) ;
old = new ;
2009-02-22 11:38:47 +03:00
new = st_mfp . tim_dt_b ;
2007-05-02 00:32:39 +04:00
} while ( old ! = new ) ;
2009-02-22 11:38:47 +03:00
st_mfp . tim_ct_b = 0x10 ;
2007-05-02 00:32:39 +04:00
udelay ( SYNC_DELAY ) ;
if ( atari_switches & ATARI_SWITCH_OVSC_IKBD )
acia . key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE ;
if ( atari_switches & ATARI_SWITCH_OVSC_MIDI )
acia . mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID ;
if ( atari_switches & ( ATARI_SWITCH_OVSC_SND6 | ATARI_SWITCH_OVSC_SND7 ) ) {
sound_ym . rd_data_reg_sel = 14 ;
sound_ym . wd_data = sound_ym . rd_data_reg_sel |
( ( atari_switches & ATARI_SWITCH_OVSC_SND6 ) ? 0x40 : 0 ) |
( ( atari_switches & ATARI_SWITCH_OVSC_SND7 ) ? 0x80 : 0 ) ;
}
local_irq_restore ( flags ) ;
2005-04-17 02:20:36 +04:00
}
/* ------------------- External Video ---------------------- */
# ifdef ATAFB_EXT
2007-05-02 00:32:39 +04:00
static int ext_encode_fix ( struct fb_fix_screeninfo * fix , struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
strcpy ( fix - > id , " Unknown Extern " ) ;
2005-04-17 02:20:36 +04:00
fix - > smem_start = ( unsigned long ) external_addr ;
fix - > smem_len = PAGE_ALIGN ( external_len ) ;
if ( external_depth = = 1 ) {
fix - > type = FB_TYPE_PACKED_PIXELS ;
/* The letters 'n' and 'i' in the "atavideo=external:" stand
* for " normal " and " inverted " , rsp . , in the monochrome case */
fix - > visual =
( external_pmode = = FB_TYPE_INTERLEAVED_PLANES | |
external_pmode = = FB_TYPE_PACKED_PIXELS ) ?
2007-05-02 00:32:39 +04:00
FB_VISUAL_MONO10 : FB_VISUAL_MONO01 ;
} else {
2005-04-17 02:20:36 +04:00
/* Use STATIC if we don't know how to access color registers */
int visual = external_vgaiobase ?
FB_VISUAL_PSEUDOCOLOR :
FB_VISUAL_STATIC_PSEUDOCOLOR ;
switch ( external_pmode ) {
2007-05-02 00:32:39 +04:00
case - 1 : /* truecolor */
fix - > type = FB_TYPE_PACKED_PIXELS ;
fix - > visual = FB_VISUAL_TRUECOLOR ;
2005-04-17 02:20:36 +04:00
break ;
2007-05-02 00:32:39 +04:00
case FB_TYPE_PACKED_PIXELS :
fix - > type = FB_TYPE_PACKED_PIXELS ;
fix - > visual = visual ;
2005-04-17 02:20:36 +04:00
break ;
2007-05-02 00:32:39 +04:00
case FB_TYPE_PLANES :
fix - > type = FB_TYPE_PLANES ;
fix - > visual = visual ;
2005-04-17 02:20:36 +04:00
break ;
2007-05-02 00:32:39 +04:00
case FB_TYPE_INTERLEAVED_PLANES :
fix - > type = FB_TYPE_INTERLEAVED_PLANES ;
fix - > type_aux = 2 ;
fix - > visual = visual ;
2005-04-17 02:20:36 +04:00
break ;
}
}
fix - > xpanstep = 0 ;
fix - > ypanstep = 0 ;
fix - > ywrapstep = 0 ;
2008-11-18 23:13:01 +03:00
fix - > line_length = par - > next_line ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-05-02 00:32:39 +04:00
static int ext_decode_var ( struct fb_var_screeninfo * var , struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
struct fb_var_screeninfo * myvar = & atafb_predefined [ 0 ] ;
2007-05-02 00:32:39 +04:00
2005-04-17 02:20:36 +04:00
if ( var - > bits_per_pixel > myvar - > bits_per_pixel | |
2007-05-02 00:32:39 +04:00
var - > xres > myvar - > xres | |
var - > xres_virtual > myvar - > xres_virtual | |
var - > yres > myvar - > yres | |
var - > xoffset > 0 | |
var - > yoffset > 0 )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2008-11-18 23:13:01 +03:00
par - > next_line = external_xres_virtual * external_depth / 8 ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-05-02 00:32:39 +04:00
static int ext_encode_var ( struct fb_var_screeninfo * var , struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
memset ( var , 0 , sizeof ( struct fb_var_screeninfo ) ) ;
2007-05-02 00:32:39 +04:00
var - > red . offset = 0 ;
var - > red . length = ( external_pmode = = - 1 ) ? external_depth / 3 :
2005-04-17 02:20:36 +04:00
( external_vgaiobase ? external_bitspercol : 0 ) ;
2007-05-02 00:32:39 +04:00
var - > red . msb_right = 0 ;
var - > grayscale = 0 ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
var - > pixclock = 31041 ;
var - > left_margin = 120 ; /* these are surely incorrect */
var - > right_margin = 100 ;
var - > upper_margin = 8 ;
var - > lower_margin = 16 ;
var - > hsync_len = 140 ;
var - > vsync_len = 30 ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
var - > height = - 1 ;
var - > width = - 1 ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
var - > sync = 0 ;
2005-04-17 02:20:36 +04:00
var - > xres = external_xres ;
var - > yres = external_yres ;
var - > xres_virtual = external_xres_virtual ;
var - > bits_per_pixel = external_depth ;
2007-05-02 00:32:39 +04:00
var - > blue = var - > green = var - > red ;
var - > transp . offset = 0 ;
var - > transp . length = 0 ;
var - > transp . msb_right = 0 ;
var - > yres_virtual = var - > yres ;
var - > xoffset = 0 ;
var - > yoffset = 0 ;
var - > nonstd = 0 ;
var - > activate = 0 ;
var - > vmode = FB_VMODE_NONINTERLACED ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-05-02 00:32:39 +04:00
static void ext_get_par ( struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
par - > screen_base = external_addr ;
}
2007-05-02 00:32:39 +04:00
static void ext_set_par ( struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
}
# define OUTB(port,val) \
2007-05-02 00:32:39 +04:00
* ( ( unsigned volatile char * ) ( ( port ) + external_vgaiobase ) ) = ( val )
2005-04-17 02:20:36 +04:00
# define INB(port) \
( * ( ( unsigned volatile char * ) ( ( port ) + external_vgaiobase ) ) )
2007-05-02 00:32:39 +04:00
# define DACDelay \
2005-04-17 02:20:36 +04:00
do { \
2007-05-02 00:32:39 +04:00
unsigned char tmp = INB ( 0x3da ) ; \
tmp = INB ( 0x3da ) ; \
2005-04-17 02:20:36 +04:00
} while ( 0 )
2007-05-02 00:32:39 +04:00
static int ext_setcolreg ( unsigned int regno , unsigned int red ,
unsigned int green , unsigned int blue ,
unsigned int transp , struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
unsigned char colmask = ( 1 < < external_bitspercol ) - 1 ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
if ( ! external_vgaiobase )
2005-04-17 02:20:36 +04:00
return 1 ;
2009-10-24 19:18:23 +04:00
if ( regno > 255 )
return 1 ;
2005-04-17 02:20:36 +04:00
switch ( external_card_type ) {
2007-05-02 00:32:39 +04:00
case IS_VGA :
OUTB ( 0x3c8 , regno ) ;
DACDelay ;
OUTB ( 0x3c9 , red & colmask ) ;
DACDelay ;
OUTB ( 0x3c9 , green & colmask ) ;
DACDelay ;
OUTB ( 0x3c9 , blue & colmask ) ;
DACDelay ;
return 0 ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
case IS_MV300 :
OUTB ( ( MV300_reg [ regno ] < < 2 ) + 1 , red ) ;
OUTB ( ( MV300_reg [ regno ] < < 2 ) + 1 , green ) ;
OUTB ( ( MV300_reg [ regno ] < < 2 ) + 1 , blue ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
default :
return 1 ;
}
}
static int ext_detect ( void )
2005-04-17 02:20:36 +04:00
{
struct fb_var_screeninfo * myvar = & atafb_predefined [ 0 ] ;
struct atafb_par dummy_par ;
myvar - > xres = external_xres ;
myvar - > xres_virtual = external_xres_virtual ;
myvar - > yres = external_yres ;
myvar - > bits_per_pixel = external_depth ;
ext_encode_var ( myvar , & dummy_par ) ;
return 1 ;
}
# endif /* ATAFB_EXT */
/* ------ This is the same for most hardware types -------- */
static void set_screen_base ( void * s_base )
{
unsigned long addr ;
2007-05-02 00:32:39 +04:00
addr = virt_to_phys ( s_base ) ;
2005-04-17 02:20:36 +04:00
/* Setup Screen Memory */
2007-05-02 00:32:39 +04:00
shifter . bas_hi = ( unsigned char ) ( ( addr & 0xff0000 ) > > 16 ) ;
shifter . bas_md = ( unsigned char ) ( ( addr & 0x00ff00 ) > > 8 ) ;
shifter . bas_lo = ( unsigned char ) ( addr & 0x0000ff ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
static int pan_display ( struct fb_var_screeninfo * var , struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
struct atafb_par * par = ( struct atafb_par * ) info - > par ;
2005-04-17 02:20:36 +04:00
if ( ! fbhw - > set_screen_base | |
2007-05-02 00:32:39 +04:00
( ! ATARIHW_PRESENT ( EXTD_SHIFTER ) & & var - > xoffset ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
var - > xoffset = up ( var - > xoffset , 16 ) ;
par - > screen_base = screen_base +
2007-05-02 00:32:39 +04:00
( var - > yoffset * info - > var . xres_virtual + var - > xoffset )
* info - > var . bits_per_pixel / 8 ;
fbhw - > set_screen_base ( par - > screen_base ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* ------------ Interfaces to hardware functions ------------ */
# ifdef ATAFB_TT
static struct fb_hwswitch tt_switch = {
2007-05-02 00:32:39 +04:00
. detect = tt_detect ,
. encode_fix = tt_encode_fix ,
. decode_var = tt_decode_var ,
. encode_var = tt_encode_var ,
. get_par = tt_get_par ,
. set_par = tt_set_par ,
. set_screen_base = set_screen_base ,
. pan_display = pan_display ,
2005-04-17 02:20:36 +04:00
} ;
# endif
# ifdef ATAFB_FALCON
static struct fb_hwswitch falcon_switch = {
2007-05-02 00:32:39 +04:00
. detect = falcon_detect ,
. encode_fix = falcon_encode_fix ,
. decode_var = falcon_decode_var ,
. encode_var = falcon_encode_var ,
. get_par = falcon_get_par ,
. set_par = falcon_set_par ,
. set_screen_base = set_screen_base ,
. blank = falcon_blank ,
. pan_display = falcon_pan_display ,
2005-04-17 02:20:36 +04:00
} ;
# endif
# ifdef ATAFB_STE
static struct fb_hwswitch st_switch = {
2007-05-02 00:32:39 +04:00
. detect = stste_detect ,
. encode_fix = stste_encode_fix ,
. decode_var = stste_decode_var ,
. encode_var = stste_encode_var ,
. get_par = stste_get_par ,
. set_par = stste_set_par ,
. set_screen_base = stste_set_screen_base ,
. pan_display = pan_display
2005-04-17 02:20:36 +04:00
} ;
# endif
# ifdef ATAFB_EXT
static struct fb_hwswitch ext_switch = {
2007-05-02 00:32:39 +04:00
. detect = ext_detect ,
. encode_fix = ext_encode_fix ,
. decode_var = ext_decode_var ,
. encode_var = ext_encode_var ,
. get_par = ext_get_par ,
. set_par = ext_set_par ,
2005-04-17 02:20:36 +04:00
} ;
# endif
2007-05-02 00:32:39 +04:00
static void ata_get_par ( struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
if ( current_par_valid )
* par = current_par ;
2005-04-17 02:20:36 +04:00
else
fbhw - > get_par ( par ) ;
}
2007-05-02 00:32:39 +04:00
static void ata_set_par ( struct atafb_par * par )
2005-04-17 02:20:36 +04:00
{
fbhw - > set_par ( par ) ;
2007-05-02 00:32:39 +04:00
current_par = * par ;
current_par_valid = 1 ;
2005-04-17 02:20:36 +04:00
}
/* =========================================================== */
/* ============== Hardware Independent Functions ============= */
/* =========================================================== */
/* used for hardware scrolling */
2007-05-02 00:32:39 +04:00
static int do_fb_set_var ( struct fb_var_screeninfo * var , int isactive )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
int err , activate ;
2005-04-17 02:20:36 +04:00
struct atafb_par par ;
2007-05-02 00:32:39 +04:00
err = fbhw - > decode_var ( var , & par ) ;
if ( err )
2005-04-17 02:20:36 +04:00
return err ;
2007-05-02 00:32:39 +04:00
activate = var - > activate ;
2005-04-17 02:20:36 +04:00
if ( ( ( var - > activate & FB_ACTIVATE_MASK ) = = FB_ACTIVATE_NOW ) & & isactive )
2007-05-02 00:32:39 +04:00
ata_set_par ( & par ) ;
2005-04-17 02:20:36 +04:00
fbhw - > encode_var ( var , & par ) ;
2007-05-02 00:32:39 +04:00
var - > activate = activate ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-07-07 21:15:16 +04:00
/* fbhw->encode_fix() must be called with fb_info->mm_lock held
* if it is called after the register_framebuffer ( ) - not a case here
*/
2007-05-02 00:32:39 +04:00
static int atafb_get_fix ( struct fb_fix_screeninfo * fix , struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
struct atafb_par par ;
2007-05-02 00:32:39 +04:00
int err ;
// Get fix directly (case con == -1 before)??
err = fbhw - > decode_var ( & info - > var , & par ) ;
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
memset ( fix , 0 , sizeof ( struct fb_fix_screeninfo ) ) ;
2009-06-30 22:41:29 +04:00
err = fbhw - > encode_fix ( fix , & par ) ;
return err ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
static int atafb_get_var ( struct fb_var_screeninfo * var , struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
struct atafb_par par ;
2007-05-02 00:32:39 +04:00
ata_get_par ( & par ) ;
fbhw - > encode_var ( var , & par ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-05-02 00:32:39 +04:00
// No longer called by fbcon!
// Still called by set_var internally
static void atafb_set_disp ( struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
atafb_get_var ( & info - > var , info ) ;
atafb_get_fix ( & info - > fix , info ) ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
info - > screen_base = ( void * ) info - > fix . smem_start ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
static int atafb_setcolreg ( u_int regno , u_int red , u_int green , u_int blue ,
u_int transp , struct fb_info * info )
{
red > > = 8 ;
green > > = 8 ;
blue > > = 8 ;
return info - > fbops - > fb_setcolreg ( regno , red , green , blue , transp , info ) ;
}
2005-04-17 02:20:36 +04:00
static int
2007-05-02 00:32:39 +04:00
atafb_pan_display ( struct fb_var_screeninfo * var , struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
int xoffset = var - > xoffset ;
int yoffset = var - > yoffset ;
int err ;
if ( var - > vmode & FB_VMODE_YWRAP ) {
if ( yoffset < 0 | | yoffset > = info - > var . yres_virtual | | xoffset )
return - EINVAL ;
} else {
if ( xoffset + info - > var . xres > info - > var . xres_virtual | |
yoffset + info - > var . yres > info - > var . yres_virtual )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
if ( fbhw - > pan_display ) {
err = fbhw - > pan_display ( var , info ) ;
if ( err )
return err ;
} else
return - EINVAL ;
info - > var . xoffset = xoffset ;
info - > var . yoffset = yoffset ;
if ( var - > vmode & FB_VMODE_YWRAP )
info - > var . vmode | = FB_VMODE_YWRAP ;
else
info - > var . vmode & = ~ FB_VMODE_YWRAP ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-05-02 00:32:39 +04:00
/*
* generic drawing routines ; imageblit needs updating for image depth > 1
*/
# if BITS_PER_LONG == 32
# define BYTES_PER_LONG 4
# define SHIFT_PER_LONG 5
# elif BITS_PER_LONG == 64
# define BYTES_PER_LONG 8
# define SHIFT_PER_LONG 6
# else
# define Please update me
# endif
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
static void atafb_fillrect ( struct fb_info * info , const struct fb_fillrect * rect )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
struct atafb_par * par = ( struct atafb_par * ) info - > par ;
int x2 , y2 ;
u32 width , height ;
if ( ! rect - > width | | ! rect - > height )
return ;
2008-11-18 23:13:01 +03:00
# ifdef ATAFB_FALCON
if ( info - > var . bits_per_pixel = = 16 ) {
cfb_fillrect ( info , rect ) ;
return ;
}
# endif
2007-05-02 00:32:39 +04:00
/*
* We could use hardware clipping but on many cards you get around
* hardware clipping by writing to framebuffer directly .
* */
x2 = rect - > dx + rect - > width ;
y2 = rect - > dy + rect - > height ;
x2 = x2 < info - > var . xres_virtual ? x2 : info - > var . xres_virtual ;
y2 = y2 < info - > var . yres_virtual ? y2 : info - > var . yres_virtual ;
width = x2 - rect - > dx ;
height = y2 - rect - > dy ;
if ( info - > var . bits_per_pixel = = 1 )
atafb_mfb_fillrect ( info , par - > next_line , rect - > color ,
rect - > dy , rect - > dx , height , width ) ;
else if ( info - > var . bits_per_pixel = = 2 )
atafb_iplan2p2_fillrect ( info , par - > next_line , rect - > color ,
rect - > dy , rect - > dx , height , width ) ;
else if ( info - > var . bits_per_pixel = = 4 )
atafb_iplan2p4_fillrect ( info , par - > next_line , rect - > color ,
rect - > dy , rect - > dx , height , width ) ;
2005-04-17 02:20:36 +04:00
else
2007-05-02 00:32:39 +04:00
atafb_iplan2p8_fillrect ( info , par - > next_line , rect - > color ,
rect - > dy , rect - > dx , height , width ) ;
return ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
static void atafb_copyarea ( struct fb_info * info , const struct fb_copyarea * area )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
struct atafb_par * par = ( struct atafb_par * ) info - > par ;
int x2 , y2 ;
u32 dx , dy , sx , sy , width , height ;
int rev_copy = 0 ;
2008-11-18 23:13:01 +03:00
# ifdef ATAFB_FALCON
if ( info - > var . bits_per_pixel = = 16 ) {
cfb_copyarea ( info , area ) ;
return ;
}
# endif
2007-05-02 00:32:39 +04:00
/* clip the destination */
x2 = area - > dx + area - > width ;
y2 = area - > dy + area - > height ;
dx = area - > dx > 0 ? area - > dx : 0 ;
dy = area - > dy > 0 ? area - > dy : 0 ;
x2 = x2 < info - > var . xres_virtual ? x2 : info - > var . xres_virtual ;
y2 = y2 < info - > var . yres_virtual ? y2 : info - > var . yres_virtual ;
width = x2 - dx ;
height = y2 - dy ;
2008-07-24 08:31:18 +04:00
if ( area - > sx + dx < area - > dx | | area - > sy + dy < area - > dy )
return ;
2007-05-02 00:32:39 +04:00
/* update sx,sy */
sx = area - > sx + ( dx - area - > dx ) ;
sy = area - > sy + ( dy - area - > dy ) ;
/* the source must be completely inside the virtual screen */
2008-07-24 08:31:18 +04:00
if ( sx + width > info - > var . xres_virtual | |
sy + height > info - > var . yres_virtual )
2007-05-02 00:32:39 +04:00
return ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
if ( dy > sy | | ( dy = = sy & & dx > sx ) ) {
dy + = height ;
sy + = height ;
rev_copy = 1 ;
}
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
if ( info - > var . bits_per_pixel = = 1 )
atafb_mfb_copyarea ( info , par - > next_line , sy , sx , dy , dx , height , width ) ;
else if ( info - > var . bits_per_pixel = = 2 )
atafb_iplan2p2_copyarea ( info , par - > next_line , sy , sx , dy , dx , height , width ) ;
else if ( info - > var . bits_per_pixel = = 4 )
atafb_iplan2p4_copyarea ( info , par - > next_line , sy , sx , dy , dx , height , width ) ;
else
atafb_iplan2p8_copyarea ( info , par - > next_line , sy , sx , dy , dx , height , width ) ;
return ;
}
static void atafb_imageblit ( struct fb_info * info , const struct fb_image * image )
{
struct atafb_par * par = ( struct atafb_par * ) info - > par ;
int x2 , y2 ;
unsigned long * dst ;
int dst_idx ;
const char * src ;
u32 dx , dy , width , height , pitch ;
2008-11-18 23:13:01 +03:00
# ifdef ATAFB_FALCON
if ( info - > var . bits_per_pixel = = 16 ) {
cfb_imageblit ( info , image ) ;
return ;
}
# endif
2007-05-02 00:32:39 +04:00
/*
* We could use hardware clipping but on many cards you get around
* hardware clipping by writing to framebuffer directly like we are
* doing here .
*/
x2 = image - > dx + image - > width ;
y2 = image - > dy + image - > height ;
dx = image - > dx ;
dy = image - > dy ;
x2 = x2 < info - > var . xres_virtual ? x2 : info - > var . xres_virtual ;
y2 = y2 < info - > var . yres_virtual ? y2 : info - > var . yres_virtual ;
width = x2 - dx ;
height = y2 - dy ;
if ( image - > depth = = 1 ) {
// used for font data
dst = ( unsigned long * )
( ( unsigned long ) info - > screen_base & ~ ( BYTES_PER_LONG - 1 ) ) ;
dst_idx = ( ( unsigned long ) info - > screen_base & ( BYTES_PER_LONG - 1 ) ) * 8 ;
dst_idx + = dy * par - > next_line * 8 + dx ;
src = image - > data ;
pitch = ( image - > width + 7 ) / 8 ;
while ( height - - ) {
if ( info - > var . bits_per_pixel = = 1 )
atafb_mfb_linefill ( info , par - > next_line ,
dy , dx , width , src ,
image - > bg_color , image - > fg_color ) ;
else if ( info - > var . bits_per_pixel = = 2 )
atafb_iplan2p2_linefill ( info , par - > next_line ,
dy , dx , width , src ,
image - > bg_color , image - > fg_color ) ;
else if ( info - > var . bits_per_pixel = = 4 )
atafb_iplan2p4_linefill ( info , par - > next_line ,
dy , dx , width , src ,
image - > bg_color , image - > fg_color ) ;
else
atafb_iplan2p8_linefill ( info , par - > next_line ,
dy , dx , width , src ,
image - > bg_color , image - > fg_color ) ;
dy + + ;
src + = pitch ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
} else {
2008-12-21 17:48:12 +03:00
c2p_iplan2 ( info - > screen_base , image - > data , dx , dy , width ,
height , par - > next_line , image - > width ,
info - > var . bits_per_pixel ) ;
2005-04-17 02:20:36 +04:00
}
}
static int
2006-01-15 00:21:25 +03:00
atafb_ioctl ( struct fb_info * info , unsigned int cmd , unsigned long arg )
2005-04-17 02:20:36 +04:00
{
switch ( cmd ) {
# ifdef FBCMD_GET_CURRENTPAR
case FBCMD_GET_CURRENTPAR :
if ( copy_to_user ( ( void * ) arg , ( void * ) & current_par ,
sizeof ( struct atafb_par ) ) )
return - EFAULT ;
return 0 ;
# endif
# ifdef FBCMD_SET_CURRENTPAR
case FBCMD_SET_CURRENTPAR :
if ( copy_from_user ( ( void * ) & current_par , ( void * ) arg ,
sizeof ( struct atafb_par ) ) )
return - EFAULT ;
2007-05-02 00:32:39 +04:00
ata_set_par ( & current_par ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
# endif
}
return - EINVAL ;
}
/* (un)blank/poweroff
* 0 = unblank
* 1 = blank
* 2 = suspend vsync
* 3 = suspend hsync
* 4 = off
*/
2007-05-02 00:32:39 +04:00
static int atafb_blank ( int blank , struct fb_info * info )
2005-04-17 02:20:36 +04:00
{
unsigned short black [ 16 ] ;
struct fb_cmap cmap ;
if ( fbhw - > blank & & ! fbhw - > blank ( blank ) )
return 1 ;
if ( blank ) {
2007-05-02 00:32:39 +04:00
memset ( black , 0 , 16 * sizeof ( unsigned short ) ) ;
cmap . red = black ;
cmap . green = black ;
cmap . blue = black ;
cmap . transp = NULL ;
cmap . start = 0 ;
cmap . len = 16 ;
fb_set_cmap ( & cmap , info ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
#if 0
2005-04-17 02:20:36 +04:00
else
2007-05-02 00:32:39 +04:00
do_install_cmap ( info ) ;
# endif
return 0 ;
}
/*
* New fbcon interface . . .
*/
/* check var by decoding var into hw par, rounding if necessary,
* then encoding hw par back into new , validated var */
static int atafb_check_var ( struct fb_var_screeninfo * var , struct fb_info * info )
{
int err ;
struct atafb_par par ;
/* Validate wanted screen parameters */
// if ((err = ata_decode_var(var, &par)))
err = fbhw - > decode_var ( var , & par ) ;
if ( err )
return err ;
/* Encode (possibly rounded) screen parameters */
fbhw - > encode_var ( var , & par ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-05-02 00:32:39 +04:00
/* actually set hw par by decoding var, then setting hardware from
* hw par just decoded */
static int atafb_set_par ( struct fb_info * info )
{
struct atafb_par * par = ( struct atafb_par * ) info - > par ;
/* Decode wanted screen parameters */
fbhw - > decode_var ( & info - > var , par ) ;
2009-06-30 22:41:29 +04:00
mutex_lock ( & info - > mm_lock ) ;
2007-05-02 00:32:39 +04:00
fbhw - > encode_fix ( & info - > fix , par ) ;
2009-06-30 22:41:29 +04:00
mutex_unlock ( & info - > mm_lock ) ;
2007-05-02 00:32:39 +04:00
/* Set new videomode */
ata_set_par ( par ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
static struct fb_ops atafb_ops = {
. owner = THIS_MODULE ,
2007-05-02 00:32:39 +04:00
. fb_check_var = atafb_check_var ,
. fb_set_par = atafb_set_par ,
. fb_setcolreg = atafb_setcolreg ,
2005-04-17 02:20:36 +04:00
. fb_blank = atafb_blank ,
2007-05-02 00:32:39 +04:00
. fb_pan_display = atafb_pan_display ,
. fb_fillrect = atafb_fillrect ,
. fb_copyarea = atafb_copyarea ,
. fb_imageblit = atafb_imageblit ,
2005-04-17 02:20:36 +04:00
. fb_ioctl = atafb_ioctl ,
} ;
2007-05-02 00:32:39 +04:00
static void check_default_par ( int detected_mode )
2005-04-17 02:20:36 +04:00
{
char default_name [ 10 ] ;
int i ;
struct fb_var_screeninfo var ;
unsigned long min_mem ;
/* First try the user supplied mode */
if ( default_par ) {
2007-05-02 00:32:39 +04:00
var = atafb_predefined [ default_par - 1 ] ;
2005-04-17 02:20:36 +04:00
var . activate = FB_ACTIVATE_TEST ;
2007-05-02 00:32:39 +04:00
if ( do_fb_set_var ( & var , 1 ) )
default_par = 0 ; /* failed */
2005-04-17 02:20:36 +04:00
}
/* Next is the autodetected one */
2007-05-02 00:32:39 +04:00
if ( ! default_par ) {
var = atafb_predefined [ detected_mode - 1 ] ; /* autodetect */
2005-04-17 02:20:36 +04:00
var . activate = FB_ACTIVATE_TEST ;
2007-05-02 00:32:39 +04:00
if ( ! do_fb_set_var ( & var , 1 ) )
default_par = detected_mode ;
2005-04-17 02:20:36 +04:00
}
/* If that also failed, try some default modes... */
2007-05-02 00:32:39 +04:00
if ( ! default_par ) {
2005-04-17 02:20:36 +04:00
/* try default1, default2... */
2007-05-02 00:32:39 +04:00
for ( i = 1 ; i < 10 ; i + + ) {
sprintf ( default_name , " default%d " , i ) ;
default_par = get_video_mode ( default_name ) ;
if ( ! default_par )
2005-04-17 02:20:36 +04:00
panic ( " can't set default video mode " ) ;
2007-05-02 00:32:39 +04:00
var = atafb_predefined [ default_par - 1 ] ;
2005-04-17 02:20:36 +04:00
var . activate = FB_ACTIVATE_TEST ;
2007-05-02 00:32:39 +04:00
if ( ! do_fb_set_var ( & var , 1 ) )
2005-04-17 02:20:36 +04:00
break ; /* ok */
}
}
2007-05-02 00:32:39 +04:00
min_mem = var . xres_virtual * var . yres_virtual * var . bits_per_pixel / 8 ;
2005-04-17 02:20:36 +04:00
if ( default_mem_req < min_mem )
2007-05-02 00:32:39 +04:00
default_mem_req = min_mem ;
2005-04-17 02:20:36 +04:00
}
# ifdef ATAFB_EXT
static void __init atafb_setup_ext ( char * spec )
{
2007-05-02 00:32:39 +04:00
int xres , xres_virtual , yres , depth , planes ;
2005-04-17 02:20:36 +04:00
unsigned long addr , len ;
char * p ;
/* Format is: <xres>;<yres>;<depth>;<plane organ.>;
* < screen mem addr >
* [ ; < screen mem length > [ ; < vgaiobase > [ ; < bits - per - col > [ ; < colorreg - type >
* [ ; < xres - virtual > ] ] ] ] ]
*
* 09 / 23 / 97 Juergen
* < xres_virtual > : hardware ' s x - resolution ( f . e . ProMST )
*
* Even xres_virtual is available , we neither support panning nor hw - scrolling !
*/
2007-05-02 00:32:39 +04:00
p = strsep ( & spec , " ; " ) ;
if ( ! p | | ! * p )
return ;
2005-04-17 02:20:36 +04:00
xres_virtual = xres = simple_strtoul ( p , NULL , 10 ) ;
if ( xres < = 0 )
2007-05-02 00:32:39 +04:00
return ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
p = strsep ( & spec , " ; " ) ;
if ( ! p | | ! * p )
return ;
2005-04-17 02:20:36 +04:00
yres = simple_strtoul ( p , NULL , 10 ) ;
if ( yres < = 0 )
2007-05-02 00:32:39 +04:00
return ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
p = strsep ( & spec , " ; " ) ;
if ( ! p | | ! * p )
return ;
2005-04-17 02:20:36 +04:00
depth = simple_strtoul ( p , NULL , 10 ) ;
if ( depth ! = 1 & & depth ! = 2 & & depth ! = 4 & & depth ! = 8 & &
2007-05-02 00:32:39 +04:00
depth ! = 16 & & depth ! = 24 )
return ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
p = strsep ( & spec , " ; " ) ;
if ( ! p | | ! * p )
return ;
2005-04-17 02:20:36 +04:00
if ( * p = = ' i ' )
planes = FB_TYPE_INTERLEAVED_PLANES ;
else if ( * p = = ' p ' )
planes = FB_TYPE_PACKED_PIXELS ;
else if ( * p = = ' n ' )
planes = FB_TYPE_PLANES ;
else if ( * p = = ' t ' )
2007-05-02 00:32:39 +04:00
planes = - 1 ; /* true color */
2005-04-17 02:20:36 +04:00
else
return ;
2007-05-02 00:32:39 +04:00
p = strsep ( & spec , " ; " ) ;
if ( ! p | | ! * p )
2005-04-17 02:20:36 +04:00
return ;
addr = simple_strtoul ( p , NULL , 0 ) ;
2007-05-02 00:32:39 +04:00
p = strsep ( & spec , " ; " ) ;
if ( ! p | | ! * p )
len = xres * yres * depth / 8 ;
2005-04-17 02:20:36 +04:00
else
len = simple_strtoul ( p , NULL , 0 ) ;
2007-05-02 00:32:39 +04:00
p = strsep ( & spec , " ; " ) ;
if ( p & & * p )
external_vgaiobase = simple_strtoul ( p , NULL , 0 ) ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
p = strsep ( & spec , " ; " ) ;
if ( p & & * p ) {
2005-04-17 02:20:36 +04:00
external_bitspercol = simple_strtoul ( p , NULL , 0 ) ;
if ( external_bitspercol > 8 )
external_bitspercol = 8 ;
else if ( external_bitspercol < 1 )
external_bitspercol = 1 ;
}
2007-05-02 00:32:39 +04:00
p = strsep ( & spec , " ; " ) ;
if ( p & & * p ) {
2005-04-17 02:20:36 +04:00
if ( ! strcmp ( p , " vga " ) )
external_card_type = IS_VGA ;
if ( ! strcmp ( p , " mv300 " ) )
external_card_type = IS_MV300 ;
}
2007-05-02 00:32:39 +04:00
p = strsep ( & spec , " ; " ) ;
if ( p & & * p ) {
2005-04-17 02:20:36 +04:00
xres_virtual = simple_strtoul ( p , NULL , 10 ) ;
if ( xres_virtual < xres )
xres_virtual = xres ;
2007-05-02 00:32:39 +04:00
if ( xres_virtual * yres * depth / 8 > len )
len = xres_virtual * yres * depth / 8 ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
external_xres = xres ;
external_xres_virtual = xres_virtual ;
external_yres = yres ;
2005-04-17 02:20:36 +04:00
external_depth = depth ;
external_pmode = planes ;
2007-05-02 00:32:39 +04:00
external_addr = ( void * ) addr ;
external_len = len ;
if ( external_card_type = = IS_MV300 ) {
switch ( external_depth ) {
case 1 :
MV300_reg = MV300_reg_1bit ;
break ;
case 4 :
MV300_reg = MV300_reg_4bit ;
break ;
case 8 :
MV300_reg = MV300_reg_8bit ;
break ;
}
}
2005-04-17 02:20:36 +04:00
}
# endif /* ATAFB_EXT */
static void __init atafb_setup_int ( char * spec )
{
/* Format to config extended internal video hardware like OverScan:
2007-05-02 00:32:39 +04:00
* " internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset> "
* Explanation :
* < xres > : x - resolution
* < yres > : y - resolution
* The following are only needed if you have an overscan which
* needs a black border :
* < xres_max > : max . length of a line in pixels your OverScan hardware would allow
* < yres_max > : max . number of lines your OverScan hardware would allow
* < offset > : Offset from physical beginning to visible beginning
* of screen in bytes
*/
2005-04-17 02:20:36 +04:00
int xres ;
char * p ;
if ( ! ( p = strsep ( & spec , " ; " ) ) | | ! * p )
return ;
xres = simple_strtoul ( p , NULL , 10 ) ;
if ( ! ( p = strsep ( & spec , " ; " ) ) | | ! * p )
return ;
2007-05-02 00:32:39 +04:00
sttt_xres = xres ;
tt_yres = st_yres = simple_strtoul ( p , NULL , 10 ) ;
if ( ( p = strsep ( & spec , " ; " ) ) & & * p )
sttt_xres_virtual = simple_strtoul ( p , NULL , 10 ) ;
if ( ( p = strsep ( & spec , " ; " ) ) & & * p )
sttt_yres_virtual = simple_strtoul ( p , NULL , 0 ) ;
if ( ( p = strsep ( & spec , " ; " ) ) & & * p )
ovsc_offset = simple_strtoul ( p , NULL , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( ovsc_offset | | ( sttt_yres_virtual ! = st_yres ) )
2007-05-02 00:32:39 +04:00
use_hwscroll = 0 ;
2005-04-17 02:20:36 +04:00
}
# ifdef ATAFB_FALCON
static void __init atafb_setup_mcap ( char * spec )
{
char * p ;
int vmin , vmax , hmin , hmax ;
/* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
* < V * > vertical freq . in Hz
* < H * > horizontal freq . in kHz
*/
if ( ! ( p = strsep ( & spec , " ; " ) ) | | ! * p )
return ;
vmin = simple_strtoul ( p , NULL , 10 ) ;
if ( vmin < = 0 )
return ;
if ( ! ( p = strsep ( & spec , " ; " ) ) | | ! * p )
return ;
vmax = simple_strtoul ( p , NULL , 10 ) ;
if ( vmax < = 0 | | vmax < = vmin )
return ;
if ( ! ( p = strsep ( & spec , " ; " ) ) | | ! * p )
return ;
hmin = 1000 * simple_strtoul ( p , NULL , 10 ) ;
if ( hmin < = 0 )
return ;
if ( ! ( p = strsep ( & spec , " " ) ) | | ! * p )
return ;
hmax = 1000 * simple_strtoul ( p , NULL , 10 ) ;
if ( hmax < = 0 | | hmax < = hmin )
return ;
fb_info . monspecs . vfmin = vmin ;
fb_info . monspecs . vfmax = vmax ;
fb_info . monspecs . hfmin = hmin ;
fb_info . monspecs . hfmax = hmax ;
}
# endif /* ATAFB_FALCON */
static void __init atafb_setup_user ( char * spec )
{
/* Format of user defined video mode is: <xres>;<yres>;<depth>
*/
char * p ;
int xres , yres , depth , temp ;
2007-05-02 00:32:39 +04:00
p = strsep ( & spec , " ; " ) ;
if ( ! p | | ! * p )
2005-04-17 02:20:36 +04:00
return ;
xres = simple_strtoul ( p , NULL , 10 ) ;
2007-05-02 00:32:39 +04:00
p = strsep ( & spec , " ; " ) ;
if ( ! p | | ! * p )
2005-04-17 02:20:36 +04:00
return ;
yres = simple_strtoul ( p , NULL , 10 ) ;
2007-05-02 00:32:39 +04:00
p = strsep ( & spec , " " ) ;
if ( ! p | | ! * p )
2005-04-17 02:20:36 +04:00
return ;
depth = simple_strtoul ( p , NULL , 10 ) ;
2007-05-02 00:32:39 +04:00
temp = get_video_mode ( " user0 " ) ;
if ( temp ) {
default_par = temp ;
atafb_predefined [ default_par - 1 ] . xres = xres ;
atafb_predefined [ default_par - 1 ] . yres = yres ;
atafb_predefined [ default_par - 1 ] . bits_per_pixel = depth ;
2005-04-17 02:20:36 +04:00
}
}
2007-05-02 00:32:39 +04:00
int __init atafb_setup ( char * options )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
char * this_opt ;
int temp ;
2005-04-17 02:20:36 +04:00
2007-05-02 00:32:39 +04:00
if ( ! options | | ! * options )
2005-04-17 02:20:36 +04:00
return 0 ;
2007-05-02 00:32:39 +04:00
while ( ( this_opt = strsep ( & options , " , " ) ) ! = NULL ) {
if ( ! * this_opt )
continue ;
if ( ( temp = get_video_mode ( this_opt ) ) ) {
default_par = temp ;
mode_option = this_opt ;
} else if ( ! strcmp ( this_opt , " inverse " ) )
inverse = 1 ;
else if ( ! strncmp ( this_opt , " hwscroll_ " , 9 ) ) {
hwscroll = simple_strtoul ( this_opt + 9 , NULL , 10 ) ;
if ( hwscroll < 0 )
hwscroll = 0 ;
if ( hwscroll > 200 )
hwscroll = 200 ;
}
2005-04-17 02:20:36 +04:00
# ifdef ATAFB_EXT
2007-05-02 00:32:39 +04:00
else if ( ! strcmp ( this_opt , " mv300 " ) ) {
external_bitspercol = 8 ;
external_card_type = IS_MV300 ;
} else if ( ! strncmp ( this_opt , " external: " , 9 ) )
atafb_setup_ext ( this_opt + 9 ) ;
# endif
else if ( ! strncmp ( this_opt , " internal: " , 9 ) )
atafb_setup_int ( this_opt + 9 ) ;
# ifdef ATAFB_FALCON
else if ( ! strncmp ( this_opt , " eclock: " , 7 ) ) {
fext . f = simple_strtoul ( this_opt + 7 , NULL , 10 ) ;
/* external pixelclock in kHz --> ps */
fext . t = 1000000000 / fext . f ;
fext . f * = 1000 ;
} else if ( ! strncmp ( this_opt , " monitorcap: " , 11 ) )
atafb_setup_mcap ( this_opt + 11 ) ;
# endif
else if ( ! strcmp ( this_opt , " keep " ) )
DontCalcRes = 1 ;
else if ( ! strncmp ( this_opt , " R " , 1 ) )
atafb_setup_user ( this_opt + 1 ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
return 0 ;
}
int __init atafb_init ( void )
{
2008-12-30 16:10:11 +03:00
int pad , detected_mode , error ;
2007-05-02 00:32:39 +04:00
unsigned int defmode = 0 ;
unsigned long mem_req ;
# ifndef MODULE
char * option = NULL ;
if ( fb_get_options ( " atafb " , & option ) )
return - ENODEV ;
atafb_setup ( option ) ;
# endif
printk ( " atafb_init: start \n " ) ;
if ( ! MACH_IS_ATARI )
2008-07-17 23:16:10 +04:00
return - ENODEV ;
2007-05-02 00:32:39 +04:00
do {
# ifdef ATAFB_EXT
if ( external_addr ) {
printk ( " atafb_init: initializing external hw \n " ) ;
fbhw = & ext_switch ;
atafb_ops . fb_setcolreg = & ext_setcolreg ;
defmode = DEFMODE_EXT ;
break ;
}
# endif
# ifdef ATAFB_TT
if ( ATARIHW_PRESENT ( TT_SHIFTER ) ) {
printk ( " atafb_init: initializing TT hw \n " ) ;
fbhw = & tt_switch ;
atafb_ops . fb_setcolreg = & tt_setcolreg ;
defmode = DEFMODE_TT ;
break ;
}
2005-04-17 02:20:36 +04:00
# endif
# ifdef ATAFB_FALCON
2007-05-02 00:32:39 +04:00
if ( ATARIHW_PRESENT ( VIDEL_SHIFTER ) ) {
printk ( " atafb_init: initializing Falcon hw \n " ) ;
fbhw = & falcon_switch ;
atafb_ops . fb_setcolreg = & falcon_setcolreg ;
2008-12-30 16:10:11 +03:00
error = request_irq ( IRQ_AUTO_4 , falcon_vbl_switcher ,
IRQ_TYPE_PRIO ,
" framebuffer/modeswitch " ,
falcon_vbl_switcher ) ;
if ( error )
return error ;
2007-05-02 00:32:39 +04:00
defmode = DEFMODE_F30 ;
break ;
}
# endif
# ifdef ATAFB_STE
if ( ATARIHW_PRESENT ( STND_SHIFTER ) | |
ATARIHW_PRESENT ( EXTD_SHIFTER ) ) {
printk ( " atafb_init: initializing ST/E hw \n " ) ;
fbhw = & st_switch ;
atafb_ops . fb_setcolreg = & stste_setcolreg ;
defmode = DEFMODE_STE ;
break ;
}
fbhw = & st_switch ;
atafb_ops . fb_setcolreg = & stste_setcolreg ;
printk ( " Cannot determine video hardware; defaulting to ST(e) \n " ) ;
# else /* ATAFB_STE */
/* no default driver included */
/* Nobody will ever see this message :-) */
panic ( " Cannot initialize video hardware " ) ;
# endif
} while ( 0 ) ;
/* Multisync monitor capabilities */
/* Atari-TOS defaults if no boot option present */
if ( fb_info . monspecs . hfmin = = 0 ) {
fb_info . monspecs . hfmin = 31000 ;
fb_info . monspecs . hfmax = 32000 ;
fb_info . monspecs . vfmin = 58 ;
fb_info . monspecs . vfmax = 62 ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
detected_mode = fbhw - > detect ( ) ;
check_default_par ( detected_mode ) ;
# ifdef ATAFB_EXT
if ( ! external_addr ) {
# endif /* ATAFB_EXT */
mem_req = default_mem_req + ovsc_offset + ovsc_addlen ;
mem_req = PAGE_ALIGN ( mem_req ) + PAGE_SIZE ;
screen_base = atari_stram_alloc ( mem_req , " atafb " ) ;
if ( ! screen_base )
panic ( " Cannot allocate screen memory " ) ;
memset ( screen_base , 0 , mem_req ) ;
pad = - ( unsigned long ) screen_base & ( PAGE_SIZE - 1 ) ;
screen_base + = pad ;
real_screen_base = screen_base + ovsc_offset ;
screen_len = ( mem_req - pad - ovsc_offset ) & PAGE_MASK ;
st_ovsc_switch ( ) ;
if ( CPU_IS_040_OR_060 ) {
/* On a '040+, the cache mode of video RAM must be set to
* write - through also for internal video hardware ! */
cache_push ( virt_to_phys ( screen_base ) , screen_len ) ;
kernel_set_cachemode ( screen_base , screen_len ,
IOMAP_WRITETHROUGH ) ;
}
printk ( " atafb: screen_base %p real_screen_base %p screen_len %d \n " ,
screen_base , real_screen_base , screen_len ) ;
# ifdef ATAFB_EXT
} else {
/* Map the video memory (physical address given) to somewhere
* in the kernel address space .
*/
external_addr = ioremap_writethrough ( ( unsigned long ) external_addr ,
external_len ) ;
if ( external_vgaiobase )
external_vgaiobase =
( unsigned long ) ioremap ( external_vgaiobase , 0x10000 ) ;
screen_base =
real_screen_base = external_addr ;
screen_len = external_len & PAGE_MASK ;
memset ( screen_base , 0 , external_len ) ;
}
# endif /* ATAFB_EXT */
// strcpy(fb_info.mode->name, "Atari Builtin ");
fb_info . fbops = & atafb_ops ;
// try to set default (detected; requested) var
do_fb_set_var ( & atafb_predefined [ default_par - 1 ] , 1 ) ;
// reads hw state into current par, which may not be sane yet
ata_get_par ( & current_par ) ;
fb_info . par = & current_par ;
// tries to read from HW which may not be initialized yet
// so set sane var first, then call atafb_set_par
atafb_get_var ( & fb_info . var , & fb_info ) ;
2008-11-18 23:13:01 +03:00
# ifdef ATAFB_FALCON
fb_info . pseudo_palette = current_par . hw . falcon . pseudo_palette ;
# endif
2007-05-02 00:32:39 +04:00
fb_info . flags = FBINFO_FLAG_DEFAULT ;
if ( ! fb_find_mode ( & fb_info . var , & fb_info , mode_option , atafb_modedb ,
NUM_TOTAL_MODES , & atafb_modedb [ defmode ] ,
fb_info . var . bits_per_pixel ) ) {
return - EINVAL ;
}
2008-07-17 23:16:19 +04:00
fb_videomode_to_modelist ( atafb_modedb , NUM_TOTAL_MODES ,
& fb_info . modelist ) ;
2007-05-02 00:32:39 +04:00
atafb_set_disp ( & fb_info ) ;
fb_alloc_cmap ( & ( fb_info . cmap ) , 1 < < fb_info . var . bits_per_pixel , 0 ) ;
printk ( " Determined %dx%d, depth %d \n " ,
fb_info . var . xres , fb_info . var . yres , fb_info . var . bits_per_pixel ) ;
if ( ( fb_info . var . xres ! = fb_info . var . xres_virtual ) | |
( fb_info . var . yres ! = fb_info . var . yres_virtual ) )
printk ( " virtual %dx%d \n " , fb_info . var . xres_virtual ,
fb_info . var . yres_virtual ) ;
if ( register_framebuffer ( & fb_info ) < 0 ) {
# ifdef ATAFB_EXT
if ( external_addr ) {
iounmap ( external_addr ) ;
external_addr = NULL ;
}
if ( external_vgaiobase ) {
iounmap ( ( void * ) external_vgaiobase ) ;
external_vgaiobase = 0 ;
}
2005-04-17 02:20:36 +04:00
# endif
2007-05-02 00:32:39 +04:00
return - EINVAL ;
}
// FIXME: mode needs setting!
//printk("fb%d: %s frame buffer device, using %dK of video memory\n",
// fb_info.node, fb_info.mode->name, screen_len>>10);
printk ( " fb%d: frame buffer device, using %dK of video memory \n " ,
fb_info . node , screen_len > > 10 ) ;
/* TODO: This driver cannot be unloaded yet */
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-05-02 00:32:39 +04:00
module_init ( atafb_init ) ;
2005-04-17 02:20:36 +04:00
# ifdef MODULE
MODULE_LICENSE ( " GPL " ) ;
2007-05-02 00:32:39 +04:00
int cleanup_module ( void )
2005-04-17 02:20:36 +04:00
{
2007-05-02 00:32:39 +04:00
unregister_framebuffer ( & fb_info ) ;
return atafb_deinit ( ) ;
2005-04-17 02:20:36 +04:00
}
# endif /* MODULE */