2007-07-11 23:18:52 +04:00
/* -*- linux-c -*- ------------------------------------------------------- *
*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
* Copyright 2007 rPath , Inc . - All Rights Reserved
2009-04-02 05:20:11 +04:00
* Copyright 2009 Intel Corporation ; author H . Peter Anvin
2007-07-11 23:18:52 +04:00
*
* This file is part of the Linux kernel , and is made available under
* the terms of the GNU General Public License version 2.
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* VESA text modes
*/
# include "boot.h"
# include "video.h"
# include "vesa.h"
/* VESA information */
static struct vesa_general_info vginfo ;
static struct vesa_mode_info vminfo ;
2008-10-22 03:49:09 +04:00
static __videocard video_vesa ;
2007-07-11 23:18:52 +04:00
2008-04-11 01:28:10 +04:00
# ifndef _WAKEUP
2007-07-11 23:18:52 +04:00
static void vesa_store_mode_params_graphics ( void ) ;
2008-04-11 01:28:10 +04:00
# else /* _WAKEUP */
static inline void vesa_store_mode_params_graphics ( void ) { }
# endif /* _WAKEUP */
2007-07-11 23:18:52 +04:00
static int vesa_probe ( void )
{
2009-04-02 05:20:11 +04:00
struct biosregs ireg , oreg ;
2007-07-11 23:18:52 +04:00
u16 mode ;
addr_t mode_ptr ;
struct mode_info * mi ;
int nmodes = 0 ;
video_vesa . modes = GET_HEAP ( struct mode_info , 0 ) ;
2009-04-02 05:20:11 +04:00
initregs ( & ireg ) ;
ireg . ax = 0x4f00 ;
ireg . di = ( size_t ) & vginfo ;
intcall ( 0x10 , & ireg , & oreg ) ;
2007-07-11 23:18:52 +04:00
2009-07-01 06:13:07 +04:00
if ( oreg . ax ! = 0x004f | |
2007-07-11 23:18:52 +04:00
vginfo . signature ! = VESA_MAGIC | |
vginfo . version < 0x0102 )
return 0 ; /* Not present */
2009-06-26 21:53:57 +04:00
2007-07-11 23:18:52 +04:00
set_fs ( vginfo . video_mode_ptr . seg ) ;
mode_ptr = vginfo . video_mode_ptr . off ;
while ( ( mode = rdfs16 ( mode_ptr ) ) ! = 0xffff ) {
mode_ptr + = 2 ;
2007-10-26 03:09:38 +04:00
if ( ! heap_free ( sizeof ( struct mode_info ) ) )
2007-07-11 23:18:52 +04:00
break ; /* Heap full, can't save mode info */
if ( mode & ~ 0x1ff )
continue ;
memset ( & vminfo , 0 , sizeof vminfo ) ; /* Just in case... */
2009-04-02 05:20:11 +04:00
ireg . ax = 0x4f01 ;
ireg . cx = mode ;
ireg . di = ( size_t ) & vminfo ;
intcall ( 0x10 , & ireg , & oreg ) ;
2007-07-11 23:18:52 +04:00
2009-07-01 06:13:07 +04:00
if ( oreg . ax ! = 0x004f )
2007-07-11 23:18:52 +04:00
continue ;
if ( ( vminfo . mode_attr & 0x15 ) = = 0x05 ) {
/* Text Mode, TTY BIOS supported,
supported by hardware */
mi = GET_HEAP ( struct mode_info , 1 ) ;
2008-01-30 15:33:02 +03:00
mi - > mode = mode + VIDEO_FIRST_VESA ;
mi - > depth = 0 ; /* text */
mi - > x = vminfo . h_res ;
mi - > y = vminfo . v_res ;
2007-07-11 23:18:52 +04:00
nmodes + + ;
2008-01-30 15:33:02 +03:00
} else if ( ( vminfo . mode_attr & 0x99 ) = = 0x99 & &
( vminfo . memory_layout = = 4 | |
vminfo . memory_layout = = 6 ) & &
vminfo . memory_planes = = 1 ) {
2008-10-16 09:03:51 +04:00
# ifdef CONFIG_FB_BOOT_VESA_SUPPORT
2007-07-11 23:18:52 +04:00
/* Graphics mode, color, linear frame buffer
2008-01-30 15:33:02 +03:00
supported . Only register the mode if
if framebuffer is configured , however ,
2008-10-16 09:03:51 +04:00
otherwise the user will be left without a screen . */
2007-07-11 23:18:52 +04:00
mi = GET_HEAP ( struct mode_info , 1 ) ;
mi - > mode = mode + VIDEO_FIRST_VESA ;
2008-01-30 15:33:02 +03:00
mi - > depth = vminfo . bpp ;
mi - > x = vminfo . h_res ;
mi - > y = vminfo . v_res ;
2007-07-11 23:18:52 +04:00
nmodes + + ;
# endif
}
}
return nmodes ;
}
static int vesa_set_mode ( struct mode_info * mode )
{
2009-04-02 05:20:11 +04:00
struct biosregs ireg , oreg ;
2007-07-11 23:18:52 +04:00
int is_graphic ;
u16 vesa_mode = mode - > mode - VIDEO_FIRST_VESA ;
memset ( & vminfo , 0 , sizeof vminfo ) ; /* Just in case... */
2009-04-02 05:20:11 +04:00
initregs ( & ireg ) ;
ireg . ax = 0x4f01 ;
ireg . cx = vesa_mode ;
ireg . di = ( size_t ) & vminfo ;
intcall ( 0x10 , & ireg , & oreg ) ;
2007-07-11 23:18:52 +04:00
2009-04-02 05:20:11 +04:00
if ( oreg . ax ! = 0x004f )
2007-07-11 23:18:52 +04:00
return - 1 ;
if ( ( vminfo . mode_attr & 0x15 ) = = 0x05 ) {
/* It's a supported text mode */
is_graphic = 0 ;
2008-10-16 09:03:51 +04:00
# ifdef CONFIG_FB_BOOT_VESA_SUPPORT
2007-07-11 23:18:52 +04:00
} else if ( ( vminfo . mode_attr & 0x99 ) = = 0x99 ) {
/* It's a graphics mode with linear frame buffer */
is_graphic = 1 ;
vesa_mode | = 0x4000 ; /* Request linear frame buffer */
2008-10-16 09:03:51 +04:00
# endif
2007-07-11 23:18:52 +04:00
} else {
return - 1 ; /* Invalid mode */
}
2009-04-02 05:20:11 +04:00
initregs ( & ireg ) ;
ireg . ax = 0x4f02 ;
ireg . bx = vesa_mode ;
intcall ( 0x10 , & ireg , & oreg ) ;
2007-07-11 23:18:52 +04:00
2009-04-02 05:20:11 +04:00
if ( oreg . ax ! = 0x004f )
2007-07-11 23:18:52 +04:00
return - 1 ;
graphic_mode = is_graphic ;
if ( ! is_graphic ) {
/* Text mode */
force_x = mode - > x ;
force_y = mode - > y ;
do_restore = 1 ;
} else {
/* Graphics mode */
vesa_store_mode_params_graphics ( ) ;
}
return 0 ;
}
2008-04-11 01:28:10 +04:00
# ifndef _WAKEUP
2007-07-11 23:18:52 +04:00
/* Switch DAC to 8-bit mode */
static void vesa_dac_set_8bits ( void )
{
2009-04-02 05:20:11 +04:00
struct biosregs ireg , oreg ;
2007-07-11 23:18:52 +04:00
u8 dac_size = 6 ;
/* If possible, switch the DAC to 8-bit mode */
if ( vginfo . capabilities & 1 ) {
2009-04-02 05:20:11 +04:00
initregs ( & ireg ) ;
ireg . ax = 0x4f08 ;
ireg . bh = 0x08 ;
intcall ( 0x10 , & ireg , & oreg ) ;
if ( oreg . ax = = 0x004f )
dac_size = oreg . bh ;
2007-07-11 23:18:52 +04:00
}
/* Set the color sizes to the DAC size, and offsets to 0 */
2009-04-02 05:20:11 +04:00
boot_params . screen_info . red_size = dac_size ;
2007-07-11 23:18:52 +04:00
boot_params . screen_info . green_size = dac_size ;
2009-04-02 05:20:11 +04:00
boot_params . screen_info . blue_size = dac_size ;
boot_params . screen_info . rsvd_size = dac_size ;
2007-07-11 23:18:52 +04:00
2009-04-02 05:20:11 +04:00
boot_params . screen_info . red_pos = 0 ;
boot_params . screen_info . green_pos = 0 ;
boot_params . screen_info . blue_pos = 0 ;
boot_params . screen_info . rsvd_pos = 0 ;
2007-07-11 23:18:52 +04:00
}
/* Save the VESA protected mode info */
static void vesa_store_pm_info ( void )
{
2009-04-02 05:20:11 +04:00
struct biosregs ireg , oreg ;
2007-07-11 23:18:52 +04:00
2009-04-02 05:20:11 +04:00
initregs ( & ireg ) ;
ireg . ax = 0x4f0a ;
intcall ( 0x10 , & ireg , & oreg ) ;
2007-07-11 23:18:52 +04:00
2009-04-02 05:20:11 +04:00
if ( oreg . ax ! = 0x004f )
2007-07-11 23:18:52 +04:00
return ;
2009-04-02 05:20:11 +04:00
boot_params . screen_info . vesapm_seg = oreg . es ;
boot_params . screen_info . vesapm_off = oreg . di ;
2007-07-11 23:18:52 +04:00
}
/*
* Save video mode parameters for graphics mode
*/
static void vesa_store_mode_params_graphics ( void )
{
/* Tell the kernel we're in VESA graphics mode */
2008-10-05 14:16:04 +04:00
boot_params . screen_info . orig_video_isVGA = VIDEO_TYPE_VLFB ;
2007-07-11 23:18:52 +04:00
/* Mode parameters */
boot_params . screen_info . vesa_attributes = vminfo . mode_attr ;
boot_params . screen_info . lfb_linelength = vminfo . logical_scan ;
boot_params . screen_info . lfb_width = vminfo . h_res ;
boot_params . screen_info . lfb_height = vminfo . v_res ;
boot_params . screen_info . lfb_depth = vminfo . bpp ;
boot_params . screen_info . pages = vminfo . image_planes ;
boot_params . screen_info . lfb_base = vminfo . lfb_ptr ;
memcpy ( & boot_params . screen_info . red_size ,
& vminfo . rmask , 8 ) ;
/* General parameters */
boot_params . screen_info . lfb_size = vginfo . total_memory ;
if ( vminfo . bpp < = 8 )
vesa_dac_set_8bits ( ) ;
vesa_store_pm_info ( ) ;
}
/*
* Save EDID information for the kernel ; this is invoked , separately ,
* after mode - setting .
*/
void vesa_store_edid ( void )
{
# ifdef CONFIG_FIRMWARE_EDID
2009-04-02 05:20:11 +04:00
struct biosregs ireg , oreg ;
2007-07-11 23:18:52 +04:00
/* Apparently used as a nonsense token... */
memset ( & boot_params . edid_info , 0x13 , sizeof boot_params . edid_info ) ;
if ( vginfo . version < 0x0200 )
return ; /* EDID requires VBE 2.0+ */
2009-04-02 05:20:11 +04:00
initregs ( & ireg ) ;
ireg . ax = 0x4f15 ; /* VBE DDC */
/* ireg.bx = 0x0000; */ /* Report DDC capabilities */
/* ireg.cx = 0; */ /* Controller 0 */
ireg . es = 0 ; /* ES:DI must be 0 by spec */
intcall ( 0x10 , & ireg , & oreg ) ;
2007-07-11 23:18:52 +04:00
2009-04-02 05:20:11 +04:00
if ( oreg . ax ! = 0x004f )
2007-07-11 23:18:52 +04:00
return ; /* No EDID */
/* BH = time in seconds to transfer EDD information */
/* BL = DDC level supported */
2009-04-02 05:20:11 +04:00
ireg . ax = 0x4f15 ; /* VBE DDC */
ireg . bx = 0x0001 ; /* Read EDID */
/* ireg.cx = 0; */ /* Controller 0 */
/* ireg.dx = 0; */ /* EDID block number */
ireg . es = ds ( ) ;
ireg . di = ( size_t ) & boot_params . edid_info ; /* (ES:)Pointer to block */
intcall ( 0x10 , & ireg , & oreg ) ;
2007-07-11 23:18:52 +04:00
# endif /* CONFIG_FIRMWARE_EDID */
}
2008-04-11 01:28:10 +04:00
# endif /* not _WAKEUP */
2008-10-22 03:49:09 +04:00
static __videocard video_vesa =
2007-07-11 23:18:52 +04:00
{
. card_name = " VESA " ,
. probe = vesa_probe ,
. set_mode = vesa_set_mode ,
. xmode_first = VIDEO_FIRST_VESA ,
. xmode_n = 0x200 ,
} ;