2007-07-17 04:06:01 -07:00
/*
* Epson Blizzard LCD controller driver
*
* Copyright ( C ) 2004 - 2005 Nokia Corporation
* Authors : Juha Yrjola < juha . yrjola @ nokia . com >
* Imre Deak < imre . deak @ nokia . com >
* YUV support : Jussi Laako < jussi . laako @ nokia . com >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
# include <linux/module.h>
# include <linux/mm.h>
# include <linux/fb.h>
# include <linux/delay.h>
# include <linux/clk.h>
2008-08-05 16:14:15 +01:00
# include <mach/dma.h>
# include <mach/omapfb.h>
# include <mach/blizzard.h>
2007-07-17 04:06:01 -07:00
# include "dispc.h"
# define MODULE_NAME "blizzard"
# define BLIZZARD_REV_CODE 0x00
# define BLIZZARD_CONFIG 0x02
# define BLIZZARD_PLL_DIV 0x04
# define BLIZZARD_PLL_LOCK_RANGE 0x06
# define BLIZZARD_PLL_CLOCK_SYNTH_0 0x08
# define BLIZZARD_PLL_CLOCK_SYNTH_1 0x0a
# define BLIZZARD_PLL_MODE 0x0c
# define BLIZZARD_CLK_SRC 0x0e
# define BLIZZARD_MEM_BANK0_ACTIVATE 0x10
# define BLIZZARD_MEM_BANK0_STATUS 0x14
2009-09-22 16:46:53 -07:00
# define BLIZZARD_PANEL_CONFIGURATION 0x28
2007-07-17 04:06:01 -07:00
# define BLIZZARD_HDISP 0x2a
# define BLIZZARD_HNDP 0x2c
# define BLIZZARD_VDISP0 0x2e
# define BLIZZARD_VDISP1 0x30
# define BLIZZARD_VNDP 0x32
# define BLIZZARD_HSW 0x34
# define BLIZZARD_VSW 0x38
# define BLIZZARD_DISPLAY_MODE 0x68
# define BLIZZARD_INPUT_WIN_X_START_0 0x6c
# define BLIZZARD_DATA_SOURCE_SELECT 0x8e
# define BLIZZARD_DISP_MEM_DATA_PORT 0x90
# define BLIZZARD_DISP_MEM_READ_ADDR0 0x92
# define BLIZZARD_POWER_SAVE 0xE6
# define BLIZZARD_NDISP_CTRL_STATUS 0xE8
/* Data source select */
/* For S1D13745 */
# define BLIZZARD_SRC_WRITE_LCD_BACKGROUND 0x00
# define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE 0x01
# define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE 0x04
# define BLIZZARD_SRC_DISABLE_OVERLAY 0x05
/* For S1D13744 */
# define BLIZZARD_SRC_WRITE_LCD 0x00
# define BLIZZARD_SRC_BLT_LCD 0x06
# define BLIZZARD_COLOR_RGB565 0x01
# define BLIZZARD_COLOR_YUV420 0x09
# define BLIZZARD_VERSION_S1D13745 0x01 /* Hailstorm */
# define BLIZZARD_VERSION_S1D13744 0x02 /* Blizzard */
# define BLIZZARD_AUTO_UPDATE_TIME (HZ / 20)
/* Reserve 4 request slots for requests in irq context */
# define REQ_POOL_SIZE 24
# define IRQ_REQ_POOL_SIZE 4
# define REQ_FROM_IRQ_POOL 0x01
# define REQ_COMPLETE 0
# define REQ_PENDING 1
struct blizzard_reg_list {
int start ;
int end ;
} ;
/* These need to be saved / restored separately from the rest. */
2009-10-05 13:31:47 -07:00
static const struct blizzard_reg_list blizzard_pll_regs [ ] = {
2007-07-17 04:06:01 -07:00
{
. start = 0x04 , /* Don't save PLL ctrl (0x0C) */
. end = 0x0a ,
} ,
{
. start = 0x0e , /* Clock configuration */
. end = 0x0e ,
} ,
} ;
2009-10-05 13:31:47 -07:00
static const struct blizzard_reg_list blizzard_gen_regs [ ] = {
2007-07-17 04:06:01 -07:00
{
. start = 0x18 , /* SDRAM control */
. end = 0x20 ,
} ,
{
. start = 0x28 , /* LCD Panel configuration */
. end = 0x5a , /* HSSI interface, TV configuration */
} ,
} ;
static u8 blizzard_reg_cache [ 0x5a / 2 ] ;
struct update_param {
int plane ;
int x , y , width , height ;
int out_x , out_y ;
int out_width , out_height ;
int color_mode ;
int bpp ;
int flags ;
} ;
struct blizzard_request {
struct list_head entry ;
unsigned int flags ;
int ( * handler ) ( struct blizzard_request * req ) ;
void ( * complete ) ( void * data ) ;
void * complete_data ;
union {
struct update_param update ;
struct completion * sync ;
} par ;
} ;
struct plane_info {
unsigned long offset ;
int pos_x , pos_y ;
int width , height ;
int out_width , out_height ;
int scr_width ;
int color_mode ;
int bpp ;
} ;
struct blizzard_struct {
enum omapfb_update_mode update_mode ;
enum omapfb_update_mode update_mode_before_suspend ;
struct timer_list auto_update_timer ;
int stop_auto_update ;
struct omapfb_update_window auto_update_window ;
int enabled_planes ;
int vid_nonstd_color ;
int vid_scaled ;
int last_color_mode ;
int zoom_on ;
2009-09-22 16:46:53 -07:00
int zoom_area_gx1 ;
int zoom_area_gx2 ;
int zoom_area_gy1 ;
int zoom_area_gy2 ;
2007-07-17 04:06:01 -07:00
int screen_width ;
int screen_height ;
unsigned te_connected : 1 ;
unsigned vsync_only : 1 ;
struct plane_info plane [ OMAPFB_PLANE_NUM ] ;
struct blizzard_request req_pool [ REQ_POOL_SIZE ] ;
struct list_head pending_req_list ;
struct list_head free_req_list ;
struct semaphore req_sema ;
spinlock_t req_lock ;
unsigned long sys_ck_rate ;
struct extif_timings reg_timings , lut_timings ;
u32 max_transmit_size ;
u32 extif_clk_period ;
int extif_clk_div ;
unsigned long pix_tx_time ;
unsigned long line_upd_time ;
struct omapfb_device * fbdev ;
struct lcd_ctrl_extif * extif ;
2009-10-05 13:31:46 -07:00
const struct lcd_ctrl * int_ctrl ;
2007-07-17 04:06:01 -07:00
void ( * power_up ) ( struct device * dev ) ;
void ( * power_down ) ( struct device * dev ) ;
int version ;
} blizzard ;
struct lcd_ctrl blizzard_ctrl ;
static u8 blizzard_read_reg ( u8 reg )
{
u8 data ;
blizzard . extif - > set_bits_per_cycle ( 8 ) ;
blizzard . extif - > write_command ( & reg , 1 ) ;
blizzard . extif - > read_data ( & data , 1 ) ;
return data ;
}
static void blizzard_write_reg ( u8 reg , u8 val )
{
blizzard . extif - > set_bits_per_cycle ( 8 ) ;
blizzard . extif - > write_command ( & reg , 1 ) ;
blizzard . extif - > write_data ( & val , 1 ) ;
}
static void blizzard_restart_sdram ( void )
{
unsigned long tmo ;
blizzard_write_reg ( BLIZZARD_MEM_BANK0_ACTIVATE , 0 ) ;
udelay ( 50 ) ;
blizzard_write_reg ( BLIZZARD_MEM_BANK0_ACTIVATE , 1 ) ;
tmo = jiffies + msecs_to_jiffies ( 200 ) ;
while ( ! ( blizzard_read_reg ( BLIZZARD_MEM_BANK0_STATUS ) & 0x01 ) ) {
if ( time_after ( jiffies , tmo ) ) {
dev_err ( blizzard . fbdev - > dev ,
2007-10-18 03:06:30 -07:00
" s1d1374x: SDRAM not ready \n " ) ;
2007-07-17 04:06:01 -07:00
break ;
}
msleep ( 1 ) ;
}
}
static void blizzard_stop_sdram ( void )
{
blizzard_write_reg ( BLIZZARD_MEM_BANK0_ACTIVATE , 0 ) ;
}
/* Wait until the last window was completely written into the controllers
* SDRAM and we can start transferring the next window .
*/
static void blizzard_wait_line_buffer ( void )
{
unsigned long tmo = jiffies + msecs_to_jiffies ( 30 ) ;
while ( blizzard_read_reg ( BLIZZARD_NDISP_CTRL_STATUS ) & ( 1 < < 7 ) ) {
if ( time_after ( jiffies , tmo ) ) {
if ( printk_ratelimit ( ) )
dev_err ( blizzard . fbdev - > dev ,
" s1d1374x: line buffer not ready \n " ) ;
break ;
}
}
}
/* Wait until the YYC color space converter is idle. */
static void blizzard_wait_yyc ( void )
{
unsigned long tmo = jiffies + msecs_to_jiffies ( 30 ) ;
while ( blizzard_read_reg ( BLIZZARD_NDISP_CTRL_STATUS ) & ( 1 < < 4 ) ) {
if ( time_after ( jiffies , tmo ) ) {
if ( printk_ratelimit ( ) )
dev_err ( blizzard . fbdev - > dev ,
" s1d1374x: YYC not ready \n " ) ;
break ;
}
}
}
static void disable_overlay ( void )
{
blizzard_write_reg ( BLIZZARD_DATA_SOURCE_SELECT ,
BLIZZARD_SRC_DISABLE_OVERLAY ) ;
}
static void set_window_regs ( int x_start , int y_start , int x_end , int y_end ,
int x_out_start , int y_out_start ,
int x_out_end , int y_out_end , int color_mode ,
int zoom_off , int flags )
{
u8 tmp [ 18 ] ;
u8 cmd ;
x_end - - ;
y_end - - ;
tmp [ 0 ] = x_start ;
tmp [ 1 ] = x_start > > 8 ;
tmp [ 2 ] = y_start ;
tmp [ 3 ] = y_start > > 8 ;
tmp [ 4 ] = x_end ;
tmp [ 5 ] = x_end > > 8 ;
tmp [ 6 ] = y_end ;
tmp [ 7 ] = y_end > > 8 ;
x_out_end - - ;
y_out_end - - ;
tmp [ 8 ] = x_out_start ;
tmp [ 9 ] = x_out_start > > 8 ;
tmp [ 10 ] = y_out_start ;
tmp [ 11 ] = y_out_start > > 8 ;
tmp [ 12 ] = x_out_end ;
tmp [ 13 ] = x_out_end > > 8 ;
tmp [ 14 ] = y_out_end ;
tmp [ 15 ] = y_out_end > > 8 ;
tmp [ 16 ] = color_mode ;
if ( zoom_off & & blizzard . version = = BLIZZARD_VERSION_S1D13745 )
tmp [ 17 ] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND ;
else if ( flags & OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY )
tmp [ 17 ] = BLIZZARD_SRC_WRITE_OVERLAY_ENABLE ;
else
tmp [ 17 ] = blizzard . version = = BLIZZARD_VERSION_S1D13744 ?
BLIZZARD_SRC_WRITE_LCD :
BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE ;
blizzard . extif - > set_bits_per_cycle ( 8 ) ;
cmd = BLIZZARD_INPUT_WIN_X_START_0 ;
blizzard . extif - > write_command ( & cmd , 1 ) ;
blizzard . extif - > write_data ( tmp , 18 ) ;
}
static void enable_tearsync ( int y , int width , int height , int screen_height ,
int out_height , int force_vsync )
{
u8 b ;
b = blizzard_read_reg ( BLIZZARD_NDISP_CTRL_STATUS ) ;
b | = 1 < < 3 ;
blizzard_write_reg ( BLIZZARD_NDISP_CTRL_STATUS , b ) ;
if ( likely ( blizzard . vsync_only | | force_vsync ) ) {
blizzard . extif - > enable_tearsync ( 1 , 0 ) ;
return ;
}
if ( width * blizzard . pix_tx_time < blizzard . line_upd_time ) {
blizzard . extif - > enable_tearsync ( 1 , 0 ) ;
return ;
}
if ( ( width * blizzard . pix_tx_time / 1000 ) * height <
( y + out_height ) * ( blizzard . line_upd_time / 1000 ) ) {
blizzard . extif - > enable_tearsync ( 1 , 0 ) ;
return ;
}
blizzard . extif - > enable_tearsync ( 1 , y + 1 ) ;
}
static void disable_tearsync ( void )
{
u8 b ;
blizzard . extif - > enable_tearsync ( 0 , 0 ) ;
b = blizzard_read_reg ( BLIZZARD_NDISP_CTRL_STATUS ) ;
b & = ~ ( 1 < < 3 ) ;
blizzard_write_reg ( BLIZZARD_NDISP_CTRL_STATUS , b ) ;
b = blizzard_read_reg ( BLIZZARD_NDISP_CTRL_STATUS ) ;
}
static inline void set_extif_timings ( const struct extif_timings * t ) ;
static inline struct blizzard_request * alloc_req ( void )
{
unsigned long flags ;
struct blizzard_request * req ;
int req_flags = 0 ;
if ( ! in_interrupt ( ) )
down ( & blizzard . req_sema ) ;
else
req_flags = REQ_FROM_IRQ_POOL ;
spin_lock_irqsave ( & blizzard . req_lock , flags ) ;
BUG_ON ( list_empty ( & blizzard . free_req_list ) ) ;
req = list_entry ( blizzard . free_req_list . next ,
struct blizzard_request , entry ) ;
list_del ( & req - > entry ) ;
spin_unlock_irqrestore ( & blizzard . req_lock , flags ) ;
INIT_LIST_HEAD ( & req - > entry ) ;
req - > flags = req_flags ;
return req ;
}
static inline void free_req ( struct blizzard_request * req )
{
unsigned long flags ;
spin_lock_irqsave ( & blizzard . req_lock , flags ) ;
list_del ( & req - > entry ) ;
list_add ( & req - > entry , & blizzard . free_req_list ) ;
if ( ! ( req - > flags & REQ_FROM_IRQ_POOL ) )
up ( & blizzard . req_sema ) ;
spin_unlock_irqrestore ( & blizzard . req_lock , flags ) ;
}
static void process_pending_requests ( void )
{
unsigned long flags ;
spin_lock_irqsave ( & blizzard . req_lock , flags ) ;
while ( ! list_empty ( & blizzard . pending_req_list ) ) {
struct blizzard_request * req ;
void ( * complete ) ( void * ) ;
void * complete_data ;
req = list_entry ( blizzard . pending_req_list . next ,
struct blizzard_request , entry ) ;
spin_unlock_irqrestore ( & blizzard . req_lock , flags ) ;
if ( req - > handler ( req ) = = REQ_PENDING )
return ;
complete = req - > complete ;
complete_data = req - > complete_data ;
free_req ( req ) ;
if ( complete )
complete ( complete_data ) ;
spin_lock_irqsave ( & blizzard . req_lock , flags ) ;
}
spin_unlock_irqrestore ( & blizzard . req_lock , flags ) ;
}
static void submit_req_list ( struct list_head * head )
{
unsigned long flags ;
int process = 1 ;
spin_lock_irqsave ( & blizzard . req_lock , flags ) ;
if ( likely ( ! list_empty ( & blizzard . pending_req_list ) ) )
process = 0 ;
list_splice_init ( head , blizzard . pending_req_list . prev ) ;
spin_unlock_irqrestore ( & blizzard . req_lock , flags ) ;
if ( process )
process_pending_requests ( ) ;
}
static void request_complete ( void * data )
{
struct blizzard_request * req = ( struct blizzard_request * ) data ;
void ( * complete ) ( void * ) ;
void * complete_data ;
complete = req - > complete ;
complete_data = req - > complete_data ;
free_req ( req ) ;
if ( complete )
complete ( complete_data ) ;
process_pending_requests ( ) ;
}
static int do_full_screen_update ( struct blizzard_request * req )
{
int i ;
int flags ;
for ( i = 0 ; i < 3 ; i + + ) {
struct plane_info * p = & blizzard . plane [ i ] ;
if ( ! ( blizzard . enabled_planes & ( 1 < < i ) ) ) {
blizzard . int_ctrl - > enable_plane ( i , 0 ) ;
continue ;
}
dev_dbg ( blizzard . fbdev - > dev , " pw %d ph %d \n " ,
p - > width , p - > height ) ;
blizzard . int_ctrl - > setup_plane ( i ,
OMAPFB_CHANNEL_OUT_LCD , p - > offset ,
p - > scr_width , p - > pos_x , p - > pos_y ,
p - > width , p - > height ,
p - > color_mode ) ;
blizzard . int_ctrl - > enable_plane ( i , 1 ) ;
}
dev_dbg ( blizzard . fbdev - > dev , " sw %d sh %d \n " ,
blizzard . screen_width , blizzard . screen_height ) ;
blizzard_wait_line_buffer ( ) ;
flags = req - > par . update . flags ;
if ( flags & OMAPFB_FORMAT_FLAG_TEARSYNC )
enable_tearsync ( 0 , blizzard . screen_width ,
blizzard . screen_height ,
blizzard . screen_height ,
blizzard . screen_height ,
flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC ) ;
else
disable_tearsync ( ) ;
set_window_regs ( 0 , 0 , blizzard . screen_width , blizzard . screen_height ,
0 , 0 , blizzard . screen_width , blizzard . screen_height ,
BLIZZARD_COLOR_RGB565 , blizzard . zoom_on , flags ) ;
blizzard . zoom_on = 0 ;
blizzard . extif - > set_bits_per_cycle ( 16 ) ;
/* set_window_regs has left the register index at the right
* place , so no need to set it here .
*/
blizzard . extif - > transfer_area ( blizzard . screen_width ,
blizzard . screen_height ,
request_complete , req ) ;
return REQ_PENDING ;
}
2009-09-22 16:46:53 -07:00
static int check_1d_intersect ( int a1 , int a2 , int b1 , int b2 )
{
if ( a2 < = b1 | | b2 < = a1 )
return 0 ;
return 1 ;
}
2007-07-17 04:06:01 -07:00
/* Setup all planes with an overlapping area with the update window. */
static int do_partial_update ( struct blizzard_request * req , int plane ,
int x , int y , int w , int h ,
int x_out , int y_out , int w_out , int h_out ,
int wnd_color_mode , int bpp )
{
int i ;
int gx1 , gy1 , gx2 , gy2 ;
int gx1_out , gy1_out , gx2_out , gy2_out ;
int color_mode ;
int flags ;
int zoom_off ;
2009-09-22 16:46:53 -07:00
int have_zoom_for_this_update = 0 ;
2007-07-17 04:06:01 -07:00
/* Global coordinates, relative to pixel 0,0 of the LCD */
gx1 = x + blizzard . plane [ plane ] . pos_x ;
gy1 = y + blizzard . plane [ plane ] . pos_y ;
gx2 = gx1 + w ;
gy2 = gy1 + h ;
flags = req - > par . update . flags ;
if ( flags & OMAPFB_FORMAT_FLAG_DOUBLE ) {
gx1_out = gx1 ;
gy1_out = gy1 ;
gx2_out = gx1 + w * 2 ;
gy2_out = gy1 + h * 2 ;
} else {
gx1_out = x_out + blizzard . plane [ plane ] . pos_x ;
gy1_out = y_out + blizzard . plane [ plane ] . pos_y ;
gx2_out = gx1_out + w_out ;
gy2_out = gy1_out + h_out ;
}
for ( i = 0 ; i < OMAPFB_PLANE_NUM ; i + + ) {
struct plane_info * p = & blizzard . plane [ i ] ;
int px1 , py1 ;
int px2 , py2 ;
int pw , ph ;
int pposx , pposy ;
unsigned long offset ;
if ( ! ( blizzard . enabled_planes & ( 1 < < i ) ) | |
( wnd_color_mode & & i ! = plane ) ) {
blizzard . int_ctrl - > enable_plane ( i , 0 ) ;
continue ;
}
/* Plane coordinates */
if ( i = = plane ) {
/* Plane in which we are doing the update.
* Local coordinates are the one in the update
* request .
*/
px1 = x ;
py1 = y ;
px2 = x + w ;
py2 = y + h ;
pposx = 0 ;
pposy = 0 ;
} else {
/* Check if this plane has an overlapping part */
px1 = gx1 - p - > pos_x ;
py1 = gy1 - p - > pos_y ;
px2 = gx2 - p - > pos_x ;
py2 = gy2 - p - > pos_y ;
if ( px1 > = p - > width | | py1 > = p - > height | |
px2 < = 0 | | py2 < = 0 ) {
blizzard . int_ctrl - > enable_plane ( i , 0 ) ;
continue ;
}
/* Calculate the coordinates for the overlapping
* part in the plane ' s local coordinates .
*/
pposx = - px1 ;
pposy = - py1 ;
if ( px1 < 0 )
px1 = 0 ;
if ( py1 < 0 )
py1 = 0 ;
if ( px2 > p - > width )
px2 = p - > width ;
if ( py2 > p - > height )
py2 = p - > height ;
if ( pposx < 0 )
pposx = 0 ;
if ( pposy < 0 )
pposy = 0 ;
}
pw = px2 - px1 ;
ph = py2 - py1 ;
offset = p - > offset + ( p - > scr_width * py1 + px1 ) * p - > bpp / 8 ;
if ( wnd_color_mode )
/* Window embedded in the plane with a differing
* color mode / bpp . Calculate the number of DMA
* transfer elements in terms of the plane ' s bpp .
*/
pw = ( pw + 1 ) * bpp / p - > bpp ;
# ifdef VERBOSE
dev_dbg ( blizzard . fbdev - > dev ,
" plane %d offset %#08lx pposx %d pposy %d "
" px1 %d py1 %d pw %d ph %d \n " ,
i , offset , pposx , pposy , px1 , py1 , pw , ph ) ;
# endif
blizzard . int_ctrl - > setup_plane ( i ,
OMAPFB_CHANNEL_OUT_LCD , offset ,
p - > scr_width ,
pposx , pposy , pw , ph ,
p - > color_mode ) ;
blizzard . int_ctrl - > enable_plane ( i , 1 ) ;
}
switch ( wnd_color_mode ) {
case OMAPFB_COLOR_YUV420 :
color_mode = BLIZZARD_COLOR_YUV420 ;
/* Currently only the 16 bits/pixel cycle format is
* supported on the external interface . Adjust the number
* of transfer elements per line for 12 bpp format .
*/
w = ( w + 1 ) * 3 / 4 ;
break ;
default :
color_mode = BLIZZARD_COLOR_RGB565 ;
break ;
}
blizzard_wait_line_buffer ( ) ;
if ( blizzard . last_color_mode = = BLIZZARD_COLOR_YUV420 )
blizzard_wait_yyc ( ) ;
blizzard . last_color_mode = color_mode ;
if ( flags & OMAPFB_FORMAT_FLAG_TEARSYNC )
enable_tearsync ( gy1 , w , h ,
blizzard . screen_height ,
h_out ,
flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC ) ;
else
disable_tearsync ( ) ;
2009-09-22 16:46:53 -07:00
if ( ( gx2_out - gx1_out ) ! = ( gx2 - gx1 ) | |
( gy2_out - gy1_out ) ! = ( gy2 - gy1 ) )
have_zoom_for_this_update = 1 ;
/* 'background' type of screen update (as opposed to 'destructive')
can be used to disable scaling if scaling is active */
zoom_off = blizzard . zoom_on & & ! have_zoom_for_this_update & &
( gx1_out = = 0 ) & & ( gx2_out = = blizzard . screen_width ) & &
( gy1_out = = 0 ) & & ( gy2_out = = blizzard . screen_height ) & &
( gx1 = = 0 ) & & ( gy1 = = 0 ) ;
if ( blizzard . zoom_on & & ! have_zoom_for_this_update & & ! zoom_off & &
check_1d_intersect ( blizzard . zoom_area_gx1 , blizzard . zoom_area_gx2 ,
gx1_out , gx2_out ) & &
check_1d_intersect ( blizzard . zoom_area_gy1 , blizzard . zoom_area_gy2 ,
gy1_out , gy2_out ) ) {
/* Previous screen update was using scaling, current update
* is not using it . Additionally , current screen update is
* going to overlap with the scaled area . Scaling needs to be
* disabled in order to avoid ' magnifying glass ' effect .
* Dummy setup of background window can be used for this .
*/
set_window_regs ( 0 , 0 , blizzard . screen_width ,
blizzard . screen_height ,
0 , 0 , blizzard . screen_width ,
blizzard . screen_height ,
BLIZZARD_COLOR_RGB565 , 1 , flags ) ;
blizzard . zoom_on = 0 ;
}
/* remember scaling settings if we have scaled update */
if ( have_zoom_for_this_update ) {
blizzard . zoom_on = 1 ;
blizzard . zoom_area_gx1 = gx1_out ;
blizzard . zoom_area_gx2 = gx2_out ;
blizzard . zoom_area_gy1 = gy1_out ;
blizzard . zoom_area_gy2 = gy2_out ;
}
2007-07-17 04:06:01 -07:00
set_window_regs ( gx1 , gy1 , gx2 , gy2 , gx1_out , gy1_out , gx2_out , gy2_out ,
color_mode , zoom_off , flags ) ;
2009-09-22 16:46:53 -07:00
if ( zoom_off )
blizzard . zoom_on = 0 ;
2007-07-17 04:06:01 -07:00
blizzard . extif - > set_bits_per_cycle ( 16 ) ;
/* set_window_regs has left the register index at the right
* place , so no need to set it here .
*/
blizzard . extif - > transfer_area ( w , h , request_complete , req ) ;
return REQ_PENDING ;
}
static int send_frame_handler ( struct blizzard_request * req )
{
struct update_param * par = & req - > par . update ;
int plane = par - > plane ;
# ifdef VERBOSE
dev_dbg ( blizzard . fbdev - > dev ,
" send_frame: x %d y %d w %d h %d "
" x_out %d y_out %d w_out %d h_out %d "
" color_mode %04x flags %04x planes %01x \n " ,
par - > x , par - > y , par - > width , par - > height ,
par - > out_x , par - > out_y , par - > out_width , par - > out_height ,
par - > color_mode , par - > flags , blizzard . enabled_planes ) ;
# endif
if ( par - > flags & OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY )
disable_overlay ( ) ;
if ( ( blizzard . enabled_planes & blizzard . vid_nonstd_color ) | |
( blizzard . enabled_planes & blizzard . vid_scaled ) )
return do_full_screen_update ( req ) ;
return do_partial_update ( req , plane , par - > x , par - > y ,
par - > width , par - > height ,
par - > out_x , par - > out_y ,
par - > out_width , par - > out_height ,
par - > color_mode , par - > bpp ) ;
}
static void send_frame_complete ( void * data )
{
}
# define ADD_PREQ(_x, _y, _w, _h, _x_out, _y_out, _w_out, _h_out) do { \
req = alloc_req ( ) ; \
req - > handler = send_frame_handler ; \
req - > complete = send_frame_complete ; \
req - > par . update . plane = plane_idx ; \
req - > par . update . x = _x ; \
req - > par . update . y = _y ; \
req - > par . update . width = _w ; \
req - > par . update . height = _h ; \
req - > par . update . out_x = _x_out ; \
req - > par . update . out_y = _y_out ; \
req - > par . update . out_width = _w_out ; \
req - > par . update . out_height = _h_out ; \
req - > par . update . bpp = bpp ; \
req - > par . update . color_mode = color_mode ; \
req - > par . update . flags = flags ; \
list_add_tail ( & req - > entry , req_head ) ; \
} while ( 0 )
static void create_req_list ( int plane_idx ,
struct omapfb_update_window * win ,
struct list_head * req_head )
{
struct blizzard_request * req ;
int x = win - > x ;
int y = win - > y ;
int width = win - > width ;
int height = win - > height ;
int x_out = win - > out_x ;
int y_out = win - > out_y ;
int width_out = win - > out_width ;
int height_out = win - > out_height ;
int color_mode ;
int bpp ;
int flags ;
unsigned int ystart = y ;
unsigned int yspan = height ;
unsigned int ystart_out = y_out ;
unsigned int yspan_out = height_out ;
flags = win - > format & ~ OMAPFB_FORMAT_MASK ;
color_mode = win - > format & OMAPFB_FORMAT_MASK ;
switch ( color_mode ) {
case OMAPFB_COLOR_YUV420 :
/* Embedded window with different color mode */
bpp = 12 ;
/* X, Y, height must be aligned at 2, width at 4 pixels */
x & = ~ 1 ;
y & = ~ 1 ;
height = yspan = height & ~ 1 ;
width = width & ~ 3 ;
break ;
default :
/* Same as the plane color mode */
bpp = blizzard . plane [ plane_idx ] . bpp ;
break ;
}
if ( width * height * bpp / 8 > blizzard . max_transmit_size ) {
yspan = blizzard . max_transmit_size / ( width * bpp / 8 ) ;
yspan_out = yspan * height_out / height ;
ADD_PREQ ( x , ystart , width , yspan , x_out , ystart_out ,
width_out , yspan_out ) ;
ystart + = yspan ;
ystart_out + = yspan_out ;
yspan = height - yspan ;
yspan_out = height_out - yspan_out ;
flags & = ~ OMAPFB_FORMAT_FLAG_TEARSYNC ;
}
ADD_PREQ ( x , ystart , width , yspan , x_out , ystart_out ,
width_out , yspan_out ) ;
}
static void auto_update_complete ( void * data )
{
if ( ! blizzard . stop_auto_update )
mod_timer ( & blizzard . auto_update_timer ,
jiffies + BLIZZARD_AUTO_UPDATE_TIME ) ;
}
static void blizzard_update_window_auto ( unsigned long arg )
{
LIST_HEAD ( req_list ) ;
struct blizzard_request * last ;
struct omapfb_plane_struct * plane ;
plane = blizzard . fbdev - > fb_info [ 0 ] - > par ;
create_req_list ( plane - > idx ,
& blizzard . auto_update_window , & req_list ) ;
last = list_entry ( req_list . prev , struct blizzard_request , entry ) ;
last - > complete = auto_update_complete ;
last - > complete_data = NULL ;
submit_req_list ( & req_list ) ;
}
int blizzard_update_window_async ( struct fb_info * fbi ,
struct omapfb_update_window * win ,
void ( * complete_callback ) ( void * arg ) ,
void * complete_callback_data )
{
LIST_HEAD ( req_list ) ;
struct blizzard_request * last ;
struct omapfb_plane_struct * plane = fbi - > par ;
if ( unlikely ( blizzard . update_mode ! = OMAPFB_MANUAL_UPDATE ) )
return - EINVAL ;
if ( unlikely ( ! blizzard . te_connected & &
( win - > format & OMAPFB_FORMAT_FLAG_TEARSYNC ) ) )
return - EINVAL ;
create_req_list ( plane - > idx , win , & req_list ) ;
last = list_entry ( req_list . prev , struct blizzard_request , entry ) ;
last - > complete = complete_callback ;
last - > complete_data = ( void * ) complete_callback_data ;
submit_req_list ( & req_list ) ;
return 0 ;
}
EXPORT_SYMBOL ( blizzard_update_window_async ) ;
static int update_full_screen ( void )
{
return blizzard_update_window_async ( blizzard . fbdev - > fb_info [ 0 ] ,
& blizzard . auto_update_window , NULL , NULL ) ;
}
static int blizzard_setup_plane ( int plane , int channel_out ,
unsigned long offset , int screen_width ,
int pos_x , int pos_y , int width , int height ,
int color_mode )
{
struct plane_info * p ;
# ifdef VERBOSE
dev_dbg ( blizzard . fbdev - > dev ,
" plane %d ch_out %d offset %#08lx scr_width %d "
" pos_x %d pos_y %d width %d height %d color_mode %d \n " ,
plane , channel_out , offset , screen_width ,
pos_x , pos_y , width , height , color_mode ) ;
# endif
if ( ( unsigned ) plane > OMAPFB_PLANE_NUM )
return - EINVAL ;
p = & blizzard . plane [ plane ] ;
switch ( color_mode ) {
case OMAPFB_COLOR_YUV422 :
case OMAPFB_COLOR_YUY422 :
p - > bpp = 16 ;
blizzard . vid_nonstd_color & = ~ ( 1 < < plane ) ;
break ;
case OMAPFB_COLOR_YUV420 :
p - > bpp = 12 ;
blizzard . vid_nonstd_color | = 1 < < plane ;
break ;
case OMAPFB_COLOR_RGB565 :
p - > bpp = 16 ;
blizzard . vid_nonstd_color & = ~ ( 1 < < plane ) ;
break ;
default :
return - EINVAL ;
}
p - > offset = offset ;
p - > pos_x = pos_x ;
p - > pos_y = pos_y ;
p - > width = width ;
p - > height = height ;
p - > scr_width = screen_width ;
if ( ! p - > out_width )
p - > out_width = width ;
if ( ! p - > out_height )
p - > out_height = height ;
p - > color_mode = color_mode ;
return 0 ;
}
static int blizzard_set_scale ( int plane , int orig_w , int orig_h ,
int out_w , int out_h )
{
struct plane_info * p = & blizzard . plane [ plane ] ;
int r ;
dev_dbg ( blizzard . fbdev - > dev ,
" plane %d orig_w %d orig_h %d out_w %d out_h %d \n " ,
plane , orig_w , orig_h , out_w , out_h ) ;
if ( ( unsigned ) plane > OMAPFB_PLANE_NUM )
return - ENODEV ;
r = blizzard . int_ctrl - > set_scale ( plane , orig_w , orig_h , out_w , out_h ) ;
if ( r < 0 )
return r ;
p - > width = orig_w ;
p - > height = orig_h ;
p - > out_width = out_w ;
p - > out_height = out_h ;
if ( orig_w = = out_w & & orig_h = = out_h )
blizzard . vid_scaled & = ~ ( 1 < < plane ) ;
else
blizzard . vid_scaled | = 1 < < plane ;
return 0 ;
}
2009-09-22 16:46:53 -07:00
static int blizzard_set_rotate ( int angle )
{
u32 l ;
l = blizzard_read_reg ( BLIZZARD_PANEL_CONFIGURATION ) ;
l & = ~ 0x03 ;
switch ( angle ) {
case 0 :
l = l | 0x00 ;
break ;
case 90 :
l = l | 0x03 ;
break ;
case 180 :
l = l | 0x02 ;
break ;
case 270 :
l = l | 0x01 ;
break ;
default :
return - EINVAL ;
}
blizzard_write_reg ( BLIZZARD_PANEL_CONFIGURATION , l ) ;
return 0 ;
}
2007-07-17 04:06:01 -07:00
static int blizzard_enable_plane ( int plane , int enable )
{
if ( enable )
blizzard . enabled_planes | = 1 < < plane ;
else
blizzard . enabled_planes & = ~ ( 1 < < plane ) ;
return 0 ;
}
static int sync_handler ( struct blizzard_request * req )
{
complete ( req - > par . sync ) ;
return REQ_COMPLETE ;
}
static void blizzard_sync ( void )
{
LIST_HEAD ( req_list ) ;
struct blizzard_request * req ;
struct completion comp ;
req = alloc_req ( ) ;
req - > handler = sync_handler ;
req - > complete = NULL ;
init_completion ( & comp ) ;
req - > par . sync = & comp ;
list_add ( & req - > entry , & req_list ) ;
submit_req_list ( & req_list ) ;
wait_for_completion ( & comp ) ;
}
static void blizzard_bind_client ( struct omapfb_notifier_block * nb )
{
if ( blizzard . update_mode = = OMAPFB_MANUAL_UPDATE ) {
omapfb_notify_clients ( blizzard . fbdev , OMAPFB_EVENT_READY ) ;
}
}
static int blizzard_set_update_mode ( enum omapfb_update_mode mode )
{
if ( unlikely ( mode ! = OMAPFB_MANUAL_UPDATE & &
mode ! = OMAPFB_AUTO_UPDATE & &
mode ! = OMAPFB_UPDATE_DISABLED ) )
return - EINVAL ;
if ( mode = = blizzard . update_mode )
return 0 ;
dev_info ( blizzard . fbdev - > dev , " s1d1374x: setting update mode to %s \n " ,
mode = = OMAPFB_UPDATE_DISABLED ? " disabled " :
( mode = = OMAPFB_AUTO_UPDATE ? " auto " : " manual " ) ) ;
switch ( blizzard . update_mode ) {
case OMAPFB_MANUAL_UPDATE :
omapfb_notify_clients ( blizzard . fbdev , OMAPFB_EVENT_DISABLED ) ;
break ;
case OMAPFB_AUTO_UPDATE :
blizzard . stop_auto_update = 1 ;
del_timer_sync ( & blizzard . auto_update_timer ) ;
break ;
case OMAPFB_UPDATE_DISABLED :
break ;
}
blizzard . update_mode = mode ;
blizzard_sync ( ) ;
blizzard . stop_auto_update = 0 ;
switch ( mode ) {
case OMAPFB_MANUAL_UPDATE :
omapfb_notify_clients ( blizzard . fbdev , OMAPFB_EVENT_READY ) ;
break ;
case OMAPFB_AUTO_UPDATE :
blizzard_update_window_auto ( 0 ) ;
break ;
case OMAPFB_UPDATE_DISABLED :
break ;
}
return 0 ;
}
static enum omapfb_update_mode blizzard_get_update_mode ( void )
{
return blizzard . update_mode ;
}
static inline void set_extif_timings ( const struct extif_timings * t )
{
blizzard . extif - > set_timings ( t ) ;
}
static inline unsigned long round_to_extif_ticks ( unsigned long ps , int div )
{
int bus_tick = blizzard . extif_clk_period * div ;
return ( ps + bus_tick - 1 ) / bus_tick * bus_tick ;
}
static int calc_reg_timing ( unsigned long sysclk , int div )
{
struct extif_timings * t ;
unsigned long systim ;
/* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns,
* AccessTime 2 ns + 12.2 ns ( regs ) ,
* WEOffTime = WEOnTime + 1 ns ,
* REOffTime = REOnTime + 12 ns ( regs ) ,
* CSOffTime = REOffTime + 1 ns
* ReadCycle = 2 ns + 2 * SYSCLK ( regs ) ,
* WriteCycle = 2 * SYSCLK + 2 ns ,
* CSPulseWidth = 10 ns */
systim = 1000000000 / ( sysclk / 1000 ) ;
dev_dbg ( blizzard . fbdev - > dev ,
" Blizzard systim %lu ps extif_clk_period %u div %d \n " ,
systim , blizzard . extif_clk_period , div ) ;
t = & blizzard . reg_timings ;
memset ( t , 0 , sizeof ( * t ) ) ;
t - > clk_div = div ;
t - > cs_on_time = 0 ;
t - > we_on_time = round_to_extif_ticks ( t - > cs_on_time + 2000 , div ) ;
t - > re_on_time = round_to_extif_ticks ( t - > cs_on_time + 2000 , div ) ;
t - > access_time = round_to_extif_ticks ( t - > re_on_time + 12200 , div ) ;
t - > we_off_time = round_to_extif_ticks ( t - > we_on_time + 1000 , div ) ;
t - > re_off_time = round_to_extif_ticks ( t - > re_on_time + 13000 , div ) ;
t - > cs_off_time = round_to_extif_ticks ( t - > re_off_time + 1000 , div ) ;
t - > we_cycle_time = round_to_extif_ticks ( 2 * systim + 2000 , div ) ;
if ( t - > we_cycle_time < t - > we_off_time )
t - > we_cycle_time = t - > we_off_time ;
t - > re_cycle_time = round_to_extif_ticks ( 2 * systim + 2000 , div ) ;
if ( t - > re_cycle_time < t - > re_off_time )
t - > re_cycle_time = t - > re_off_time ;
t - > cs_pulse_width = 0 ;
dev_dbg ( blizzard . fbdev - > dev , " [reg]cson %d csoff %d reon %d reoff %d \n " ,
t - > cs_on_time , t - > cs_off_time , t - > re_on_time , t - > re_off_time ) ;
dev_dbg ( blizzard . fbdev - > dev , " [reg]weon %d weoff %d recyc %d wecyc %d \n " ,
t - > we_on_time , t - > we_off_time , t - > re_cycle_time ,
t - > we_cycle_time ) ;
dev_dbg ( blizzard . fbdev - > dev , " [reg]rdaccess %d cspulse %d \n " ,
t - > access_time , t - > cs_pulse_width ) ;
return blizzard . extif - > convert_timings ( t ) ;
}
static int calc_lut_timing ( unsigned long sysclk , int div )
{
struct extif_timings * t ;
unsigned long systim ;
/* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns,
* AccessTime 2 ns + 4 * SYSCLK + 26 ( lut ) ,
* WEOffTime = WEOnTime + 1 ns ,
* REOffTime = REOnTime + 4 * SYSCLK + 26 ns ( lut ) ,
* CSOffTime = REOffTime + 1 ns
* ReadCycle = 2 ns + 4 * SYSCLK + 26 ns ( lut ) ,
* WriteCycle = 2 * SYSCLK + 2 ns ,
* CSPulseWidth = 10 ns */
systim = 1000000000 / ( sysclk / 1000 ) ;
dev_dbg ( blizzard . fbdev - > dev ,
" Blizzard systim %lu ps extif_clk_period %u div %d \n " ,
systim , blizzard . extif_clk_period , div ) ;
t = & blizzard . lut_timings ;
memset ( t , 0 , sizeof ( * t ) ) ;
t - > clk_div = div ;
t - > cs_on_time = 0 ;
t - > we_on_time = round_to_extif_ticks ( t - > cs_on_time + 2000 , div ) ;
t - > re_on_time = round_to_extif_ticks ( t - > cs_on_time + 2000 , div ) ;
t - > access_time = round_to_extif_ticks ( t - > re_on_time + 4 * systim +
26000 , div ) ;
t - > we_off_time = round_to_extif_ticks ( t - > we_on_time + 1000 , div ) ;
t - > re_off_time = round_to_extif_ticks ( t - > re_on_time + 4 * systim +
26000 , div ) ;
t - > cs_off_time = round_to_extif_ticks ( t - > re_off_time + 1000 , div ) ;
t - > we_cycle_time = round_to_extif_ticks ( 2 * systim + 2000 , div ) ;
if ( t - > we_cycle_time < t - > we_off_time )
t - > we_cycle_time = t - > we_off_time ;
t - > re_cycle_time = round_to_extif_ticks ( 2000 + 4 * systim + 26000 , div ) ;
if ( t - > re_cycle_time < t - > re_off_time )
t - > re_cycle_time = t - > re_off_time ;
t - > cs_pulse_width = 0 ;
dev_dbg ( blizzard . fbdev - > dev ,
" [lut]cson %d csoff %d reon %d reoff %d \n " ,
t - > cs_on_time , t - > cs_off_time , t - > re_on_time , t - > re_off_time ) ;
dev_dbg ( blizzard . fbdev - > dev ,
" [lut]weon %d weoff %d recyc %d wecyc %d \n " ,
t - > we_on_time , t - > we_off_time , t - > re_cycle_time ,
t - > we_cycle_time ) ;
dev_dbg ( blizzard . fbdev - > dev , " [lut]rdaccess %d cspulse %d \n " ,
t - > access_time , t - > cs_pulse_width ) ;
return blizzard . extif - > convert_timings ( t ) ;
}
static int calc_extif_timings ( unsigned long sysclk , int * extif_mem_div )
{
int max_clk_div ;
int div ;
blizzard . extif - > get_clk_info ( & blizzard . extif_clk_period , & max_clk_div ) ;
for ( div = 1 ; div < = max_clk_div ; div + + ) {
if ( calc_reg_timing ( sysclk , div ) = = 0 )
break ;
}
if ( div > max_clk_div ) {
dev_dbg ( blizzard . fbdev - > dev , " reg timing failed \n " ) ;
goto err ;
}
* extif_mem_div = div ;
for ( div = 1 ; div < = max_clk_div ; div + + ) {
if ( calc_lut_timing ( sysclk , div ) = = 0 )
break ;
}
if ( div > max_clk_div )
goto err ;
blizzard . extif_clk_div = div ;
return 0 ;
err :
dev_err ( blizzard . fbdev - > dev , " can't setup timings \n " ) ;
return - 1 ;
}
static void calc_blizzard_clk_rates ( unsigned long ext_clk ,
unsigned long * sys_clk , unsigned long * pix_clk )
{
int pix_clk_src ;
int sys_div = 0 , sys_mul = 0 ;
int pix_div ;
pix_clk_src = blizzard_read_reg ( BLIZZARD_CLK_SRC ) ;
pix_div = ( ( pix_clk_src > > 3 ) & 0x1f ) + 1 ;
if ( ( pix_clk_src & ( 0x3 < < 1 ) ) = = 0 ) {
/* Source is the PLL */
sys_div = ( blizzard_read_reg ( BLIZZARD_PLL_DIV ) & 0x3f ) + 1 ;
sys_mul = blizzard_read_reg ( BLIZZARD_PLL_CLOCK_SYNTH_0 ) ;
sys_mul | = ( ( blizzard_read_reg ( BLIZZARD_PLL_CLOCK_SYNTH_1 )
& 0x0f ) < < 11 ) ;
* sys_clk = ext_clk * sys_mul / sys_div ;
} else /* else source is ext clk, or oscillator */
* sys_clk = ext_clk ;
* pix_clk = * sys_clk / pix_div ; /* HZ */
dev_dbg ( blizzard . fbdev - > dev ,
" ext_clk %ld pix_src %d pix_div %d sys_div %d sys_mul %d \n " ,
ext_clk , pix_clk_src & ( 0x3 < < 1 ) , pix_div , sys_div , sys_mul ) ;
dev_dbg ( blizzard . fbdev - > dev , " sys_clk %ld pix_clk %ld \n " ,
* sys_clk , * pix_clk ) ;
}
static int setup_tearsync ( unsigned long pix_clk , int extif_div )
{
int hdisp , vdisp ;
int hndp , vndp ;
int hsw , vsw ;
int hs , vs ;
int hs_pol_inv , vs_pol_inv ;
int use_hsvs , use_ndp ;
u8 b ;
hsw = blizzard_read_reg ( BLIZZARD_HSW ) ;
vsw = blizzard_read_reg ( BLIZZARD_VSW ) ;
hs_pol_inv = ! ( hsw & 0x80 ) ;
vs_pol_inv = ! ( vsw & 0x80 ) ;
hsw = hsw & 0x7f ;
vsw = vsw & 0x3f ;
hdisp = blizzard_read_reg ( BLIZZARD_HDISP ) * 8 ;
vdisp = blizzard_read_reg ( BLIZZARD_VDISP0 ) +
( ( blizzard_read_reg ( BLIZZARD_VDISP1 ) & 0x3 ) < < 8 ) ;
hndp = blizzard_read_reg ( BLIZZARD_HNDP ) & 0x3f ;
vndp = blizzard_read_reg ( BLIZZARD_VNDP ) ;
/* time to transfer one pixel (16bpp) in ps */
blizzard . pix_tx_time = blizzard . reg_timings . we_cycle_time ;
if ( blizzard . extif - > get_max_tx_rate ! = NULL ) {
/* The external interface might have a rate limitation,
* if so , we have to maximize our transfer rate .
*/
unsigned long min_tx_time ;
unsigned long max_tx_rate = blizzard . extif - > get_max_tx_rate ( ) ;
dev_dbg ( blizzard . fbdev - > dev , " max_tx_rate %ld HZ \n " ,
max_tx_rate ) ;
min_tx_time = 1000000000 / ( max_tx_rate / 1000 ) ; /* ps */
if ( blizzard . pix_tx_time < min_tx_time )
blizzard . pix_tx_time = min_tx_time ;
}
/* time to update one line in ps */
blizzard . line_upd_time = ( hdisp + hndp ) * 1000000 / ( pix_clk / 1000 ) ;
blizzard . line_upd_time * = 1000 ;
if ( hdisp * blizzard . pix_tx_time > blizzard . line_upd_time )
/* transfer speed too low, we might have to use both
* HS and VS */
use_hsvs = 1 ;
else
/* decent transfer speed, we'll always use only VS */
use_hsvs = 0 ;
if ( use_hsvs & & ( hs_pol_inv | | vs_pol_inv ) ) {
/* HS or'ed with VS doesn't work, use the active high
* TE signal based on HNDP / VNDP */
use_ndp = 1 ;
hs_pol_inv = 0 ;
vs_pol_inv = 0 ;
hs = hndp ;
vs = vndp ;
} else {
/* Use HS or'ed with VS as a TE signal if both are needed
* or VNDP if only vsync is needed . */
use_ndp = 0 ;
hs = hsw ;
vs = vsw ;
if ( ! use_hsvs ) {
hs_pol_inv = 0 ;
vs_pol_inv = 0 ;
}
}
hs = hs * 1000000 / ( pix_clk / 1000 ) ; /* ps */
hs * = 1000 ;
vs = vs * ( hdisp + hndp ) * 1000000 / ( pix_clk / 1000 ) ; /* ps */
vs * = 1000 ;
if ( vs < = hs )
return - EDOM ;
/* set VS to 120% of HS to minimize VS detection time */
vs = hs * 12 / 10 ;
/* minimize HS too */
if ( hs > 10000 )
hs = 10000 ;
b = blizzard_read_reg ( BLIZZARD_NDISP_CTRL_STATUS ) ;
b & = ~ 0x3 ;
b | = use_hsvs ? 1 : 0 ;
b | = ( use_ndp & & use_hsvs ) ? 0 : 2 ;
blizzard_write_reg ( BLIZZARD_NDISP_CTRL_STATUS , b ) ;
blizzard . vsync_only = ! use_hsvs ;
dev_dbg ( blizzard . fbdev - > dev ,
" pix_clk %ld HZ pix_tx_time %ld ps line_upd_time %ld ps \n " ,
pix_clk , blizzard . pix_tx_time , blizzard . line_upd_time ) ;
dev_dbg ( blizzard . fbdev - > dev ,
" hs %d ps vs %d ps mode %d vsync_only %d \n " ,
hs , vs , b & 0x3 , ! use_hsvs ) ;
return blizzard . extif - > setup_tearsync ( 1 , hs , vs ,
hs_pol_inv , vs_pol_inv ,
extif_div ) ;
}
static void blizzard_get_caps ( int plane , struct omapfb_caps * caps )
{
blizzard . int_ctrl - > get_caps ( plane , caps ) ;
caps - > ctrl | = OMAPFB_CAPS_MANUAL_UPDATE |
OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE |
OMAPFB_CAPS_WINDOW_SCALE |
2009-09-22 16:46:53 -07:00
OMAPFB_CAPS_WINDOW_OVERLAY |
OMAPFB_CAPS_WINDOW_ROTATE ;
2007-07-17 04:06:01 -07:00
if ( blizzard . te_connected )
caps - > ctrl | = OMAPFB_CAPS_TEARSYNC ;
caps - > wnd_color | = ( 1 < < OMAPFB_COLOR_RGB565 ) |
( 1 < < OMAPFB_COLOR_YUV420 ) ;
}
2009-10-05 13:31:47 -07:00
static void _save_regs ( const struct blizzard_reg_list * list , int cnt )
2007-07-17 04:06:01 -07:00
{
int i ;
for ( i = 0 ; i < cnt ; i + + , list + + ) {
int reg ;
for ( reg = list - > start ; reg < = list - > end ; reg + = 2 )
blizzard_reg_cache [ reg / 2 ] = blizzard_read_reg ( reg ) ;
}
}
2009-10-05 13:31:47 -07:00
static void _restore_regs ( const struct blizzard_reg_list * list , int cnt )
2007-07-17 04:06:01 -07:00
{
int i ;
for ( i = 0 ; i < cnt ; i + + , list + + ) {
int reg ;
for ( reg = list - > start ; reg < = list - > end ; reg + = 2 )
blizzard_write_reg ( reg , blizzard_reg_cache [ reg / 2 ] ) ;
}
}
static void blizzard_save_all_regs ( void )
{
_save_regs ( blizzard_pll_regs , ARRAY_SIZE ( blizzard_pll_regs ) ) ;
_save_regs ( blizzard_gen_regs , ARRAY_SIZE ( blizzard_gen_regs ) ) ;
}
static void blizzard_restore_pll_regs ( void )
{
_restore_regs ( blizzard_pll_regs , ARRAY_SIZE ( blizzard_pll_regs ) ) ;
}
static void blizzard_restore_gen_regs ( void )
{
_restore_regs ( blizzard_gen_regs , ARRAY_SIZE ( blizzard_gen_regs ) ) ;
}
static void blizzard_suspend ( void )
{
u32 l ;
unsigned long tmo ;
if ( blizzard . last_color_mode ) {
update_full_screen ( ) ;
blizzard_sync ( ) ;
}
blizzard . update_mode_before_suspend = blizzard . update_mode ;
/* the following will disable clocks as well */
blizzard_set_update_mode ( OMAPFB_UPDATE_DISABLED ) ;
blizzard_save_all_regs ( ) ;
blizzard_stop_sdram ( ) ;
l = blizzard_read_reg ( BLIZZARD_POWER_SAVE ) ;
/* Standby, Sleep. We assume we use an external clock. */
l | = 0x03 ;
blizzard_write_reg ( BLIZZARD_POWER_SAVE , l ) ;
tmo = jiffies + msecs_to_jiffies ( 100 ) ;
while ( ! ( blizzard_read_reg ( BLIZZARD_PLL_MODE ) & ( 1 < < 1 ) ) ) {
if ( time_after ( jiffies , tmo ) ) {
dev_err ( blizzard . fbdev - > dev ,
" s1d1374x: sleep timeout, stopping PLL manually \n " ) ;
l = blizzard_read_reg ( BLIZZARD_PLL_MODE ) ;
l & = ~ 0x03 ;
/* Disable PLL, counter function */
l | = 0x2 ;
blizzard_write_reg ( BLIZZARD_PLL_MODE , l ) ;
break ;
}
msleep ( 1 ) ;
}
if ( blizzard . power_down ! = NULL )
blizzard . power_down ( blizzard . fbdev - > dev ) ;
}
static void blizzard_resume ( void )
{
u32 l ;
if ( blizzard . power_up ! = NULL )
blizzard . power_up ( blizzard . fbdev - > dev ) ;
l = blizzard_read_reg ( BLIZZARD_POWER_SAVE ) ;
/* Standby, Sleep */
l & = ~ 0x03 ;
blizzard_write_reg ( BLIZZARD_POWER_SAVE , l ) ;
blizzard_restore_pll_regs ( ) ;
l = blizzard_read_reg ( BLIZZARD_PLL_MODE ) ;
l & = ~ 0x03 ;
/* Enable PLL, counter function */
l | = 0x1 ;
blizzard_write_reg ( BLIZZARD_PLL_MODE , l ) ;
while ( ! ( blizzard_read_reg ( BLIZZARD_PLL_DIV ) & ( 1 < < 7 ) ) )
msleep ( 1 ) ;
blizzard_restart_sdram ( ) ;
blizzard_restore_gen_regs ( ) ;
/* Enable display */
blizzard_write_reg ( BLIZZARD_DISPLAY_MODE , 0x01 ) ;
/* the following will enable clocks as necessary */
blizzard_set_update_mode ( blizzard . update_mode_before_suspend ) ;
/* Force a background update */
blizzard . zoom_on = 1 ;
update_full_screen ( ) ;
blizzard_sync ( ) ;
}
static int blizzard_init ( struct omapfb_device * fbdev , int ext_mode ,
struct omapfb_mem_desc * req_vram )
{
int r = 0 , i ;
u8 rev , conf ;
unsigned long ext_clk ;
int extif_div ;
unsigned long sys_clk , pix_clk ;
struct omapfb_platform_data * omapfb_conf ;
struct blizzard_platform_data * ctrl_conf ;
blizzard . fbdev = fbdev ;
BUG_ON ( ! fbdev - > ext_if | | ! fbdev - > int_ctrl ) ;
blizzard . fbdev = fbdev ;
blizzard . extif = fbdev - > ext_if ;
blizzard . int_ctrl = fbdev - > int_ctrl ;
omapfb_conf = fbdev - > dev - > platform_data ;
ctrl_conf = omapfb_conf - > ctrl_platform_data ;
if ( ctrl_conf = = NULL | | ctrl_conf - > get_clock_rate = = NULL ) {
dev_err ( fbdev - > dev , " s1d1374x: missing platform data \n " ) ;
r = - ENOENT ;
goto err1 ;
}
blizzard . power_down = ctrl_conf - > power_down ;
blizzard . power_up = ctrl_conf - > power_up ;
spin_lock_init ( & blizzard . req_lock ) ;
if ( ( r = blizzard . int_ctrl - > init ( fbdev , 1 , req_vram ) ) < 0 )
goto err1 ;
if ( ( r = blizzard . extif - > init ( fbdev ) ) < 0 )
goto err2 ;
blizzard_ctrl . set_color_key = blizzard . int_ctrl - > set_color_key ;
blizzard_ctrl . get_color_key = blizzard . int_ctrl - > get_color_key ;
blizzard_ctrl . setup_mem = blizzard . int_ctrl - > setup_mem ;
blizzard_ctrl . mmap = blizzard . int_ctrl - > mmap ;
ext_clk = ctrl_conf - > get_clock_rate ( fbdev - > dev ) ;
if ( ( r = calc_extif_timings ( ext_clk , & extif_div ) ) < 0 )
goto err3 ;
set_extif_timings ( & blizzard . reg_timings ) ;
if ( blizzard . power_up ! = NULL )
blizzard . power_up ( fbdev - > dev ) ;
calc_blizzard_clk_rates ( ext_clk , & sys_clk , & pix_clk ) ;
if ( ( r = calc_extif_timings ( sys_clk , & extif_div ) ) < 0 )
goto err3 ;
set_extif_timings ( & blizzard . reg_timings ) ;
if ( ! ( blizzard_read_reg ( BLIZZARD_PLL_DIV ) & 0x80 ) ) {
dev_err ( fbdev - > dev ,
" controller not initialized by the bootloader \n " ) ;
r = - ENODEV ;
goto err3 ;
}
if ( ctrl_conf - > te_connected ) {
if ( ( r = setup_tearsync ( pix_clk , extif_div ) ) < 0 )
goto err3 ;
blizzard . te_connected = 1 ;
}
rev = blizzard_read_reg ( BLIZZARD_REV_CODE ) ;
conf = blizzard_read_reg ( BLIZZARD_CONFIG ) ;
switch ( rev & 0xfc ) {
case 0x9c :
blizzard . version = BLIZZARD_VERSION_S1D13744 ;
pr_info ( " omapfb: s1d13744 LCD controller rev %d "
" initialized (CNF pins %x) \n " , rev & 0x03 , conf & 0x07 ) ;
break ;
case 0xa4 :
blizzard . version = BLIZZARD_VERSION_S1D13745 ;
pr_info ( " omapfb: s1d13745 LCD controller rev %d "
" initialized (CNF pins %x) \n " , rev & 0x03 , conf & 0x07 ) ;
break ;
default :
dev_err ( fbdev - > dev , " invalid s1d1374x revision %02x \n " ,
rev ) ;
r = - ENODEV ;
goto err3 ;
}
blizzard . max_transmit_size = blizzard . extif - > max_transmit_size ;
blizzard . update_mode = OMAPFB_UPDATE_DISABLED ;
blizzard . auto_update_window . x = 0 ;
blizzard . auto_update_window . y = 0 ;
blizzard . auto_update_window . width = fbdev - > panel - > x_res ;
blizzard . auto_update_window . height = fbdev - > panel - > y_res ;
blizzard . auto_update_window . out_x = 0 ;
blizzard . auto_update_window . out_x = 0 ;
blizzard . auto_update_window . out_width = fbdev - > panel - > x_res ;
blizzard . auto_update_window . out_height = fbdev - > panel - > y_res ;
blizzard . auto_update_window . format = 0 ;
blizzard . screen_width = fbdev - > panel - > x_res ;
blizzard . screen_height = fbdev - > panel - > y_res ;
init_timer ( & blizzard . auto_update_timer ) ;
blizzard . auto_update_timer . function = blizzard_update_window_auto ;
blizzard . auto_update_timer . data = 0 ;
INIT_LIST_HEAD ( & blizzard . free_req_list ) ;
INIT_LIST_HEAD ( & blizzard . pending_req_list ) ;
for ( i = 0 ; i < ARRAY_SIZE ( blizzard . req_pool ) ; i + + )
list_add ( & blizzard . req_pool [ i ] . entry , & blizzard . free_req_list ) ;
BUG_ON ( i < = IRQ_REQ_POOL_SIZE ) ;
sema_init ( & blizzard . req_sema , i - IRQ_REQ_POOL_SIZE ) ;
return 0 ;
err3 :
if ( blizzard . power_down ! = NULL )
blizzard . power_down ( fbdev - > dev ) ;
blizzard . extif - > cleanup ( ) ;
err2 :
blizzard . int_ctrl - > cleanup ( ) ;
err1 :
return r ;
}
static void blizzard_cleanup ( void )
{
blizzard_set_update_mode ( OMAPFB_UPDATE_DISABLED ) ;
blizzard . extif - > cleanup ( ) ;
blizzard . int_ctrl - > cleanup ( ) ;
if ( blizzard . power_down ! = NULL )
blizzard . power_down ( blizzard . fbdev - > dev ) ;
}
struct lcd_ctrl blizzard_ctrl = {
. name = " blizzard " ,
. init = blizzard_init ,
. cleanup = blizzard_cleanup ,
. bind_client = blizzard_bind_client ,
. get_caps = blizzard_get_caps ,
. set_update_mode = blizzard_set_update_mode ,
. get_update_mode = blizzard_get_update_mode ,
. setup_plane = blizzard_setup_plane ,
. set_scale = blizzard_set_scale ,
. enable_plane = blizzard_enable_plane ,
2009-09-22 16:46:53 -07:00
. set_rotate = blizzard_set_rotate ,
2007-07-17 04:06:01 -07:00
. update_window = blizzard_update_window_async ,
. sync = blizzard_sync ,
. suspend = blizzard_suspend ,
. resume = blizzard_resume ,
} ;