2006-07-03 00:24:19 -07:00
/*
* drivers / video / pnx4008 / sdum . c
*
* Display Update Master support
*
* Authors : Grigory Tolstolytkin < gtolstolytkin @ ru . mvista . com >
* Vitaly Wool < vitalywool @ gmail . com >
* Based on Philips Semiconductors ' s code
*
* Copyrght ( c ) 2005 - 2006 MontaVista Software , Inc .
* Copyright ( c ) 2005 Philips Semiconductors
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed " as is " without any warranty of any
* kind , whether express or implied .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/string.h>
# include <linux/mm.h>
# include <linux/tty.h>
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <linux/delay.h>
# include <linux/interrupt.h>
# include <linux/platform_device.h>
# include <linux/fb.h>
# include <linux/init.h>
# include <linux/dma-mapping.h>
# include <linux/clk.h>
# include <asm/uaccess.h>
# include <asm/arch/gpio.h>
# include "sdum.h"
# include "fbcommon.h"
# include "dum.h"
/* Framebuffers we have */
static struct pnx4008_fb_addr {
int fb_type ;
long addr_offset ;
long fb_length ;
} fb_addr [ ] = {
[ 0 ] = {
FB_TYPE_YUV , 0 , 0xB0000
} ,
[ 1 ] = {
FB_TYPE_RGB , 0xB0000 , 0x50000
} ,
} ;
static struct dum_data {
u32 lcd_phys_start ;
u32 lcd_virt_start ;
u32 slave_phys_base ;
u32 * slave_virt_base ;
int fb_owning_channel [ MAX_DUM_CHANNELS ] ;
struct dumchannel_uf chan_uf_store [ MAX_DUM_CHANNELS ] ;
} dum_data ;
/* Different local helper functions */
static u32 nof_pixels_dx ( struct dum_ch_setup * ch_setup )
{
return ( ch_setup - > xmax - ch_setup - > xmin + 1 ) ;
}
static u32 nof_pixels_dy ( struct dum_ch_setup * ch_setup )
{
return ( ch_setup - > ymax - ch_setup - > ymin + 1 ) ;
}
static u32 nof_pixels_dxy ( struct dum_ch_setup * ch_setup )
{
return ( nof_pixels_dx ( ch_setup ) * nof_pixels_dy ( ch_setup ) ) ;
}
static u32 nof_bytes ( struct dum_ch_setup * ch_setup )
{
u32 r = nof_pixels_dxy ( ch_setup ) ;
switch ( ch_setup - > format ) {
case RGB888 :
case RGB666 :
r * = 4 ;
break ;
default :
r * = 2 ;
break ;
}
return r ;
}
static u32 build_command ( int disp_no , u32 reg , u32 val )
{
return ( ( disp_no < < 26 ) | BIT ( 25 ) | ( val < < 16 ) | ( disp_no < < 10 ) |
( reg < < 0 ) ) ;
}
static u32 build_double_index ( int disp_no , u32 val )
{
return ( ( disp_no < < 26 ) | ( val < < 16 ) | ( disp_no < < 10 ) | ( val < < 0 ) ) ;
}
static void build_disp_window ( struct dum_ch_setup * ch_setup , struct disp_window * dw )
{
dw - > ymin = ch_setup - > ymin ;
dw - > ymax = ch_setup - > ymax ;
dw - > xmin_l = ch_setup - > xmin & 0xFF ;
dw - > xmin_h = ( ch_setup - > xmin & BIT ( 8 ) ) > > 8 ;
dw - > xmax_l = ch_setup - > xmax & 0xFF ;
dw - > xmax_h = ( ch_setup - > xmax & BIT ( 8 ) ) > > 8 ;
}
static int put_channel ( struct dumchannel chan )
{
int i = chan . channelnr ;
if ( i < 0 | | i > MAX_DUM_CHANNELS )
return - EINVAL ;
else {
DUM_CH_MIN ( i ) = chan . dum_ch_min ;
DUM_CH_MAX ( i ) = chan . dum_ch_max ;
DUM_CH_CONF ( i ) = chan . dum_ch_conf ;
DUM_CH_CTRL ( i ) = chan . dum_ch_ctrl ;
}
return 0 ;
}
static void clear_channel ( int channr )
{
struct dumchannel chan ;
chan . channelnr = channr ;
chan . dum_ch_min = 0 ;
chan . dum_ch_max = 0 ;
chan . dum_ch_conf = 0 ;
chan . dum_ch_ctrl = 0 ;
put_channel ( chan ) ;
}
static int put_cmd_string ( struct cmdstring cmds )
{
u16 * cmd_str_virtaddr ;
u32 * cmd_ptr0_virtaddr ;
u32 cmd_str_physaddr ;
int i = cmds . channelnr ;
if ( i < 0 | | i > MAX_DUM_CHANNELS )
return - EINVAL ;
else if ( ( cmd_ptr0_virtaddr =
( int * ) ioremap_nocache ( DUM_COM_BASE ,
sizeof ( int ) * MAX_DUM_CHANNELS ) ) = =
NULL )
return - EIOREMAPFAILED ;
else {
cmd_str_physaddr = ioread32 ( & cmd_ptr0_virtaddr [ cmds . channelnr ] ) ;
if ( ( cmd_str_virtaddr =
( u16 * ) ioremap_nocache ( cmd_str_physaddr ,
sizeof ( cmds ) ) ) = = NULL ) {
iounmap ( cmd_ptr0_virtaddr ) ;
return - EIOREMAPFAILED ;
} else {
int t ;
for ( t = 0 ; t < 8 ; t + + )
iowrite16 ( * ( ( u16 * ) & cmds . prestringlen + t ) ,
cmd_str_virtaddr + t ) ;
for ( t = 0 ; t < cmds . prestringlen / 2 ; t + + )
iowrite16 ( * ( ( u16 * ) & cmds . precmd + t ) ,
cmd_str_virtaddr + t + 8 ) ;
for ( t = 0 ; t < cmds . poststringlen / 2 ; t + + )
iowrite16 ( * ( ( u16 * ) & cmds . postcmd + t ) ,
cmd_str_virtaddr + t + 8 +
cmds . prestringlen / 2 ) ;
iounmap ( cmd_ptr0_virtaddr ) ;
iounmap ( cmd_str_virtaddr ) ;
}
}
return 0 ;
}
static u32 dum_ch_setup ( int ch_no , struct dum_ch_setup * ch_setup )
{
struct cmdstring cmds_c ;
struct cmdstring * cmds = & cmds_c ;
struct disp_window dw ;
int standard ;
u32 orientation = 0 ;
struct dumchannel chan = { 0 } ;
int ret ;
if ( ( ch_setup - > xmirror ) | | ( ch_setup - > ymirror ) | | ( ch_setup - > rotate ) ) {
standard = 0 ;
orientation = BIT ( 1 ) ; /* always set 9-bit-bus */
if ( ch_setup - > xmirror )
orientation | = BIT ( 4 ) ;
if ( ch_setup - > ymirror )
orientation | = BIT ( 3 ) ;
if ( ch_setup - > rotate )
orientation | = BIT ( 0 ) ;
} else
standard = 1 ;
cmds - > channelnr = ch_no ;
/* build command string header */
if ( standard ) {
cmds - > prestringlen = 32 ;
cmds - > poststringlen = 0 ;
} else {
cmds - > prestringlen = 48 ;
cmds - > poststringlen = 16 ;
}
cmds - > format =
( u16 ) ( ( ch_setup - > disp_no < < 4 ) | ( BIT ( 3 ) ) | ( ch_setup - > format ) ) ;
cmds - > reserved = 0x0 ;
cmds - > startaddr_low = ( ch_setup - > minadr & 0xFFFF ) ;
cmds - > startaddr_high = ( ch_setup - > minadr > > 16 ) ;
if ( ( ch_setup - > minadr = = 0 ) & & ( ch_setup - > maxadr = = 0 )
& & ( ch_setup - > xmin = = 0 )
& & ( ch_setup - > ymin = = 0 ) & & ( ch_setup - > xmax = = 0 )
& & ( ch_setup - > ymax = = 0 ) ) {
cmds - > pixdatlen_low = 0 ;
cmds - > pixdatlen_high = 0 ;
} else {
u32 nbytes = nof_bytes ( ch_setup ) ;
cmds - > pixdatlen_low = ( nbytes & 0xFFFF ) ;
cmds - > pixdatlen_high = ( nbytes > > 16 ) ;
}
if ( ch_setup - > slave_trans )
cmds - > pixdatlen_high | = BIT ( 15 ) ;
/* build pre-string */
build_disp_window ( ch_setup , & dw ) ;
if ( standard ) {
cmds - > precmd [ 0 ] =
build_command ( ch_setup - > disp_no , DISP_XMIN_L_REG , 0x99 ) ;
cmds - > precmd [ 1 ] =
build_command ( ch_setup - > disp_no , DISP_XMIN_L_REG ,
dw . xmin_l ) ;
cmds - > precmd [ 2 ] =
build_command ( ch_setup - > disp_no , DISP_XMIN_H_REG ,
dw . xmin_h ) ;
cmds - > precmd [ 3 ] =
build_command ( ch_setup - > disp_no , DISP_YMIN_REG , dw . ymin ) ;
cmds - > precmd [ 4 ] =
build_command ( ch_setup - > disp_no , DISP_XMAX_L_REG ,
dw . xmax_l ) ;
cmds - > precmd [ 5 ] =
build_command ( ch_setup - > disp_no , DISP_XMAX_H_REG ,
dw . xmax_h ) ;
cmds - > precmd [ 6 ] =
build_command ( ch_setup - > disp_no , DISP_YMAX_REG , dw . ymax ) ;
cmds - > precmd [ 7 ] =
build_double_index ( ch_setup - > disp_no , DISP_PIXEL_REG ) ;
} else {
if ( dw . xmin_l = = ch_no )
cmds - > precmd [ 0 ] =
build_command ( ch_setup - > disp_no , DISP_XMIN_L_REG ,
0x99 ) ;
else
cmds - > precmd [ 0 ] =
build_command ( ch_setup - > disp_no , DISP_XMIN_L_REG ,
ch_no ) ;
cmds - > precmd [ 1 ] =
build_command ( ch_setup - > disp_no , DISP_XMIN_L_REG ,
dw . xmin_l ) ;
cmds - > precmd [ 2 ] =
build_command ( ch_setup - > disp_no , DISP_XMIN_H_REG ,
dw . xmin_h ) ;
cmds - > precmd [ 3 ] =
build_command ( ch_setup - > disp_no , DISP_YMIN_REG , dw . ymin ) ;
cmds - > precmd [ 4 ] =
build_command ( ch_setup - > disp_no , DISP_XMAX_L_REG ,
dw . xmax_l ) ;
cmds - > precmd [ 5 ] =
build_command ( ch_setup - > disp_no , DISP_XMAX_H_REG ,
dw . xmax_h ) ;
cmds - > precmd [ 6 ] =
build_command ( ch_setup - > disp_no , DISP_YMAX_REG , dw . ymax ) ;
cmds - > precmd [ 7 ] =
build_command ( ch_setup - > disp_no , DISP_1_REG , orientation ) ;
cmds - > precmd [ 8 ] =
build_double_index ( ch_setup - > disp_no , DISP_PIXEL_REG ) ;
cmds - > precmd [ 9 ] =
build_double_index ( ch_setup - > disp_no , DISP_PIXEL_REG ) ;
cmds - > precmd [ 0xA ] =
build_double_index ( ch_setup - > disp_no , DISP_PIXEL_REG ) ;
cmds - > precmd [ 0xB ] =
build_double_index ( ch_setup - > disp_no , DISP_PIXEL_REG ) ;
cmds - > postcmd [ 0 ] =
build_command ( ch_setup - > disp_no , DISP_1_REG , BIT ( 1 ) ) ;
cmds - > postcmd [ 1 ] =
build_command ( ch_setup - > disp_no , DISP_DUMMY1_REG , 1 ) ;
cmds - > postcmd [ 2 ] =
build_command ( ch_setup - > disp_no , DISP_DUMMY1_REG , 2 ) ;
cmds - > postcmd [ 3 ] =
build_command ( ch_setup - > disp_no , DISP_DUMMY1_REG , 3 ) ;
}
if ( ( ret = put_cmd_string ( cmds_c ) ) ! = 0 ) {
return ret ;
}
chan . channelnr = cmds - > channelnr ;
chan . dum_ch_min = ch_setup - > dirtybuffer + ch_setup - > minadr ;
chan . dum_ch_max = ch_setup - > dirtybuffer + ch_setup - > maxadr ;
chan . dum_ch_conf = 0x002 ;
chan . dum_ch_ctrl = 0x04 ;
put_channel ( chan ) ;
return 0 ;
}
static u32 display_open ( int ch_no , int auto_update , u32 * dirty_buffer ,
u32 * frame_buffer , u32 xpos , u32 ypos , u32 w , u32 h )
{
struct dum_ch_setup k ;
int ret ;
/* keep width & height within display area */
if ( ( xpos + w ) > DISP_MAX_X_SIZE )
w = DISP_MAX_X_SIZE - xpos ;
if ( ( ypos + h ) > DISP_MAX_Y_SIZE )
h = DISP_MAX_Y_SIZE - ypos ;
/* assume 1 display only */
k . disp_no = 0 ;
k . xmin = xpos ;
k . ymin = ypos ;
k . xmax = xpos + ( w - 1 ) ;
k . ymax = ypos + ( h - 1 ) ;
/* adjust min and max values if necessary */
if ( k . xmin > DISP_MAX_X_SIZE - 1 )
k . xmin = DISP_MAX_X_SIZE - 1 ;
if ( k . ymin > DISP_MAX_Y_SIZE - 1 )
k . ymin = DISP_MAX_Y_SIZE - 1 ;
if ( k . xmax > DISP_MAX_X_SIZE - 1 )
k . xmax = DISP_MAX_X_SIZE - 1 ;
if ( k . ymax > DISP_MAX_Y_SIZE - 1 )
k . ymax = DISP_MAX_Y_SIZE - 1 ;
k . xmirror = 0 ;
k . ymirror = 0 ;
k . rotate = 0 ;
k . minadr = ( u32 ) frame_buffer ;
k . maxadr = ( u32 ) frame_buffer + ( ( ( w - 1 ) < < 10 ) | ( ( h < < 2 ) - 2 ) ) ;
k . pad = PAD_1024 ;
k . dirtybuffer = ( u32 ) dirty_buffer ;
k . format = RGB888 ;
k . hwdirty = 0 ;
k . slave_trans = 0 ;
ret = dum_ch_setup ( ch_no , & k ) ;
return ret ;
}
static void lcd_reset ( void )
{
u32 * dum_pio_base = ( u32 * ) IO_ADDRESS ( PNX4008_PIO_BASE ) ;
udelay ( 1 ) ;
iowrite32 ( BIT ( 19 ) , & dum_pio_base [ 2 ] ) ;
udelay ( 1 ) ;
iowrite32 ( BIT ( 19 ) , & dum_pio_base [ 1 ] ) ;
udelay ( 1 ) ;
}
static int dum_init ( struct platform_device * pdev )
{
struct clk * clk ;
/* enable DUM clock */
clk = clk_get ( & pdev - > dev , " dum_ck " ) ;
if ( IS_ERR ( clk ) ) {
printk ( KERN_ERR " pnx4008_dum: Unable to access DUM clock \n " ) ;
return PTR_ERR ( clk ) ;
}
clk_set_rate ( clk , 1 ) ;
clk_put ( clk ) ;
DUM_CTRL = V_DUM_RESET ;
/* set priority to "round-robin". All other params to "false" */
DUM_CONF = BIT ( 9 ) ;
/* Display 1 */
DUM_WTCFG1 = PNX4008_DUM_WT_CFG ;
DUM_RTCFG1 = PNX4008_DUM_RT_CFG ;
DUM_TCFG = PNX4008_DUM_T_CFG ;
return 0 ;
}
static void dum_chan_init ( void )
{
int i = 0 , ch = 0 ;
u32 * cmdptrs ;
u32 * cmdstrings ;
DUM_COM_BASE =
CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS ;
if ( ( cmdptrs =
( u32 * ) ioremap_nocache ( DUM_COM_BASE ,
sizeof ( u32 ) * NR_OF_CMDSTRINGS ) ) = = NULL )
return ;
for ( ch = 0 ; ch < NR_OF_CMDSTRINGS ; ch + + )
iowrite32 ( CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * ch ,
cmdptrs + ch ) ;
for ( ch = 0 ; ch < MAX_DUM_CHANNELS ; ch + + )
clear_channel ( ch ) ;
/* Clear the cmdstrings */
cmdstrings =
( u32 * ) ioremap_nocache ( * cmdptrs ,
BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS ) ;
if ( ! cmdstrings )
goto out ;
for ( i = 0 ; i < NR_OF_CMDSTRINGS * BYTES_PER_CMDSTRING / sizeof ( u32 ) ;
i + + )
iowrite32 ( 0 , cmdstrings + i ) ;
iounmap ( ( u32 * ) cmdstrings ) ;
out :
iounmap ( ( u32 * ) cmdptrs ) ;
}
static void lcd_init ( void )
{
lcd_reset ( ) ;
DUM_OUTP_FORMAT1 = 0 ; /* RGB666 */
udelay ( 1 ) ;
iowrite32 ( V_LCD_STANDBY_OFF , dum_data . slave_virt_base ) ;
udelay ( 1 ) ;
iowrite32 ( V_LCD_USE_9BIT_BUS , dum_data . slave_virt_base ) ;
udelay ( 1 ) ;
iowrite32 ( V_LCD_SYNC_RISE_L , dum_data . slave_virt_base ) ;
udelay ( 1 ) ;
iowrite32 ( V_LCD_SYNC_RISE_H , dum_data . slave_virt_base ) ;
udelay ( 1 ) ;
iowrite32 ( V_LCD_SYNC_FALL_L , dum_data . slave_virt_base ) ;
udelay ( 1 ) ;
iowrite32 ( V_LCD_SYNC_FALL_H , dum_data . slave_virt_base ) ;
udelay ( 1 ) ;
iowrite32 ( V_LCD_SYNC_ENABLE , dum_data . slave_virt_base ) ;
udelay ( 1 ) ;
iowrite32 ( V_LCD_DISPLAY_ON , dum_data . slave_virt_base ) ;
udelay ( 1 ) ;
}
/* Interface exported to framebuffer drivers */
int pnx4008_get_fb_addresses ( int fb_type , void * * virt_addr ,
dma_addr_t * phys_addr , int * fb_length )
{
int i ;
int ret = - 1 ;
for ( i = 0 ; i < ARRAY_SIZE ( fb_addr ) ; i + + )
if ( fb_addr [ i ] . fb_type = = fb_type ) {
* virt_addr = ( void * ) ( dum_data . lcd_virt_start +
fb_addr [ i ] . addr_offset ) ;
* phys_addr =
dum_data . lcd_phys_start + fb_addr [ i ] . addr_offset ;
* fb_length = fb_addr [ i ] . fb_length ;
ret = 0 ;
break ;
}
return ret ;
}
EXPORT_SYMBOL ( pnx4008_get_fb_addresses ) ;
int pnx4008_alloc_dum_channel ( int dev_id )
{
int i = 0 ;
while ( ( i < MAX_DUM_CHANNELS ) & & ( dum_data . fb_owning_channel [ i ] ! = - 1 ) )
i + + ;
if ( i = = MAX_DUM_CHANNELS )
return - ENORESOURCESLEFT ;
else {
dum_data . fb_owning_channel [ i ] = dev_id ;
return i ;
}
}
EXPORT_SYMBOL ( pnx4008_alloc_dum_channel ) ;
int pnx4008_free_dum_channel ( int channr , int dev_id )
{
if ( channr < 0 | | channr > MAX_DUM_CHANNELS )
return - EINVAL ;
else if ( dum_data . fb_owning_channel [ channr ] ! = dev_id )
return - EFBNOTOWNER ;
else {
clear_channel ( channr ) ;
dum_data . fb_owning_channel [ channr ] = - 1 ;
}
return 0 ;
}
EXPORT_SYMBOL ( pnx4008_free_dum_channel ) ;
int pnx4008_put_dum_channel_uf ( struct dumchannel_uf chan_uf , int dev_id )
{
int i = chan_uf . channelnr ;
int ret ;
if ( i < 0 | | i > MAX_DUM_CHANNELS )
return - EINVAL ;
else if ( dum_data . fb_owning_channel [ i ] ! = dev_id )
return - EFBNOTOWNER ;
else if ( ( ret =
display_open ( chan_uf . channelnr , 0 , chan_uf . dirty ,
chan_uf . source , chan_uf . y_offset ,
chan_uf . x_offset , chan_uf . height ,
chan_uf . width ) ) ! = 0 )
return ret ;
else {
dum_data . chan_uf_store [ i ] . dirty = chan_uf . dirty ;
dum_data . chan_uf_store [ i ] . source = chan_uf . source ;
dum_data . chan_uf_store [ i ] . x_offset = chan_uf . x_offset ;
dum_data . chan_uf_store [ i ] . y_offset = chan_uf . y_offset ;
dum_data . chan_uf_store [ i ] . width = chan_uf . width ;
dum_data . chan_uf_store [ i ] . height = chan_uf . height ;
}
return 0 ;
}
EXPORT_SYMBOL ( pnx4008_put_dum_channel_uf ) ;
int pnx4008_set_dum_channel_sync ( int channr , int val , int dev_id )
{
if ( channr < 0 | | channr > MAX_DUM_CHANNELS )
return - EINVAL ;
else if ( dum_data . fb_owning_channel [ channr ] ! = dev_id )
return - EFBNOTOWNER ;
else {
if ( val = = CONF_SYNC_ON ) {
DUM_CH_CONF ( channr ) | = CONF_SYNCENABLE ;
DUM_CH_CONF ( channr ) | = DUM_CHANNEL_CFG_SYNC_MASK |
DUM_CHANNEL_CFG_SYNC_MASK_SET ;
} else if ( val = = CONF_SYNC_OFF )
DUM_CH_CONF ( channr ) & = ~ CONF_SYNCENABLE ;
else
return - EINVAL ;
}
return 0 ;
}
EXPORT_SYMBOL ( pnx4008_set_dum_channel_sync ) ;
int pnx4008_set_dum_channel_dirty_detect ( int channr , int val , int dev_id )
{
if ( channr < 0 | | channr > MAX_DUM_CHANNELS )
return - EINVAL ;
else if ( dum_data . fb_owning_channel [ channr ] ! = dev_id )
return - EFBNOTOWNER ;
else {
if ( val = = CONF_DIRTYDETECTION_ON )
DUM_CH_CONF ( channr ) | = CONF_DIRTYENABLE ;
else if ( val = = CONF_DIRTYDETECTION_OFF )
DUM_CH_CONF ( channr ) & = ~ CONF_DIRTYENABLE ;
else
return - EINVAL ;
}
return 0 ;
}
EXPORT_SYMBOL ( pnx4008_set_dum_channel_dirty_detect ) ;
#if 0 /* Functions not used currently, but likely to be used in future */
static int get_channel ( struct dumchannel * p_chan )
{
int i = p_chan - > channelnr ;
if ( i < 0 | | i > MAX_DUM_CHANNELS )
return - EINVAL ;
else {
p_chan - > dum_ch_min = DUM_CH_MIN ( i ) ;
p_chan - > dum_ch_max = DUM_CH_MAX ( i ) ;
p_chan - > dum_ch_conf = DUM_CH_CONF ( i ) ;
p_chan - > dum_ch_stat = DUM_CH_STAT ( i ) ;
p_chan - > dum_ch_ctrl = 0 ; /* WriteOnly control register */
}
return 0 ;
}
int pnx4008_get_dum_channel_uf ( struct dumchannel_uf * p_chan_uf , int dev_id )
{
int i = p_chan_uf - > channelnr ;
if ( i < 0 | | i > MAX_DUM_CHANNELS )
return - EINVAL ;
else if ( dum_data . fb_owning_channel [ i ] ! = dev_id )
return - EFBNOTOWNER ;
else {
p_chan_uf - > dirty = dum_data . chan_uf_store [ i ] . dirty ;
p_chan_uf - > source = dum_data . chan_uf_store [ i ] . source ;
p_chan_uf - > x_offset = dum_data . chan_uf_store [ i ] . x_offset ;
p_chan_uf - > y_offset = dum_data . chan_uf_store [ i ] . y_offset ;
p_chan_uf - > width = dum_data . chan_uf_store [ i ] . width ;
p_chan_uf - > height = dum_data . chan_uf_store [ i ] . height ;
}
return 0 ;
}
EXPORT_SYMBOL ( pnx4008_get_dum_channel_uf ) ;
int pnx4008_get_dum_channel_config ( int channr , int dev_id )
{
int ret ;
struct dumchannel chan ;
if ( channr < 0 | | channr > MAX_DUM_CHANNELS )
return - EINVAL ;
else if ( dum_data . fb_owning_channel [ channr ] ! = dev_id )
return - EFBNOTOWNER ;
else {
chan . channelnr = channr ;
if ( ( ret = get_channel ( & chan ) ) ! = 0 )
return ret ;
}
return ( chan . dum_ch_conf & DUM_CHANNEL_CFG_MASK ) ;
}
EXPORT_SYMBOL ( pnx4008_get_dum_channel_config ) ;
int pnx4008_force_update_dum_channel ( int channr , int dev_id )
{
if ( channr < 0 | | channr > MAX_DUM_CHANNELS )
return - EINVAL ;
else if ( dum_data . fb_owning_channel [ channr ] ! = dev_id )
return - EFBNOTOWNER ;
else
DUM_CH_CTRL ( channr ) = CTRL_SETDIRTY ;
return 0 ;
}
EXPORT_SYMBOL ( pnx4008_force_update_dum_channel ) ;
# endif
int pnx4008_sdum_mmap ( struct fb_info * info , struct vm_area_struct * vma ,
struct device * dev )
{
unsigned long off = vma - > vm_pgoff < < PAGE_SHIFT ;
if ( off < info - > fix . smem_len ) {
vma - > vm_pgoff + = 1 ;
return dma_mmap_writecombine ( dev , vma ,
( void * ) dum_data . lcd_virt_start ,
dum_data . lcd_phys_start ,
FB_DMA_SIZE ) ;
}
return - EINVAL ;
}
EXPORT_SYMBOL ( pnx4008_sdum_mmap ) ;
int pnx4008_set_dum_exit_notification ( int dev_id )
{
int i ;
for ( i = 0 ; i < MAX_DUM_CHANNELS ; i + + )
if ( dum_data . fb_owning_channel [ i ] = = dev_id )
return - ERESOURCESNOTFREED ;
return 0 ;
}
EXPORT_SYMBOL ( pnx4008_set_dum_exit_notification ) ;
/* Platform device driver for DUM */
static int sdum_suspend ( struct platform_device * pdev , pm_message_t state )
{
int retval = 0 ;
struct clk * clk ;
clk = clk_get ( 0 , " dum_ck " ) ;
if ( ! IS_ERR ( clk ) ) {
clk_set_rate ( clk , 0 ) ;
clk_put ( clk ) ;
} else
retval = PTR_ERR ( clk ) ;
/* disable BAC */
DUM_CTRL = V_BAC_DISABLE_IDLE ;
/* LCD standby & turn off display */
lcd_reset ( ) ;
return retval ;
}
static int sdum_resume ( struct platform_device * pdev )
{
int retval = 0 ;
struct clk * clk ;
clk = clk_get ( 0 , " dum_ck " ) ;
if ( ! IS_ERR ( clk ) ) {
clk_set_rate ( clk , 1 ) ;
clk_put ( clk ) ;
} else
retval = PTR_ERR ( clk ) ;
/* wait for BAC disable */
DUM_CTRL = V_BAC_DISABLE_TRIG ;
while ( DUM_CTRL & BAC_ENABLED )
udelay ( 10 ) ;
/* re-init LCD */
lcd_init ( ) ;
/* enable BAC and reset MUX */
DUM_CTRL = V_BAC_ENABLE ;
udelay ( 1 ) ;
DUM_CTRL = V_MUX_RESET ;
return 0 ;
}
static int __devinit sdum_probe ( struct platform_device * pdev )
{
int ret = 0 , i = 0 ;
/* map frame buffer */
dum_data . lcd_virt_start = ( u32 ) dma_alloc_writecombine ( & pdev - > dev ,
FB_DMA_SIZE ,
& dum_data . lcd_phys_start ,
GFP_KERNEL ) ;
if ( ! dum_data . lcd_virt_start ) {
ret = - ENOMEM ;
goto out_3 ;
}
/* map slave registers */
dum_data . slave_phys_base = PNX4008_DUM_SLAVE_BASE ;
dum_data . slave_virt_base =
( u32 * ) ioremap_nocache ( dum_data . slave_phys_base , sizeof ( u32 ) ) ;
if ( dum_data . slave_virt_base = = NULL ) {
ret = - ENOMEM ;
goto out_2 ;
}
/* initialize DUM and LCD display */
ret = dum_init ( pdev ) ;
if ( ret )
goto out_1 ;
dum_chan_init ( ) ;
lcd_init ( ) ;
DUM_CTRL = V_BAC_ENABLE ;
udelay ( 1 ) ;
DUM_CTRL = V_MUX_RESET ;
/* set decode address and sync clock divider */
DUM_DECODE = dum_data . lcd_phys_start & DUM_DECODE_MASK ;
DUM_CLK_DIV = PNX4008_DUM_CLK_DIV ;
for ( i = 0 ; i < MAX_DUM_CHANNELS ; i + + )
dum_data . fb_owning_channel [ i ] = - 1 ;
/*setup wakeup interrupt */
start_int_set_rising_edge ( SE_DISP_SYNC_INT ) ;
start_int_ack ( SE_DISP_SYNC_INT ) ;
start_int_umask ( SE_DISP_SYNC_INT ) ;
return 0 ;
out_1 :
iounmap ( ( void * ) dum_data . slave_virt_base ) ;
out_2 :
dma_free_writecombine ( & pdev - > dev , FB_DMA_SIZE ,
( void * ) dum_data . lcd_virt_start ,
dum_data . lcd_phys_start ) ;
out_3 :
return ret ;
}
static int sdum_remove ( struct platform_device * pdev )
{
struct clk * clk ;
start_int_mask ( SE_DISP_SYNC_INT ) ;
clk = clk_get ( 0 , " dum_ck " ) ;
if ( ! IS_ERR ( clk ) ) {
clk_set_rate ( clk , 0 ) ;
clk_put ( clk ) ;
}
iounmap ( ( void * ) dum_data . slave_virt_base ) ;
dma_free_writecombine ( & pdev - > dev , FB_DMA_SIZE ,
( void * ) dum_data . lcd_virt_start ,
dum_data . lcd_phys_start ) ;
return 0 ;
}
static struct platform_driver sdum_driver = {
. driver = {
2006-11-16 01:19:11 -08:00
. name = " pnx4008-sdum " ,
2006-07-03 00:24:19 -07:00
} ,
. probe = sdum_probe ,
. remove = sdum_remove ,
. suspend = sdum_suspend ,
. resume = sdum_resume ,
} ;
int __init sdum_init ( void )
{
return platform_driver_register ( & sdum_driver ) ;
}
static void __exit sdum_exit ( void )
{
platform_driver_unregister ( & sdum_driver ) ;
} ;
module_init ( sdum_init ) ;
module_exit ( sdum_exit ) ;
MODULE_LICENSE ( " GPL " ) ;