2009-11-12 11:41:42 +02:00
/*
* linux / drivers / video / omap2 / dss / dispc . c
*
* Copyright ( C ) 2009 Nokia Corporation
* Author : Tomi Valkeinen < tomi . valkeinen @ nokia . com >
*
* Some code and ideas taken from drivers / video / omap / driver
* by Imre Deak .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation .
*
* 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 , see < http : //www.gnu.org/licenses/>.
*/
# define DSS_SUBSYS_NAME "DISPC"
# include <linux/kernel.h>
# include <linux/dma-mapping.h>
# include <linux/vmalloc.h>
2011-07-10 13:20:26 -04:00
# include <linux/export.h>
2009-11-12 11:41:42 +02:00
# include <linux/clk.h>
# include <linux/io.h>
# include <linux/jiffies.h>
# include <linux/seq_file.h>
# include <linux/delay.h>
# include <linux/workqueue.h>
2010-06-09 15:31:01 +03:00
# include <linux/hardirq.h>
2011-02-23 08:41:03 +00:00
# include <linux/interrupt.h>
2011-05-23 11:51:18 +03:00
# include <linux/platform_device.h>
2011-05-27 10:52:19 +03:00
# include <linux/pm_runtime.h>
2012-09-28 13:54:35 +03:00
# include <linux/sizes.h>
2009-11-12 11:41:42 +02:00
2011-05-11 14:05:07 +03:00
# include <video/omapdss.h>
2009-11-12 11:41:42 +02:00
# include "dss.h"
2010-09-15 19:20:00 +05:30
# include "dss_features.h"
2011-05-06 11:45:49 +05:30
# include "dispc.h"
2009-11-12 11:41:42 +02:00
/* DISPC */
OMAP: DSS2: Represent DISPC register defines with channel as parameter
On OMAP4, we have a new DISPC channel for Overlay Manager LCD2. There is a set
of regsiters for LCD2 channel similar to the existing LCD channel, like
DISPC_CONTROL2, DISPC_DIVISOR2, DISPC_CONFIG2 and so on.
Introduce new enum members for LCD2 Channel and corresponding Overlay Manager
in display.h.
Represent the following DISPC register defines with channel as a parameter
to differentiate between LCD and LCD2 registers (and also DIGIT in some cases):
DISPC_DEFAULT_COLOR, DISPC_TRANS_COLOR, DISPC_TIMING_H, DISPC_TIMING_V,
DISPC_POL_FREQ, DISPC_DIVISOR, DISPC_SIZE_LCD, DISPC_DATA_CYCLEk,
DISPC_CPR_COEF_R, DISPC_CPR_COEF_G and DISPC_CPR_COEF_B
This parametrization helps in reducing the number of register defines for DISPC.
Replace the existing reads/writes to these registers in this new way.
Also, Introduce defines for registers DISPC_CONTROL2 and DISPC_CONFIG2 which
are used exclusively for LCD2 channel.
Signed-off-by: Sumit Semwal <sumit.semwal@ti.com>
Signed-off-by: Mukund Mittal <mmittal@ti.com>
Signed-off-by: Samreen <samreen@ti.com>
Signed-off-by: Archit Taneja <archit@ti.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
2010-12-02 11:27:09 +00:00
# define DISPC_SZ_REGS SZ_4K
2009-11-12 11:41:42 +02:00
# define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
DISPC_IRQ_OCP_ERR | \
DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
DISPC_IRQ_SYNC_LOST | \
DISPC_IRQ_SYNC_LOST_DIGIT )
# define DISPC_MAX_NR_ISRS 8
struct omap_dispc_isr_data {
omap_dispc_isr_t isr ;
void * arg ;
u32 mask ;
} ;
2011-06-21 09:35:36 +03:00
enum omap_burst_size {
BURST_SIZE_X2 = 0 ,
BURST_SIZE_X4 = 1 ,
BURST_SIZE_X8 = 2 ,
} ;
2009-11-12 11:41:42 +02:00
# define REG_GET(idx, start, end) \
FLD_GET ( dispc_read_reg ( idx ) , start , end )
# define REG_FLD_MOD(idx, val, start, end) \
dispc_write_reg ( idx , FLD_MOD ( dispc_read_reg ( idx ) , val , start , end ) )
2009-12-17 14:35:21 +02:00
struct dispc_irq_stats {
unsigned long last_reset ;
unsigned irq_count ;
unsigned irqs [ 32 ] ;
} ;
2012-07-03 12:26:51 +05:30
struct dispc_features {
u8 sw_start ;
u8 fp_start ;
u8 bp_start ;
u16 sw_max ;
u16 vp_max ;
u16 hp_max ;
2012-11-14 13:50:15 +05:30
u8 mgr_width_start ;
u8 mgr_height_start ;
u16 mgr_width_max ;
u16 mgr_height_max ;
2012-10-19 15:43:29 +03:00
int ( * calc_scaling ) ( unsigned long pclk , unsigned long lclk ,
2012-07-03 12:26:51 +05:30
const struct omap_video_timings * mgr_timings ,
u16 width , u16 height , u16 out_width , u16 out_height ,
enum omap_color_mode color_mode , bool * five_taps ,
int * x_predecim , int * y_predecim , int * decim_x , int * decim_y ,
2012-09-26 17:00:37 +05:30
u16 pos_x , unsigned long * core_clk , bool mem_to_mem ) ;
2012-10-19 15:36:11 +03:00
unsigned long ( * calc_core_clk ) ( unsigned long pclk ,
2012-09-26 17:00:37 +05:30
u16 width , u16 height , u16 out_width , u16 out_height ,
bool mem_to_mem ) ;
2012-08-22 16:56:57 +03:00
u8 num_fifos ;
2012-08-22 16:57:02 +03:00
/* swap GFX & WB fifos */
bool gfx_fifo_workaround : 1 ;
2012-11-08 10:01:33 +02:00
/* no DISPC_IRQ_FRAMEDONETV on this SoC */
bool no_framedone_tv : 1 ;
2012-07-03 12:26:51 +05:30
} ;
2012-08-22 16:56:57 +03:00
# define DISPC_MAX_NR_FIFOS 5
2009-11-12 11:41:42 +02:00
static struct {
2011-01-24 06:22:00 +00:00
struct platform_device * pdev ;
2009-11-12 11:41:42 +02:00
void __iomem * base ;
2011-05-27 10:52:19 +03:00
int ctx_loss_cnt ;
2011-02-23 08:41:03 +00:00
int irq ;
2011-05-27 10:52:19 +03:00
struct clk * dss_clk ;
2009-11-12 11:41:42 +02:00
2012-08-22 16:56:57 +03:00
u32 fifo_size [ DISPC_MAX_NR_FIFOS ] ;
/* maps which plane is using a fifo. fifo-id -> plane-id */
int fifo_assignment [ DISPC_MAX_NR_FIFOS ] ;
2009-11-12 11:41:42 +02:00
spinlock_t irq_lock ;
u32 irq_error_mask ;
struct omap_dispc_isr_data registered_isr [ DISPC_MAX_NR_ISRS ] ;
u32 error_irqs ;
struct work_struct error_work ;
2011-06-01 15:54:06 +03:00
bool ctx_valid ;
2009-11-12 11:41:42 +02:00
u32 ctx [ DISPC_SZ_REGS / sizeof ( u32 ) ] ;
2009-12-17 14:35:21 +02:00
2012-07-03 12:26:51 +05:30
const struct dispc_features * feat ;
2009-12-17 14:35:21 +02:00
# ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
spinlock_t irq_stats_lock ;
struct dispc_irq_stats irq_stats ;
# endif
2009-11-12 11:41:42 +02:00
} dispc ;
2011-05-19 19:47:54 +05:30
enum omap_color_component {
/* used for all color formats for OMAP3 and earlier
* and for RGB and Y color component on OMAP4
*/
DISPC_COLOR_COMPONENT_RGB_Y = 1 < < 0 ,
/* used for UV component for
* OMAP_DSS_COLOR_YUV2 , OMAP_DSS_COLOR_UYVY , OMAP_DSS_COLOR_NV12
* color formats on OMAP4
*/
DISPC_COLOR_COMPONENT_UV = 1 < < 1 ,
} ;
2012-06-21 11:07:44 +05:30
enum mgr_reg_fields {
DISPC_MGR_FLD_ENABLE ,
DISPC_MGR_FLD_STNTFT ,
DISPC_MGR_FLD_GO ,
DISPC_MGR_FLD_TFTDATALINES ,
DISPC_MGR_FLD_STALLMODE ,
DISPC_MGR_FLD_TCKENABLE ,
DISPC_MGR_FLD_TCKSELECTION ,
DISPC_MGR_FLD_CPR ,
DISPC_MGR_FLD_FIFOHANDCHECK ,
/* used to maintain a count of the above fields */
DISPC_MGR_FLD_NUM ,
} ;
static const struct {
const char * name ;
u32 vsync_irq ;
u32 framedone_irq ;
u32 sync_lost_irq ;
struct reg_field reg_desc [ DISPC_MGR_FLD_NUM ] ;
} mgr_desc [ ] = {
[ OMAP_DSS_CHANNEL_LCD ] = {
. name = " LCD " ,
. vsync_irq = DISPC_IRQ_VSYNC ,
. framedone_irq = DISPC_IRQ_FRAMEDONE ,
. sync_lost_irq = DISPC_IRQ_SYNC_LOST ,
. reg_desc = {
[ DISPC_MGR_FLD_ENABLE ] = { DISPC_CONTROL , 0 , 0 } ,
[ DISPC_MGR_FLD_STNTFT ] = { DISPC_CONTROL , 3 , 3 } ,
[ DISPC_MGR_FLD_GO ] = { DISPC_CONTROL , 5 , 5 } ,
[ DISPC_MGR_FLD_TFTDATALINES ] = { DISPC_CONTROL , 9 , 8 } ,
[ DISPC_MGR_FLD_STALLMODE ] = { DISPC_CONTROL , 11 , 11 } ,
[ DISPC_MGR_FLD_TCKENABLE ] = { DISPC_CONFIG , 10 , 10 } ,
[ DISPC_MGR_FLD_TCKSELECTION ] = { DISPC_CONFIG , 11 , 11 } ,
[ DISPC_MGR_FLD_CPR ] = { DISPC_CONFIG , 15 , 15 } ,
[ DISPC_MGR_FLD_FIFOHANDCHECK ] = { DISPC_CONFIG , 16 , 16 } ,
} ,
} ,
[ OMAP_DSS_CHANNEL_DIGIT ] = {
. name = " DIGIT " ,
. vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN ,
2012-11-08 10:01:33 +02:00
. framedone_irq = DISPC_IRQ_FRAMEDONETV ,
2012-06-21 11:07:44 +05:30
. sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT ,
. reg_desc = {
[ DISPC_MGR_FLD_ENABLE ] = { DISPC_CONTROL , 1 , 1 } ,
[ DISPC_MGR_FLD_STNTFT ] = { } ,
[ DISPC_MGR_FLD_GO ] = { DISPC_CONTROL , 6 , 6 } ,
[ DISPC_MGR_FLD_TFTDATALINES ] = { } ,
[ DISPC_MGR_FLD_STALLMODE ] = { } ,
[ DISPC_MGR_FLD_TCKENABLE ] = { DISPC_CONFIG , 12 , 12 } ,
[ DISPC_MGR_FLD_TCKSELECTION ] = { DISPC_CONFIG , 13 , 13 } ,
[ DISPC_MGR_FLD_CPR ] = { } ,
[ DISPC_MGR_FLD_FIFOHANDCHECK ] = { DISPC_CONFIG , 16 , 16 } ,
} ,
} ,
[ OMAP_DSS_CHANNEL_LCD2 ] = {
. name = " LCD2 " ,
. vsync_irq = DISPC_IRQ_VSYNC2 ,
. framedone_irq = DISPC_IRQ_FRAMEDONE2 ,
. sync_lost_irq = DISPC_IRQ_SYNC_LOST2 ,
. reg_desc = {
[ DISPC_MGR_FLD_ENABLE ] = { DISPC_CONTROL2 , 0 , 0 } ,
[ DISPC_MGR_FLD_STNTFT ] = { DISPC_CONTROL2 , 3 , 3 } ,
[ DISPC_MGR_FLD_GO ] = { DISPC_CONTROL2 , 5 , 5 } ,
[ DISPC_MGR_FLD_TFTDATALINES ] = { DISPC_CONTROL2 , 9 , 8 } ,
[ DISPC_MGR_FLD_STALLMODE ] = { DISPC_CONTROL2 , 11 , 11 } ,
[ DISPC_MGR_FLD_TCKENABLE ] = { DISPC_CONFIG2 , 10 , 10 } ,
[ DISPC_MGR_FLD_TCKSELECTION ] = { DISPC_CONFIG2 , 11 , 11 } ,
[ DISPC_MGR_FLD_CPR ] = { DISPC_CONFIG2 , 15 , 15 } ,
[ DISPC_MGR_FLD_FIFOHANDCHECK ] = { DISPC_CONFIG2 , 16 , 16 } ,
} ,
} ,
2012-06-29 10:43:13 +05:30
[ OMAP_DSS_CHANNEL_LCD3 ] = {
. name = " LCD3 " ,
. vsync_irq = DISPC_IRQ_VSYNC3 ,
. framedone_irq = DISPC_IRQ_FRAMEDONE3 ,
. sync_lost_irq = DISPC_IRQ_SYNC_LOST3 ,
. reg_desc = {
[ DISPC_MGR_FLD_ENABLE ] = { DISPC_CONTROL3 , 0 , 0 } ,
[ DISPC_MGR_FLD_STNTFT ] = { DISPC_CONTROL3 , 3 , 3 } ,
[ DISPC_MGR_FLD_GO ] = { DISPC_CONTROL3 , 5 , 5 } ,
[ DISPC_MGR_FLD_TFTDATALINES ] = { DISPC_CONTROL3 , 9 , 8 } ,
[ DISPC_MGR_FLD_STALLMODE ] = { DISPC_CONTROL3 , 11 , 11 } ,
[ DISPC_MGR_FLD_TCKENABLE ] = { DISPC_CONFIG3 , 10 , 10 } ,
[ DISPC_MGR_FLD_TCKSELECTION ] = { DISPC_CONFIG3 , 11 , 11 } ,
[ DISPC_MGR_FLD_CPR ] = { DISPC_CONFIG3 , 15 , 15 } ,
[ DISPC_MGR_FLD_FIFOHANDCHECK ] = { DISPC_CONFIG3 , 16 , 16 } ,
} ,
} ,
2012-06-21 11:07:44 +05:30
} ;
2012-09-11 12:04:47 +05:30
struct color_conv_coef {
int ry , rcr , rcb , gy , gcr , gcb , by , bcr , bcb ;
int full_range ;
} ;
2009-11-12 11:41:42 +02:00
static void _omap_dispc_set_irqs ( void ) ;
2012-09-26 16:58:52 +05:30
static unsigned long dispc_plane_pclk_rate ( enum omap_plane plane ) ;
static unsigned long dispc_plane_lclk_rate ( enum omap_plane plane ) ;
2009-11-12 11:41:42 +02:00
2011-05-06 11:45:51 +05:30
static inline void dispc_write_reg ( const u16 idx , u32 val )
2009-11-12 11:41:42 +02:00
{
2011-05-06 11:45:51 +05:30
__raw_writel ( val , dispc . base + idx ) ;
2009-11-12 11:41:42 +02:00
}
2011-05-06 11:45:51 +05:30
static inline u32 dispc_read_reg ( const u16 idx )
2009-11-12 11:41:42 +02:00
{
2011-05-06 11:45:51 +05:30
return __raw_readl ( dispc . base + idx ) ;
2009-11-12 11:41:42 +02:00
}
2012-06-21 11:07:44 +05:30
static u32 mgr_fld_read ( enum omap_channel channel , enum mgr_reg_fields regfld )
{
const struct reg_field rfld = mgr_desc [ channel ] . reg_desc [ regfld ] ;
return REG_GET ( rfld . reg , rfld . high , rfld . low ) ;
}
static void mgr_fld_write ( enum omap_channel channel ,
enum mgr_reg_fields regfld , int val ) {
const struct reg_field rfld = mgr_desc [ channel ] . reg_desc [ regfld ] ;
REG_FLD_MOD ( rfld . reg , val , rfld . high , rfld . low ) ;
}
2009-11-12 11:41:42 +02:00
# define SR(reg) \
2011-05-06 11:45:51 +05:30
dispc . ctx [ DISPC_ # # reg / sizeof ( u32 ) ] = dispc_read_reg ( DISPC_ # # reg )
2009-11-12 11:41:42 +02:00
# define RR(reg) \
2011-05-06 11:45:51 +05:30
dispc_write_reg ( DISPC_ # # reg , dispc . ctx [ DISPC_ # # reg / sizeof ( u32 ) ] )
2009-11-12 11:41:42 +02:00
2011-05-27 10:52:19 +03:00
static void dispc_save_context ( void )
2009-11-12 11:41:42 +02:00
{
2011-08-05 19:06:02 +05:30
int i , j ;
2009-11-12 11:41:42 +02:00
2011-05-27 10:52:19 +03:00
DSSDBG ( " dispc_save_context \n " ) ;
2009-11-12 11:41:42 +02:00
SR ( IRQENABLE ) ;
SR ( CONTROL ) ;
SR ( CONFIG ) ;
SR ( LINE_NUMBER ) ;
2011-09-26 11:47:29 +05:30
if ( dss_has_feature ( FEAT_ALPHA_FIXED_ZORDER ) | |
dss_has_feature ( FEAT_ALPHA_FREE_ZORDER ) )
2011-05-27 14:22:16 +03:00
SR ( GLOBAL_ALPHA ) ;
2010-12-02 11:27:12 +00:00
if ( dss_has_feature ( FEAT_MGR_LCD2 ) ) {
SR ( CONTROL2 ) ;
SR ( CONFIG2 ) ;
}
2012-06-29 10:43:13 +05:30
if ( dss_has_feature ( FEAT_MGR_LCD3 ) ) {
SR ( CONTROL3 ) ;
SR ( CONFIG3 ) ;
}
2009-11-12 11:41:42 +02:00
2011-08-05 19:06:02 +05:30
for ( i = 0 ; i < dss_feat_get_num_mgrs ( ) ; i + + ) {
SR ( DEFAULT_COLOR ( i ) ) ;
SR ( TRANS_COLOR ( i ) ) ;
SR ( SIZE_MGR ( i ) ) ;
if ( i = = OMAP_DSS_CHANNEL_DIGIT )
continue ;
SR ( TIMING_H ( i ) ) ;
SR ( TIMING_V ( i ) ) ;
SR ( POL_FREQ ( i ) ) ;
SR ( DIVISORo ( i ) ) ;
SR ( DATA_CYCLE1 ( i ) ) ;
SR ( DATA_CYCLE2 ( i ) ) ;
SR ( DATA_CYCLE3 ( i ) ) ;
2011-05-27 14:22:16 +03:00
if ( dss_has_feature ( FEAT_CPR ) ) {
2011-08-05 19:06:02 +05:30
SR ( CPR_COEF_R ( i ) ) ;
SR ( CPR_COEF_G ( i ) ) ;
SR ( CPR_COEF_B ( i ) ) ;
2011-05-27 14:22:16 +03:00
}
2010-12-02 11:27:12 +00:00
}
2009-11-12 11:41:42 +02:00
2011-08-05 19:06:02 +05:30
for ( i = 0 ; i < dss_feat_get_num_ovls ( ) ; i + + ) {
SR ( OVL_BA0 ( i ) ) ;
SR ( OVL_BA1 ( i ) ) ;
SR ( OVL_POSITION ( i ) ) ;
SR ( OVL_SIZE ( i ) ) ;
SR ( OVL_ATTRIBUTES ( i ) ) ;
SR ( OVL_FIFO_THRESHOLD ( i ) ) ;
SR ( OVL_ROW_INC ( i ) ) ;
SR ( OVL_PIXEL_INC ( i ) ) ;
if ( dss_has_feature ( FEAT_PRELOAD ) )
SR ( OVL_PRELOAD ( i ) ) ;
if ( i = = OMAP_DSS_GFX ) {
SR ( OVL_WINDOW_SKIP ( i ) ) ;
SR ( OVL_TABLE_BA ( i ) ) ;
continue ;
}
SR ( OVL_FIR ( i ) ) ;
SR ( OVL_PICTURE_SIZE ( i ) ) ;
SR ( OVL_ACCU0 ( i ) ) ;
SR ( OVL_ACCU1 ( i ) ) ;
2011-05-06 11:45:49 +05:30
2011-08-05 19:06:02 +05:30
for ( j = 0 ; j < 8 ; j + + )
SR ( OVL_FIR_COEF_H ( i , j ) ) ;
2011-05-19 19:47:53 +05:30
2011-08-05 19:06:02 +05:30
for ( j = 0 ; j < 8 ; j + + )
SR ( OVL_FIR_COEF_HV ( i , j ) ) ;
2011-05-19 19:47:53 +05:30
2011-08-05 19:06:02 +05:30
for ( j = 0 ; j < 5 ; j + + )
SR ( OVL_CONV_COEF ( i , j ) ) ;
2011-05-19 19:47:53 +05:30
2011-08-05 19:06:02 +05:30
if ( dss_has_feature ( FEAT_FIR_COEF_V ) ) {
for ( j = 0 ; j < 8 ; j + + )
SR ( OVL_FIR_COEF_V ( i , j ) ) ;
}
2011-05-06 11:45:49 +05:30
2011-08-05 19:06:02 +05:30
if ( dss_has_feature ( FEAT_HANDLE_UV_SEPARATE ) ) {
SR ( OVL_BA0_UV ( i ) ) ;
SR ( OVL_BA1_UV ( i ) ) ;
SR ( OVL_FIR2 ( i ) ) ;
SR ( OVL_ACCU2_0 ( i ) ) ;
SR ( OVL_ACCU2_1 ( i ) ) ;
2011-05-19 19:47:53 +05:30
2011-08-05 19:06:02 +05:30
for ( j = 0 ; j < 8 ; j + + )
SR ( OVL_FIR_COEF_H2 ( i , j ) ) ;
2011-05-19 19:47:53 +05:30
2011-08-05 19:06:02 +05:30
for ( j = 0 ; j < 8 ; j + + )
SR ( OVL_FIR_COEF_HV2 ( i , j ) ) ;
2011-05-19 19:47:53 +05:30
2011-08-05 19:06:02 +05:30
for ( j = 0 ; j < 8 ; j + + )
SR ( OVL_FIR_COEF_V2 ( i , j ) ) ;
}
if ( dss_has_feature ( FEAT_ATTR2 ) )
SR ( OVL_ATTRIBUTES2 ( i ) ) ;
2011-05-19 19:47:53 +05:30
}
2011-03-03 09:28:00 -06:00
if ( dss_has_feature ( FEAT_CORE_CLK_DIV ) )
SR ( DIVISOR ) ;
2011-06-01 15:54:06 +03:00
2012-02-20 11:50:06 +02:00
dispc . ctx_loss_cnt = dss_get_ctx_loss_count ( & dispc . pdev - > dev ) ;
2011-06-01 15:54:06 +03:00
dispc . ctx_valid = true ;
DSSDBG ( " context saved, ctx_loss_count %d \n " , dispc . ctx_loss_cnt ) ;
2009-11-12 11:41:42 +02:00
}
2011-05-27 10:52:19 +03:00
static void dispc_restore_context ( void )
2009-11-12 11:41:42 +02:00
{
2011-08-05 19:06:02 +05:30
int i , j , ctx ;
2011-05-27 10:52:19 +03:00
DSSDBG ( " dispc_restore_context \n " ) ;
2011-06-01 15:54:06 +03:00
if ( ! dispc . ctx_valid )
return ;
2012-02-20 11:50:06 +02:00
ctx = dss_get_ctx_loss_count ( & dispc . pdev - > dev ) ;
2011-06-01 15:54:06 +03:00
if ( ctx > = 0 & & ctx = = dispc . ctx_loss_cnt )
return ;
DSSDBG ( " ctx_loss_count: saved %d, current %d \n " ,
dispc . ctx_loss_cnt , ctx ) ;
2010-03-05 01:13:11 +02:00
/*RR(IRQENABLE);*/
2009-11-12 11:41:42 +02:00
/*RR(CONTROL);*/
RR ( CONFIG ) ;
RR ( LINE_NUMBER ) ;
2011-09-26 11:47:29 +05:30
if ( dss_has_feature ( FEAT_ALPHA_FIXED_ZORDER ) | |
dss_has_feature ( FEAT_ALPHA_FREE_ZORDER ) )
2011-05-27 14:22:16 +03:00
RR ( GLOBAL_ALPHA ) ;
2011-08-05 19:06:02 +05:30
if ( dss_has_feature ( FEAT_MGR_LCD2 ) )
2010-12-02 11:27:12 +00:00
RR ( CONFIG2 ) ;
2012-06-29 10:43:13 +05:30
if ( dss_has_feature ( FEAT_MGR_LCD3 ) )
RR ( CONFIG3 ) ;
2009-11-12 11:41:42 +02:00
2011-08-05 19:06:02 +05:30
for ( i = 0 ; i < dss_feat_get_num_mgrs ( ) ; i + + ) {
RR ( DEFAULT_COLOR ( i ) ) ;
RR ( TRANS_COLOR ( i ) ) ;
RR ( SIZE_MGR ( i ) ) ;
if ( i = = OMAP_DSS_CHANNEL_DIGIT )
continue ;
RR ( TIMING_H ( i ) ) ;
RR ( TIMING_V ( i ) ) ;
RR ( POL_FREQ ( i ) ) ;
RR ( DIVISORo ( i ) ) ;
RR ( DATA_CYCLE1 ( i ) ) ;
RR ( DATA_CYCLE2 ( i ) ) ;
RR ( DATA_CYCLE3 ( i ) ) ;
2010-12-02 11:27:12 +00:00
2011-05-27 14:22:16 +03:00
if ( dss_has_feature ( FEAT_CPR ) ) {
2011-08-05 19:06:02 +05:30
RR ( CPR_COEF_R ( i ) ) ;
RR ( CPR_COEF_G ( i ) ) ;
RR ( CPR_COEF_B ( i ) ) ;
2011-05-27 14:22:16 +03:00
}
2010-12-02 11:27:12 +00:00
}
2009-11-12 11:41:42 +02:00
2011-08-05 19:06:02 +05:30
for ( i = 0 ; i < dss_feat_get_num_ovls ( ) ; i + + ) {
RR ( OVL_BA0 ( i ) ) ;
RR ( OVL_BA1 ( i ) ) ;
RR ( OVL_POSITION ( i ) ) ;
RR ( OVL_SIZE ( i ) ) ;
RR ( OVL_ATTRIBUTES ( i ) ) ;
RR ( OVL_FIFO_THRESHOLD ( i ) ) ;
RR ( OVL_ROW_INC ( i ) ) ;
RR ( OVL_PIXEL_INC ( i ) ) ;
if ( dss_has_feature ( FEAT_PRELOAD ) )
RR ( OVL_PRELOAD ( i ) ) ;
if ( i = = OMAP_DSS_GFX ) {
RR ( OVL_WINDOW_SKIP ( i ) ) ;
RR ( OVL_TABLE_BA ( i ) ) ;
continue ;
}
RR ( OVL_FIR ( i ) ) ;
RR ( OVL_PICTURE_SIZE ( i ) ) ;
RR ( OVL_ACCU0 ( i ) ) ;
RR ( OVL_ACCU1 ( i ) ) ;
2011-05-06 11:45:49 +05:30
2011-08-05 19:06:02 +05:30
for ( j = 0 ; j < 8 ; j + + )
RR ( OVL_FIR_COEF_H ( i , j ) ) ;
2011-05-19 19:47:53 +05:30
2011-08-05 19:06:02 +05:30
for ( j = 0 ; j < 8 ; j + + )
RR ( OVL_FIR_COEF_HV ( i , j ) ) ;
2011-05-19 19:47:53 +05:30
2011-08-05 19:06:02 +05:30
for ( j = 0 ; j < 5 ; j + + )
RR ( OVL_CONV_COEF ( i , j ) ) ;
2011-05-19 19:47:53 +05:30
2011-08-05 19:06:02 +05:30
if ( dss_has_feature ( FEAT_FIR_COEF_V ) ) {
for ( j = 0 ; j < 8 ; j + + )
RR ( OVL_FIR_COEF_V ( i , j ) ) ;
}
2011-05-06 11:45:49 +05:30
2011-08-05 19:06:02 +05:30
if ( dss_has_feature ( FEAT_HANDLE_UV_SEPARATE ) ) {
RR ( OVL_BA0_UV ( i ) ) ;
RR ( OVL_BA1_UV ( i ) ) ;
RR ( OVL_FIR2 ( i ) ) ;
RR ( OVL_ACCU2_0 ( i ) ) ;
RR ( OVL_ACCU2_1 ( i ) ) ;
2011-05-19 19:47:53 +05:30
2011-08-05 19:06:02 +05:30
for ( j = 0 ; j < 8 ; j + + )
RR ( OVL_FIR_COEF_H2 ( i , j ) ) ;
2011-05-19 19:47:53 +05:30
2011-08-05 19:06:02 +05:30
for ( j = 0 ; j < 8 ; j + + )
RR ( OVL_FIR_COEF_HV2 ( i , j ) ) ;
2011-05-19 19:47:53 +05:30
2011-08-05 19:06:02 +05:30
for ( j = 0 ; j < 8 ; j + + )
RR ( OVL_FIR_COEF_V2 ( i , j ) ) ;
}
if ( dss_has_feature ( FEAT_ATTR2 ) )
RR ( OVL_ATTRIBUTES2 ( i ) ) ;
2011-05-19 19:47:53 +05:30
}
2009-11-12 11:41:42 +02:00
2011-03-03 09:28:00 -06:00
if ( dss_has_feature ( FEAT_CORE_CLK_DIV ) )
RR ( DIVISOR ) ;
2009-11-12 11:41:42 +02:00
/* enable last, because LCD & DIGIT enable are here */
RR ( CONTROL ) ;
2010-12-02 11:27:12 +00:00
if ( dss_has_feature ( FEAT_MGR_LCD2 ) )
RR ( CONTROL2 ) ;
2012-06-29 10:43:13 +05:30
if ( dss_has_feature ( FEAT_MGR_LCD3 ) )
RR ( CONTROL3 ) ;
2010-03-05 01:13:11 +02:00
/* clear spurious SYNC_LOST_DIGIT interrupts */
2012-10-10 15:13:14 +03:00
dispc_clear_irqstatus ( DISPC_IRQ_SYNC_LOST_DIGIT ) ;
2010-03-05 01:13:11 +02:00
/*
* enable last so IRQs won ' t trigger before
* the context is fully restored
*/
RR ( IRQENABLE ) ;
2011-06-01 15:54:06 +03:00
DSSDBG ( " context restored \n " ) ;
2009-11-12 11:41:42 +02:00
}
# undef SR
# undef RR
2011-05-27 10:52:19 +03:00
int dispc_runtime_get ( void )
{
int r ;
DSSDBG ( " dispc_runtime_get \n " ) ;
r = pm_runtime_get_sync ( & dispc . pdev - > dev ) ;
WARN_ON ( r < 0 ) ;
return r < 0 ? r : 0 ;
}
void dispc_runtime_put ( void )
{
int r ;
DSSDBG ( " dispc_runtime_put \n " ) ;
2012-01-23 13:23:08 +02:00
r = pm_runtime_put_sync ( & dispc . pdev - > dev ) ;
2012-06-27 16:37:18 +03:00
WARN_ON ( r < 0 & & r ! = - ENOSYS ) ;
2009-11-12 11:41:42 +02:00
}
2011-11-07 15:50:09 +02:00
u32 dispc_mgr_get_vsync_irq ( enum omap_channel channel )
{
2012-06-21 11:07:44 +05:30
return mgr_desc [ channel ] . vsync_irq ;
2011-11-07 15:50:09 +02:00
}
2011-11-18 15:39:52 +02:00
u32 dispc_mgr_get_framedone_irq ( enum omap_channel channel )
{
2012-11-08 10:01:33 +02:00
if ( channel = = OMAP_DSS_CHANNEL_DIGIT & & dispc . feat - > no_framedone_tv )
return 0 ;
2012-06-21 11:07:44 +05:30
return mgr_desc [ channel ] . framedone_irq ;
2011-11-18 15:39:52 +02:00
}
2012-10-17 10:38:52 +03:00
u32 dispc_mgr_get_sync_lost_irq ( enum omap_channel channel )
{
return mgr_desc [ channel ] . sync_lost_irq ;
}
2012-09-22 12:39:33 +05:30
u32 dispc_wb_get_framedone_irq ( void )
{
return DISPC_IRQ_FRAMEDONEWB ;
}
2011-08-16 13:45:15 +03:00
bool dispc_mgr_go_busy ( enum omap_channel channel )
2009-11-12 11:41:42 +02:00
{
2012-06-21 11:07:44 +05:30
return mgr_fld_read ( channel , DISPC_MGR_FLD_GO ) = = 1 ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:45:15 +03:00
void dispc_mgr_go ( enum omap_channel channel )
2009-11-12 11:41:42 +02:00
{
2012-10-19 15:06:07 +03:00
WARN_ON ( dispc_mgr_is_enabled ( channel ) = = false ) ;
WARN_ON ( dispc_mgr_go_busy ( channel ) ) ;
2009-11-12 11:41:42 +02:00
2012-06-21 11:07:44 +05:30
DSSDBG ( " GO %s \n " , mgr_desc [ channel ] . name ) ;
2009-11-12 11:41:42 +02:00
2012-06-21 11:07:44 +05:30
mgr_fld_write ( channel , DISPC_MGR_FLD_GO , 1 ) ;
2009-11-12 11:41:42 +02:00
}
2012-09-22 12:39:33 +05:30
bool dispc_wb_go_busy ( void )
{
return REG_GET ( DISPC_CONTROL2 , 6 , 6 ) = = 1 ;
}
void dispc_wb_go ( void )
{
enum omap_plane plane = OMAP_DSS_WB ;
bool enable , go ;
enable = REG_GET ( DISPC_OVL_ATTRIBUTES ( plane ) , 0 , 0 ) = = 1 ;
if ( ! enable )
return ;
go = REG_GET ( DISPC_CONTROL2 , 6 , 6 ) = = 1 ;
if ( go ) {
DSSERR ( " GO bit not down for WB \n " ) ;
return ;
}
REG_FLD_MOD ( DISPC_CONTROL2 , 1 , 6 , 6 ) ;
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_write_firh_reg ( enum omap_plane plane , int reg , u32 value )
2009-11-12 11:41:42 +02:00
{
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_FIR_COEF_H ( plane , reg ) , value ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_write_firhv_reg ( enum omap_plane plane , int reg , u32 value )
2009-11-12 11:41:42 +02:00
{
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_FIR_COEF_HV ( plane , reg ) , value ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_write_firv_reg ( enum omap_plane plane , int reg , u32 value )
2009-11-12 11:41:42 +02:00
{
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_FIR_COEF_V ( plane , reg ) , value ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_write_firh2_reg ( enum omap_plane plane , int reg , u32 value )
2011-05-19 19:47:53 +05:30
{
BUG_ON ( plane = = OMAP_DSS_GFX ) ;
dispc_write_reg ( DISPC_OVL_FIR_COEF_H2 ( plane , reg ) , value ) ;
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_write_firhv2_reg ( enum omap_plane plane , int reg ,
u32 value )
2011-05-19 19:47:53 +05:30
{
BUG_ON ( plane = = OMAP_DSS_GFX ) ;
dispc_write_reg ( DISPC_OVL_FIR_COEF_HV2 ( plane , reg ) , value ) ;
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_write_firv2_reg ( enum omap_plane plane , int reg , u32 value )
2011-05-19 19:47:53 +05:30
{
BUG_ON ( plane = = OMAP_DSS_GFX ) ;
dispc_write_reg ( DISPC_OVL_FIR_COEF_V2 ( plane , reg ) , value ) ;
}
2011-12-19 14:03:44 +05:30
static void dispc_ovl_set_scale_coef ( enum omap_plane plane , int fir_hinc ,
int fir_vinc , int five_taps ,
enum omap_color_component color_comp )
2009-11-12 11:41:42 +02:00
{
2011-12-19 14:03:44 +05:30
const struct dispc_coef * h_coef , * v_coef ;
2009-11-12 11:41:42 +02:00
int i ;
2011-12-19 14:03:44 +05:30
h_coef = dispc_ovl_get_scale_coef ( fir_hinc , true ) ;
v_coef = dispc_ovl_get_scale_coef ( fir_vinc , five_taps ) ;
2009-11-12 11:41:42 +02:00
for ( i = 0 ; i < 8 ; i + + ) {
u32 h , hv ;
2011-12-19 14:03:44 +05:30
h = FLD_VAL ( h_coef [ i ] . hc0_vc00 , 7 , 0 )
| FLD_VAL ( h_coef [ i ] . hc1_vc0 , 15 , 8 )
| FLD_VAL ( h_coef [ i ] . hc2_vc1 , 23 , 16 )
| FLD_VAL ( h_coef [ i ] . hc3_vc2 , 31 , 24 ) ;
hv = FLD_VAL ( h_coef [ i ] . hc4_vc22 , 7 , 0 )
| FLD_VAL ( v_coef [ i ] . hc1_vc0 , 15 , 8 )
| FLD_VAL ( v_coef [ i ] . hc2_vc1 , 23 , 16 )
| FLD_VAL ( v_coef [ i ] . hc3_vc2 , 31 , 24 ) ;
2009-11-12 11:41:42 +02:00
2011-05-19 19:47:54 +05:30
if ( color_comp = = DISPC_COLOR_COMPONENT_RGB_Y ) {
2011-08-16 13:25:00 +03:00
dispc_ovl_write_firh_reg ( plane , i , h ) ;
dispc_ovl_write_firhv_reg ( plane , i , hv ) ;
2011-05-19 19:47:54 +05:30
} else {
2011-08-16 13:25:00 +03:00
dispc_ovl_write_firh2_reg ( plane , i , h ) ;
dispc_ovl_write_firhv2_reg ( plane , i , hv ) ;
2011-05-19 19:47:54 +05:30
}
2009-11-12 11:41:42 +02:00
}
2010-08-24 15:18:43 +02:00
if ( five_taps ) {
for ( i = 0 ; i < 8 ; i + + ) {
u32 v ;
2011-12-19 14:03:44 +05:30
v = FLD_VAL ( v_coef [ i ] . hc0_vc00 , 7 , 0 )
| FLD_VAL ( v_coef [ i ] . hc4_vc22 , 15 , 8 ) ;
2011-05-19 19:47:54 +05:30
if ( color_comp = = DISPC_COLOR_COMPONENT_RGB_Y )
2011-08-16 13:25:00 +03:00
dispc_ovl_write_firv_reg ( plane , i , v ) ;
2011-05-19 19:47:54 +05:30
else
2011-08-16 13:25:00 +03:00
dispc_ovl_write_firv2_reg ( plane , i , v ) ;
2010-08-24 15:18:43 +02:00
}
2009-11-12 11:41:42 +02:00
}
}
2012-09-11 12:04:47 +05:30
static void dispc_ovl_write_color_conv_coef ( enum omap_plane plane ,
const struct color_conv_coef * ct )
{
2009-11-12 11:41:42 +02:00
# define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
2012-09-11 12:04:47 +05:30
dispc_write_reg ( DISPC_OVL_CONV_COEF ( plane , 0 ) , CVAL ( ct - > rcr , ct - > ry ) ) ;
dispc_write_reg ( DISPC_OVL_CONV_COEF ( plane , 1 ) , CVAL ( ct - > gy , ct - > rcb ) ) ;
dispc_write_reg ( DISPC_OVL_CONV_COEF ( plane , 2 ) , CVAL ( ct - > gcb , ct - > gcr ) ) ;
dispc_write_reg ( DISPC_OVL_CONV_COEF ( plane , 3 ) , CVAL ( ct - > bcr , ct - > by ) ) ;
dispc_write_reg ( DISPC_OVL_CONV_COEF ( plane , 4 ) , CVAL ( 0 , ct - > bcb ) ) ;
2009-11-12 11:41:42 +02:00
2012-09-11 12:04:47 +05:30
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( plane ) , ct - > full_range , 11 , 11 ) ;
2009-11-12 11:41:42 +02:00
# undef CVAL
}
2012-09-11 12:04:47 +05:30
static void dispc_setup_color_conv_coef ( void )
{
int i ;
int num_ovl = dss_feat_get_num_ovls ( ) ;
int num_wb = dss_feat_get_num_wbs ( ) ;
const struct color_conv_coef ctbl_bt601_5_ovl = {
298 , 409 , 0 , 298 , - 208 , - 100 , 298 , 0 , 517 , 0 ,
} ;
const struct color_conv_coef ctbl_bt601_5_wb = {
66 , 112 , - 38 , 129 , - 94 , - 74 , 25 , - 18 , 112 , 0 ,
} ;
for ( i = 1 ; i < num_ovl ; i + + )
dispc_ovl_write_color_conv_coef ( i , & ctbl_bt601_5_ovl ) ;
for ( ; i < num_wb ; i + + )
dispc_ovl_write_color_conv_coef ( i , & ctbl_bt601_5_wb ) ;
}
2009-11-12 11:41:42 +02:00
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_ba0 ( enum omap_plane plane , u32 paddr )
2009-11-12 11:41:42 +02:00
{
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_BA0 ( plane ) , paddr ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_ba1 ( enum omap_plane plane , u32 paddr )
2009-11-12 11:41:42 +02:00
{
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_BA1 ( plane ) , paddr ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_ba0_uv ( enum omap_plane plane , u32 paddr )
2011-05-19 19:47:53 +05:30
{
dispc_write_reg ( DISPC_OVL_BA0_UV ( plane ) , paddr ) ;
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_ba1_uv ( enum omap_plane plane , u32 paddr )
2011-05-19 19:47:53 +05:30
{
dispc_write_reg ( DISPC_OVL_BA1_UV ( plane ) , paddr ) ;
}
2012-09-22 12:30:17 +05:30
static void dispc_ovl_set_pos ( enum omap_plane plane ,
enum omap_overlay_caps caps , int x , int y )
2009-11-12 11:41:42 +02:00
{
2012-09-22 12:30:17 +05:30
u32 val ;
if ( ( caps & OMAP_DSS_OVL_CAP_POS ) = = 0 )
return ;
val = FLD_VAL ( y , 26 , 16 ) | FLD_VAL ( x , 10 , 0 ) ;
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_POSITION ( plane ) , val ) ;
2009-11-12 11:41:42 +02:00
}
2012-09-21 14:51:49 +05:30
static void dispc_ovl_set_input_size ( enum omap_plane plane , int width ,
int height )
2009-11-12 11:41:42 +02:00
{
u32 val = FLD_VAL ( height - 1 , 26 , 16 ) | FLD_VAL ( width - 1 , 10 , 0 ) ;
2011-05-06 11:45:49 +05:30
2012-07-28 22:59:03 +05:30
if ( plane = = OMAP_DSS_GFX | | plane = = OMAP_DSS_WB )
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_SIZE ( plane ) , val ) ;
else
dispc_write_reg ( DISPC_OVL_PICTURE_SIZE ( plane ) , val ) ;
2009-11-12 11:41:42 +02:00
}
2012-09-21 14:51:49 +05:30
static void dispc_ovl_set_output_size ( enum omap_plane plane , int width ,
int height )
2009-11-12 11:41:42 +02:00
{
u32 val ;
BUG_ON ( plane = = OMAP_DSS_GFX ) ;
val = FLD_VAL ( height - 1 , 26 , 16 ) | FLD_VAL ( width - 1 , 10 , 0 ) ;
2011-05-06 11:45:49 +05:30
2012-07-28 22:59:03 +05:30
if ( plane = = OMAP_DSS_WB )
dispc_write_reg ( DISPC_OVL_PICTURE_SIZE ( plane ) , val ) ;
else
dispc_write_reg ( DISPC_OVL_SIZE ( plane ) , val ) ;
2009-11-12 11:41:42 +02:00
}
2012-09-26 16:55:27 +05:30
static void dispc_ovl_set_zorder ( enum omap_plane plane ,
enum omap_overlay_caps caps , u8 zorder )
2011-09-08 11:29:17 +05:30
{
2012-09-26 16:55:27 +05:30
if ( ( caps & OMAP_DSS_OVL_CAP_ZORDER ) = = 0 )
2011-09-08 11:29:17 +05:30
return ;
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( plane ) , zorder , 27 , 26 ) ;
}
static void dispc_ovl_enable_zorder_planes ( void )
{
int i ;
if ( ! dss_has_feature ( FEAT_ALPHA_FREE_ZORDER ) )
return ;
for ( i = 0 ; i < dss_feat_get_num_ovls ( ) ; i + + )
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( i ) , 1 , 25 , 25 ) ;
}
2012-09-26 16:55:27 +05:30
static void dispc_ovl_set_pre_mult_alpha ( enum omap_plane plane ,
enum omap_overlay_caps caps , bool enable )
2010-11-04 12:28:42 +01:00
{
2012-09-26 16:55:27 +05:30
if ( ( caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA ) = = 0 )
2010-11-04 12:28:42 +01:00
return ;
2011-05-06 11:45:49 +05:30
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( plane ) , enable ? 1 : 0 , 28 , 28 ) ;
2010-11-04 12:28:42 +01:00
}
2012-09-26 16:55:27 +05:30
static void dispc_ovl_setup_global_alpha ( enum omap_plane plane ,
enum omap_overlay_caps caps , u8 global_alpha )
2009-11-12 11:41:42 +02:00
{
2011-09-13 18:20:33 +05:30
static const unsigned shifts [ ] = { 0 , 8 , 16 , 24 , } ;
2011-08-15 11:51:50 +03:00
int shift ;
2012-09-26 16:55:27 +05:30
if ( ( caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA ) = = 0 )
2010-11-04 12:28:42 +01:00
return ;
2010-09-15 19:20:00 +05:30
2011-08-15 11:51:50 +03:00
shift = shifts [ plane ] ;
REG_FLD_MOD ( DISPC_GLOBAL_ALPHA , global_alpha , shift + 7 , shift ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_pix_inc ( enum omap_plane plane , s32 inc )
2009-11-12 11:41:42 +02:00
{
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_PIXEL_INC ( plane ) , inc ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_row_inc ( enum omap_plane plane , s32 inc )
2009-11-12 11:41:42 +02:00
{
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_ROW_INC ( plane ) , inc ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_color_mode ( enum omap_plane plane ,
2009-11-12 11:41:42 +02:00
enum omap_color_mode color_mode )
{
u32 m = 0 ;
2011-05-19 19:47:50 +05:30
if ( plane ! = OMAP_DSS_GFX ) {
switch ( color_mode ) {
case OMAP_DSS_COLOR_NV12 :
m = 0x0 ; break ;
2012-02-21 19:36:30 +05:30
case OMAP_DSS_COLOR_RGBX16 :
2011-05-19 19:47:50 +05:30
m = 0x1 ; break ;
case OMAP_DSS_COLOR_RGBA16 :
m = 0x2 ; break ;
2012-02-21 19:36:30 +05:30
case OMAP_DSS_COLOR_RGB12U :
2011-05-19 19:47:50 +05:30
m = 0x4 ; break ;
case OMAP_DSS_COLOR_ARGB16 :
m = 0x5 ; break ;
case OMAP_DSS_COLOR_RGB16 :
m = 0x6 ; break ;
case OMAP_DSS_COLOR_ARGB16_1555 :
m = 0x7 ; break ;
case OMAP_DSS_COLOR_RGB24U :
m = 0x8 ; break ;
case OMAP_DSS_COLOR_RGB24P :
m = 0x9 ; break ;
case OMAP_DSS_COLOR_YUV2 :
m = 0xa ; break ;
case OMAP_DSS_COLOR_UYVY :
m = 0xb ; break ;
case OMAP_DSS_COLOR_ARGB32 :
m = 0xc ; break ;
case OMAP_DSS_COLOR_RGBA32 :
m = 0xd ; break ;
case OMAP_DSS_COLOR_RGBX32 :
m = 0xe ; break ;
case OMAP_DSS_COLOR_XRGB16_1555 :
m = 0xf ; break ;
default :
2012-05-18 11:47:02 +03:00
BUG ( ) ; return ;
2011-05-19 19:47:50 +05:30
}
} else {
switch ( color_mode ) {
case OMAP_DSS_COLOR_CLUT1 :
m = 0x0 ; break ;
case OMAP_DSS_COLOR_CLUT2 :
m = 0x1 ; break ;
case OMAP_DSS_COLOR_CLUT4 :
m = 0x2 ; break ;
case OMAP_DSS_COLOR_CLUT8 :
m = 0x3 ; break ;
case OMAP_DSS_COLOR_RGB12U :
m = 0x4 ; break ;
case OMAP_DSS_COLOR_ARGB16 :
m = 0x5 ; break ;
case OMAP_DSS_COLOR_RGB16 :
m = 0x6 ; break ;
case OMAP_DSS_COLOR_ARGB16_1555 :
m = 0x7 ; break ;
case OMAP_DSS_COLOR_RGB24U :
m = 0x8 ; break ;
case OMAP_DSS_COLOR_RGB24P :
m = 0x9 ; break ;
2012-02-21 19:36:30 +05:30
case OMAP_DSS_COLOR_RGBX16 :
2011-05-19 19:47:50 +05:30
m = 0xa ; break ;
2012-02-21 19:36:30 +05:30
case OMAP_DSS_COLOR_RGBA16 :
2011-05-19 19:47:50 +05:30
m = 0xb ; break ;
case OMAP_DSS_COLOR_ARGB32 :
m = 0xc ; break ;
case OMAP_DSS_COLOR_RGBA32 :
m = 0xd ; break ;
case OMAP_DSS_COLOR_RGBX32 :
m = 0xe ; break ;
case OMAP_DSS_COLOR_XRGB16_1555 :
m = 0xf ; break ;
default :
2012-05-18 11:47:02 +03:00
BUG ( ) ; return ;
2011-05-19 19:47:50 +05:30
}
2009-11-12 11:41:42 +02:00
}
2011-05-06 11:45:49 +05:30
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( plane ) , m , 4 , 1 ) ;
2009-11-12 11:41:42 +02:00
}
2012-05-11 19:19:55 +05:30
static void dispc_ovl_configure_burst_type ( enum omap_plane plane ,
enum omap_dss_rotation_type rotation_type )
{
if ( dss_has_feature ( FEAT_BURST_2D ) = = 0 )
return ;
if ( rotation_type = = OMAP_DSS_ROT_TILER )
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( plane ) , 1 , 29 , 29 ) ;
else
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( plane ) , 0 , 29 , 29 ) ;
}
2011-10-28 15:26:26 +03:00
void dispc_ovl_set_channel_out ( enum omap_plane plane , enum omap_channel channel )
2009-11-12 11:41:42 +02:00
{
int shift ;
u32 val ;
2010-12-02 11:27:12 +00:00
int chan = 0 , chan2 = 0 ;
2009-11-12 11:41:42 +02:00
switch ( plane ) {
case OMAP_DSS_GFX :
shift = 8 ;
break ;
case OMAP_DSS_VIDEO1 :
case OMAP_DSS_VIDEO2 :
2011-09-13 18:20:33 +05:30
case OMAP_DSS_VIDEO3 :
2009-11-12 11:41:42 +02:00
shift = 16 ;
break ;
default :
BUG ( ) ;
return ;
}
2011-05-06 11:45:49 +05:30
val = dispc_read_reg ( DISPC_OVL_ATTRIBUTES ( plane ) ) ;
2010-12-02 11:27:12 +00:00
if ( dss_has_feature ( FEAT_MGR_LCD2 ) ) {
switch ( channel ) {
case OMAP_DSS_CHANNEL_LCD :
chan = 0 ;
chan2 = 0 ;
break ;
case OMAP_DSS_CHANNEL_DIGIT :
chan = 1 ;
chan2 = 0 ;
break ;
case OMAP_DSS_CHANNEL_LCD2 :
chan = 0 ;
chan2 = 1 ;
break ;
2012-06-29 10:43:13 +05:30
case OMAP_DSS_CHANNEL_LCD3 :
if ( dss_has_feature ( FEAT_MGR_LCD3 ) ) {
chan = 0 ;
chan2 = 2 ;
} else {
BUG ( ) ;
return ;
}
break ;
2010-12-02 11:27:12 +00:00
default :
BUG ( ) ;
2012-05-18 11:47:02 +03:00
return ;
2010-12-02 11:27:12 +00:00
}
val = FLD_MOD ( val , chan , shift , shift ) ;
val = FLD_MOD ( val , chan2 , 31 , 30 ) ;
} else {
val = FLD_MOD ( val , channel , shift , shift ) ;
}
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_ATTRIBUTES ( plane ) , val ) ;
2009-11-12 11:41:42 +02:00
}
2011-11-03 17:03:44 +02:00
static enum omap_channel dispc_ovl_get_channel_out ( enum omap_plane plane )
{
int shift ;
u32 val ;
enum omap_channel channel ;
switch ( plane ) {
case OMAP_DSS_GFX :
shift = 8 ;
break ;
case OMAP_DSS_VIDEO1 :
case OMAP_DSS_VIDEO2 :
case OMAP_DSS_VIDEO3 :
shift = 16 ;
break ;
default :
BUG ( ) ;
2012-05-18 11:47:02 +03:00
return 0 ;
2011-11-03 17:03:44 +02:00
}
val = dispc_read_reg ( DISPC_OVL_ATTRIBUTES ( plane ) ) ;
2012-06-29 10:43:13 +05:30
if ( dss_has_feature ( FEAT_MGR_LCD3 ) ) {
if ( FLD_GET ( val , 31 , 30 ) = = 0 )
channel = FLD_GET ( val , shift , shift ) ;
else if ( FLD_GET ( val , 31 , 30 ) = = 1 )
channel = OMAP_DSS_CHANNEL_LCD2 ;
else
channel = OMAP_DSS_CHANNEL_LCD3 ;
} else if ( dss_has_feature ( FEAT_MGR_LCD2 ) ) {
2011-11-03 17:03:44 +02:00
if ( FLD_GET ( val , 31 , 30 ) = = 0 )
channel = FLD_GET ( val , shift , shift ) ;
else
channel = OMAP_DSS_CHANNEL_LCD2 ;
} else {
channel = FLD_GET ( val , shift , shift ) ;
}
return channel ;
}
2012-09-22 12:38:19 +05:30
void dispc_wb_set_channel_in ( enum dss_writeback_channel channel )
{
enum omap_plane plane = OMAP_DSS_WB ;
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( plane ) , channel , 18 , 16 ) ;
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_burst_size ( enum omap_plane plane ,
2009-11-12 11:41:42 +02:00
enum omap_burst_size burst_size )
{
2012-09-10 17:31:39 +05:30
static const unsigned shifts [ ] = { 6 , 14 , 14 , 14 , 14 , } ;
2009-11-12 11:41:42 +02:00
int shift ;
2011-08-15 11:51:50 +03:00
shift = shifts [ plane ] ;
2011-06-21 09:35:36 +03:00
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( plane ) , burst_size , shift + 1 , shift ) ;
2009-11-12 11:41:42 +02:00
}
2011-06-21 09:35:36 +03:00
static void dispc_configure_burst_sizes ( void )
{
int i ;
const int burst_size = BURST_SIZE_X8 ;
/* Configure burst size always to maximum size */
2012-10-15 15:37:22 +03:00
for ( i = 0 ; i < dss_feat_get_num_ovls ( ) ; + + i )
2011-08-16 13:25:00 +03:00
dispc_ovl_set_burst_size ( i , burst_size ) ;
2011-06-21 09:35:36 +03:00
}
2012-01-13 13:17:01 +02:00
static u32 dispc_ovl_get_burst_size ( enum omap_plane plane )
2011-06-21 09:35:36 +03:00
{
unsigned unit = dss_feat_get_burst_size_unit ( ) ;
/* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
return unit * 8 ;
}
2011-03-11 18:02:49 +05:30
void dispc_enable_gamma_table ( bool enable )
{
/*
* This is partially implemented to support only disabling of
* the gamma table .
*/
if ( enable ) {
DSSWARN ( " Gamma table enabling for TV not yet supported " ) ;
return ;
}
REG_FLD_MOD ( DISPC_CONFIG , enable , 9 , 9 ) ;
}
2011-11-04 18:14:20 +02:00
static void dispc_mgr_enable_cpr ( enum omap_channel channel , bool enable )
2011-06-21 09:34:30 +03:00
{
2012-06-21 11:07:44 +05:30
if ( channel = = OMAP_DSS_CHANNEL_DIGIT )
2011-06-21 09:34:30 +03:00
return ;
2012-06-21 11:07:44 +05:30
mgr_fld_write ( channel , DISPC_MGR_FLD_CPR , enable ) ;
2011-06-21 09:34:30 +03:00
}
2011-11-04 18:14:20 +02:00
static void dispc_mgr_set_cpr_coef ( enum omap_channel channel ,
2012-10-03 09:09:11 +02:00
const struct omap_dss_cpr_coefs * coefs )
2011-06-21 09:34:30 +03:00
{
u32 coef_r , coef_g , coef_b ;
2012-06-29 14:41:30 +05:30
if ( ! dss_mgr_is_lcd ( channel ) )
2011-06-21 09:34:30 +03:00
return ;
coef_r = FLD_VAL ( coefs - > rr , 31 , 22 ) | FLD_VAL ( coefs - > rg , 20 , 11 ) |
FLD_VAL ( coefs - > rb , 9 , 0 ) ;
coef_g = FLD_VAL ( coefs - > gr , 31 , 22 ) | FLD_VAL ( coefs - > gg , 20 , 11 ) |
FLD_VAL ( coefs - > gb , 9 , 0 ) ;
coef_b = FLD_VAL ( coefs - > br , 31 , 22 ) | FLD_VAL ( coefs - > bg , 20 , 11 ) |
FLD_VAL ( coefs - > bb , 9 , 0 ) ;
dispc_write_reg ( DISPC_CPR_COEF_R ( channel ) , coef_r ) ;
dispc_write_reg ( DISPC_CPR_COEF_G ( channel ) , coef_g ) ;
dispc_write_reg ( DISPC_CPR_COEF_B ( channel ) , coef_b ) ;
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_vid_color_conv ( enum omap_plane plane , bool enable )
2009-11-12 11:41:42 +02:00
{
u32 val ;
BUG_ON ( plane = = OMAP_DSS_GFX ) ;
2011-05-06 11:45:49 +05:30
val = dispc_read_reg ( DISPC_OVL_ATTRIBUTES ( plane ) ) ;
2009-11-12 11:41:42 +02:00
val = FLD_MOD ( val , enable , 9 , 9 ) ;
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_ATTRIBUTES ( plane ) , val ) ;
2009-11-12 11:41:42 +02:00
}
2012-09-22 12:30:17 +05:30
static void dispc_ovl_enable_replication ( enum omap_plane plane ,
enum omap_overlay_caps caps , bool enable )
2009-11-12 11:41:42 +02:00
{
2011-09-13 18:20:33 +05:30
static const unsigned shifts [ ] = { 5 , 10 , 10 , 10 } ;
2011-08-15 11:51:50 +03:00
int shift ;
2009-11-12 11:41:42 +02:00
2012-09-22 12:30:17 +05:30
if ( ( caps & OMAP_DSS_OVL_CAP_REPLICATION ) = = 0 )
return ;
2011-08-15 11:51:50 +03:00
shift = shifts [ plane ] ;
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( plane ) , enable , shift , shift ) ;
2009-11-12 11:41:42 +02:00
}
2012-04-16 12:53:44 +05:30
static void dispc_mgr_set_size ( enum omap_channel channel , u16 width ,
2012-04-16 12:53:42 +05:30
u16 height )
2009-11-12 11:41:42 +02:00
{
u32 val ;
2012-11-14 13:50:15 +05:30
val = FLD_VAL ( height - 1 , dispc . feat - > mgr_height_start , 16 ) |
FLD_VAL ( width - 1 , dispc . feat - > mgr_width_start , 0 ) ;
2012-04-16 12:53:44 +05:30
dispc_write_reg ( DISPC_SIZE_MGR ( channel ) , val ) ;
2009-11-12 11:41:42 +02:00
}
2012-08-22 16:56:57 +03:00
static void dispc_init_fifos ( void )
2009-11-12 11:41:42 +02:00
{
u32 size ;
2012-08-22 16:56:57 +03:00
int fifo ;
2010-09-15 19:20:00 +05:30
u8 start , end ;
2011-06-21 09:35:36 +03:00
u32 unit ;
unit = dss_feat_get_buffer_size_unit ( ) ;
2009-11-12 11:41:42 +02:00
2010-09-15 19:20:00 +05:30
dss_feat_get_reg_field ( FEAT_REG_FIFOSIZE , & start , & end ) ;
2009-11-12 11:41:42 +02:00
2012-08-22 16:56:57 +03:00
for ( fifo = 0 ; fifo < dispc . feat - > num_fifos ; + + fifo ) {
size = REG_GET ( DISPC_OVL_FIFO_SIZE_STATUS ( fifo ) , start , end ) ;
2011-06-21 09:35:36 +03:00
size * = unit ;
2012-08-22 16:56:57 +03:00
dispc . fifo_size [ fifo ] = size ;
/*
* By default fifos are mapped directly to overlays , fifo 0 to
* ovl 0 , fifo 1 to ovl 1 , etc .
*/
dispc . fifo_assignment [ fifo ] = fifo ;
2009-11-12 11:41:42 +02:00
}
2012-08-22 16:57:02 +03:00
/*
* The GFX fifo on OMAP4 is smaller than the other fifos . The small fifo
* causes problems with certain use cases , like using the tiler in 2 D
* mode . The below hack swaps the fifos of GFX and WB planes , thus
* giving GFX plane a larger fifo . WB but should work fine with a
* smaller fifo .
*/
if ( dispc . feat - > gfx_fifo_workaround ) {
u32 v ;
v = dispc_read_reg ( DISPC_GLOBAL_BUFFER ) ;
v = FLD_MOD ( v , 4 , 2 , 0 ) ; /* GFX BUF top to WB */
v = FLD_MOD ( v , 4 , 5 , 3 ) ; /* GFX BUF bottom to WB */
v = FLD_MOD ( v , 0 , 26 , 24 ) ; /* WB BUF top to GFX */
v = FLD_MOD ( v , 0 , 29 , 27 ) ; /* WB BUF bottom to GFX */
dispc_write_reg ( DISPC_GLOBAL_BUFFER , v ) ;
dispc . fifo_assignment [ OMAP_DSS_GFX ] = OMAP_DSS_WB ;
dispc . fifo_assignment [ OMAP_DSS_WB ] = OMAP_DSS_GFX ;
}
2009-11-12 11:41:42 +02:00
}
2012-01-13 13:17:01 +02:00
static u32 dispc_ovl_get_fifo_size ( enum omap_plane plane )
2009-11-12 11:41:42 +02:00
{
2012-08-22 16:56:57 +03:00
int fifo ;
u32 size = 0 ;
for ( fifo = 0 ; fifo < dispc . feat - > num_fifos ; + + fifo ) {
if ( dispc . fifo_assignment [ fifo ] = = plane )
size + = dispc . fifo_size [ fifo ] ;
}
return size ;
2009-11-12 11:41:42 +02:00
}
2011-10-31 08:58:52 +02:00
void dispc_ovl_set_fifo_threshold ( enum omap_plane plane , u32 low , u32 high )
2009-11-12 11:41:42 +02:00
{
2010-09-15 19:20:00 +05:30
u8 hi_start , hi_end , lo_start , lo_end ;
2011-06-21 09:35:36 +03:00
u32 unit ;
unit = dss_feat_get_buffer_size_unit ( ) ;
WARN_ON ( low % unit ! = 0 ) ;
WARN_ON ( high % unit ! = 0 ) ;
low / = unit ;
high / = unit ;
2010-09-15 19:20:00 +05:30
2011-05-06 11:45:49 +05:30
dss_feat_get_reg_field ( FEAT_REG_FIFOHIGHTHRESHOLD , & hi_start , & hi_end ) ;
dss_feat_get_reg_field ( FEAT_REG_FIFOLOWTHRESHOLD , & lo_start , & lo_end ) ;
2012-01-13 13:14:57 +02:00
DSSDBG ( " fifo(%d) threshold (bytes), old %u/%u, new %u/%u \n " ,
2009-11-12 11:41:42 +02:00
plane ,
2011-05-06 11:45:49 +05:30
REG_GET ( DISPC_OVL_FIFO_THRESHOLD ( plane ) ,
2012-01-13 13:14:57 +02:00
lo_start , lo_end ) * unit ,
2011-05-06 11:45:49 +05:30
REG_GET ( DISPC_OVL_FIFO_THRESHOLD ( plane ) ,
2012-01-13 13:14:57 +02:00
hi_start , hi_end ) * unit ,
low * unit , high * unit ) ;
2009-11-12 11:41:42 +02:00
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_FIFO_THRESHOLD ( plane ) ,
2010-09-15 19:20:00 +05:30
FLD_VAL ( high , hi_start , hi_end ) |
FLD_VAL ( low , lo_start , lo_end ) ) ;
2009-11-12 11:41:42 +02:00
}
void dispc_enable_fifomerge ( bool enable )
{
2012-01-13 13:24:04 +02:00
if ( ! dss_has_feature ( FEAT_FIFO_MERGE ) ) {
WARN_ON ( enable ) ;
return ;
}
2009-11-12 11:41:42 +02:00
DSSDBG ( " FIFO merge %s \n " , enable ? " enabled " : " disabled " ) ;
REG_FLD_MOD ( DISPC_CONFIG , enable ? 1 : 0 , 14 , 14 ) ;
}
2012-01-13 13:17:01 +02:00
void dispc_ovl_compute_fifo_thresholds ( enum omap_plane plane ,
2012-05-15 15:31:01 +03:00
u32 * fifo_low , u32 * fifo_high , bool use_fifomerge ,
bool manual_update )
2012-01-13 13:17:01 +02:00
{
/*
* All sizes are in bytes . Both the buffer and burst are made of
* buffer_units , and the fifo thresholds must be buffer_unit aligned .
*/
unsigned buf_unit = dss_feat_get_buffer_size_unit ( ) ;
2012-01-13 13:18:11 +02:00
unsigned ovl_fifo_size , total_fifo_size , burst_size ;
int i ;
2012-01-13 13:17:01 +02:00
burst_size = dispc_ovl_get_burst_size ( plane ) ;
2012-01-13 13:18:11 +02:00
ovl_fifo_size = dispc_ovl_get_fifo_size ( plane ) ;
2012-01-13 13:17:01 +02:00
2012-01-13 13:18:11 +02:00
if ( use_fifomerge ) {
total_fifo_size = 0 ;
2012-10-15 15:37:22 +03:00
for ( i = 0 ; i < dss_feat_get_num_ovls ( ) ; + + i )
2012-01-13 13:18:11 +02:00
total_fifo_size + = dispc_ovl_get_fifo_size ( i ) ;
} else {
total_fifo_size = ovl_fifo_size ;
}
/*
* We use the same low threshold for both fifomerge and non - fifomerge
* cases , but for fifomerge we calculate the high threshold using the
* combined fifo size
*/
2012-05-15 15:31:01 +03:00
if ( manual_update & & dss_has_feature ( FEAT_OMAP3_DSI_FIFO_BUG ) ) {
2012-01-13 13:18:11 +02:00
* fifo_low = ovl_fifo_size - burst_size * 2 ;
* fifo_high = total_fifo_size - burst_size ;
2012-09-10 17:31:39 +05:30
} else if ( plane = = OMAP_DSS_WB ) {
/*
* Most optimal configuration for writeback is to push out data
* to the interconnect the moment writeback pushes enough pixels
* in the FIFO to form a burst
*/
* fifo_low = 0 ;
* fifo_high = burst_size ;
2012-01-13 13:18:11 +02:00
} else {
* fifo_low = ovl_fifo_size - burst_size ;
* fifo_high = total_fifo_size - buf_unit ;
}
2012-01-13 13:17:01 +02:00
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_fir ( enum omap_plane plane ,
2011-05-19 19:47:54 +05:30
int hinc , int vinc ,
enum omap_color_component color_comp )
2009-11-12 11:41:42 +02:00
{
u32 val ;
2011-05-19 19:47:54 +05:30
if ( color_comp = = DISPC_COLOR_COMPONENT_RGB_Y ) {
u8 hinc_start , hinc_end , vinc_start , vinc_end ;
2010-09-15 19:20:00 +05:30
2011-05-19 19:47:54 +05:30
dss_feat_get_reg_field ( FEAT_REG_FIRHINC ,
& hinc_start , & hinc_end ) ;
dss_feat_get_reg_field ( FEAT_REG_FIRVINC ,
& vinc_start , & vinc_end ) ;
val = FLD_VAL ( vinc , vinc_start , vinc_end ) |
FLD_VAL ( hinc , hinc_start , hinc_end ) ;
2010-09-15 19:20:00 +05:30
2011-05-19 19:47:54 +05:30
dispc_write_reg ( DISPC_OVL_FIR ( plane ) , val ) ;
} else {
val = FLD_VAL ( vinc , 28 , 16 ) | FLD_VAL ( hinc , 12 , 0 ) ;
dispc_write_reg ( DISPC_OVL_FIR2 ( plane ) , val ) ;
}
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_vid_accu0 ( enum omap_plane plane , int haccu , int vaccu )
2009-11-12 11:41:42 +02:00
{
u32 val ;
2011-03-02 11:19:50 +05:30
u8 hor_start , hor_end , vert_start , vert_end ;
2009-11-12 11:41:42 +02:00
2011-03-02 11:19:50 +05:30
dss_feat_get_reg_field ( FEAT_REG_HORIZONTALACCU , & hor_start , & hor_end ) ;
dss_feat_get_reg_field ( FEAT_REG_VERTICALACCU , & vert_start , & vert_end ) ;
val = FLD_VAL ( vaccu , vert_start , vert_end ) |
FLD_VAL ( haccu , hor_start , hor_end ) ;
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_ACCU0 ( plane ) , val ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_vid_accu1 ( enum omap_plane plane , int haccu , int vaccu )
2009-11-12 11:41:42 +02:00
{
u32 val ;
2011-03-02 11:19:50 +05:30
u8 hor_start , hor_end , vert_start , vert_end ;
2009-11-12 11:41:42 +02:00
2011-03-02 11:19:50 +05:30
dss_feat_get_reg_field ( FEAT_REG_HORIZONTALACCU , & hor_start , & hor_end ) ;
dss_feat_get_reg_field ( FEAT_REG_VERTICALACCU , & vert_start , & vert_end ) ;
val = FLD_VAL ( vaccu , vert_start , vert_end ) |
FLD_VAL ( haccu , hor_start , hor_end ) ;
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_ACCU1 ( plane ) , val ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_vid_accu2_0 ( enum omap_plane plane , int haccu ,
int vaccu )
2011-05-19 19:47:53 +05:30
{
u32 val ;
val = FLD_VAL ( vaccu , 26 , 16 ) | FLD_VAL ( haccu , 10 , 0 ) ;
dispc_write_reg ( DISPC_OVL_ACCU2_0 ( plane ) , val ) ;
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_vid_accu2_1 ( enum omap_plane plane , int haccu ,
int vaccu )
2011-05-19 19:47:53 +05:30
{
u32 val ;
val = FLD_VAL ( vaccu , 26 , 16 ) | FLD_VAL ( haccu , 10 , 0 ) ;
dispc_write_reg ( DISPC_OVL_ACCU2_1 ( plane ) , val ) ;
}
2009-11-12 11:41:42 +02:00
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_scale_param ( enum omap_plane plane ,
2009-11-12 11:41:42 +02:00
u16 orig_width , u16 orig_height ,
u16 out_width , u16 out_height ,
2011-05-19 19:47:54 +05:30
bool five_taps , u8 rotation ,
enum omap_color_component color_comp )
2009-11-12 11:41:42 +02:00
{
2011-05-19 19:47:54 +05:30
int fir_hinc , fir_vinc ;
2009-11-12 11:41:42 +02:00
2011-05-19 19:47:51 +05:30
fir_hinc = 1024 * orig_width / out_width ;
fir_vinc = 1024 * orig_height / out_height ;
2009-11-12 11:41:42 +02:00
2011-12-19 14:03:44 +05:30
dispc_ovl_set_scale_coef ( plane , fir_hinc , fir_vinc , five_taps ,
color_comp ) ;
2011-08-16 13:25:00 +03:00
dispc_ovl_set_fir ( plane , fir_hinc , fir_vinc , color_comp ) ;
2011-05-19 19:47:54 +05:30
}
2012-05-15 12:22:34 +05:30
static void dispc_ovl_set_accu_uv ( enum omap_plane plane ,
u16 orig_width , u16 orig_height , u16 out_width , u16 out_height ,
bool ilace , enum omap_color_mode color_mode , u8 rotation )
{
int h_accu2_0 , h_accu2_1 ;
int v_accu2_0 , v_accu2_1 ;
int chroma_hinc , chroma_vinc ;
int idx ;
struct accu {
s8 h0_m , h0_n ;
s8 h1_m , h1_n ;
s8 v0_m , v0_n ;
s8 v1_m , v1_n ;
} ;
const struct accu * accu_table ;
const struct accu * accu_val ;
static const struct accu accu_nv12 [ 4 ] = {
{ 0 , 1 , 0 , 1 , - 1 , 2 , 0 , 1 } ,
{ 1 , 2 , - 3 , 4 , 0 , 1 , 0 , 1 } ,
{ - 1 , 1 , 0 , 1 , - 1 , 2 , 0 , 1 } ,
{ - 1 , 2 , - 1 , 2 , - 1 , 1 , 0 , 1 } ,
} ;
static const struct accu accu_nv12_ilace [ 4 ] = {
{ 0 , 1 , 0 , 1 , - 3 , 4 , - 1 , 4 } ,
{ - 1 , 4 , - 3 , 4 , 0 , 1 , 0 , 1 } ,
{ - 1 , 1 , 0 , 1 , - 1 , 4 , - 3 , 4 } ,
{ - 3 , 4 , - 3 , 4 , - 1 , 1 , 0 , 1 } ,
} ;
static const struct accu accu_yuv [ 4 ] = {
{ 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 } ,
{ 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 } ,
{ - 1 , 1 , 0 , 1 , 0 , 1 , 0 , 1 } ,
{ 0 , 1 , 0 , 1 , - 1 , 1 , 0 , 1 } ,
} ;
switch ( rotation ) {
case OMAP_DSS_ROT_0 :
idx = 0 ;
break ;
case OMAP_DSS_ROT_90 :
idx = 1 ;
break ;
case OMAP_DSS_ROT_180 :
idx = 2 ;
break ;
case OMAP_DSS_ROT_270 :
idx = 3 ;
break ;
default :
BUG ( ) ;
2012-05-18 11:47:02 +03:00
return ;
2012-05-15 12:22:34 +05:30
}
switch ( color_mode ) {
case OMAP_DSS_COLOR_NV12 :
if ( ilace )
accu_table = accu_nv12_ilace ;
else
accu_table = accu_nv12 ;
break ;
case OMAP_DSS_COLOR_YUV2 :
case OMAP_DSS_COLOR_UYVY :
accu_table = accu_yuv ;
break ;
default :
BUG ( ) ;
2012-05-18 11:47:02 +03:00
return ;
2012-05-15 12:22:34 +05:30
}
accu_val = & accu_table [ idx ] ;
chroma_hinc = 1024 * orig_width / out_width ;
chroma_vinc = 1024 * orig_height / out_height ;
h_accu2_0 = ( accu_val - > h0_m * chroma_hinc / accu_val - > h0_n ) % 1024 ;
h_accu2_1 = ( accu_val - > h1_m * chroma_hinc / accu_val - > h1_n ) % 1024 ;
v_accu2_0 = ( accu_val - > v0_m * chroma_vinc / accu_val - > v0_n ) % 1024 ;
v_accu2_1 = ( accu_val - > v1_m * chroma_vinc / accu_val - > v1_n ) % 1024 ;
dispc_ovl_set_vid_accu2_0 ( plane , h_accu2_0 , v_accu2_0 ) ;
dispc_ovl_set_vid_accu2_1 ( plane , h_accu2_1 , v_accu2_1 ) ;
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_scaling_common ( enum omap_plane plane ,
2011-05-19 19:47:54 +05:30
u16 orig_width , u16 orig_height ,
u16 out_width , u16 out_height ,
bool ilace , bool five_taps ,
bool fieldmode , enum omap_color_mode color_mode ,
u8 rotation )
{
int accu0 = 0 ;
int accu1 = 0 ;
u32 l ;
2009-11-12 11:41:42 +02:00
2011-08-16 13:25:00 +03:00
dispc_ovl_set_scale_param ( plane , orig_width , orig_height ,
2011-05-19 19:47:54 +05:30
out_width , out_height , five_taps ,
rotation , DISPC_COLOR_COMPONENT_RGB_Y ) ;
2011-05-06 11:45:49 +05:30
l = dispc_read_reg ( DISPC_OVL_ATTRIBUTES ( plane ) ) ;
2009-11-12 11:41:42 +02:00
2011-03-02 11:19:50 +05:30
/* RESIZEENABLE and VERTICALTAPS */
l & = ~ ( ( 0x3 < < 5 ) | ( 0x1 < < 21 ) ) ;
2011-05-19 19:47:51 +05:30
l | = ( orig_width ! = out_width ) ? ( 1 < < 5 ) : 0 ;
l | = ( orig_height ! = out_height ) ? ( 1 < < 6 ) : 0 ;
2011-03-02 11:19:50 +05:30
l | = five_taps ? ( 1 < < 21 ) : 0 ;
2009-11-12 11:41:42 +02:00
2011-03-02 11:19:50 +05:30
/* VRESIZECONF and HRESIZECONF */
if ( dss_has_feature ( FEAT_RESIZECONF ) ) {
l & = ~ ( 0x3 < < 7 ) ;
2011-05-19 19:47:54 +05:30
l | = ( orig_width < = out_width ) ? 0 : ( 1 < < 7 ) ;
l | = ( orig_height < = out_height ) ? 0 : ( 1 < < 8 ) ;
2011-03-02 11:19:50 +05:30
}
2009-11-12 11:41:42 +02:00
2011-03-02 11:19:50 +05:30
/* LINEBUFFERSPLIT */
if ( dss_has_feature ( FEAT_LINEBUFFERSPLIT ) ) {
l & = ~ ( 0x1 < < 22 ) ;
l | = five_taps ? ( 1 < < 22 ) : 0 ;
}
2009-11-12 11:41:42 +02:00
2011-05-06 11:45:49 +05:30
dispc_write_reg ( DISPC_OVL_ATTRIBUTES ( plane ) , l ) ;
2009-11-12 11:41:42 +02:00
/*
* field 0 = even field = bottom field
* field 1 = odd field = top field
*/
if ( ilace & & ! fieldmode ) {
accu1 = 0 ;
2011-05-19 19:47:54 +05:30
accu0 = ( ( 1024 * orig_height / out_height ) / 2 ) & 0x3ff ;
2009-11-12 11:41:42 +02:00
if ( accu0 > = 1024 / 2 ) {
accu1 = 1024 / 2 ;
accu0 - = accu1 ;
}
}
2011-08-16 13:25:00 +03:00
dispc_ovl_set_vid_accu0 ( plane , 0 , accu0 ) ;
dispc_ovl_set_vid_accu1 ( plane , 0 , accu1 ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_scaling_uv ( enum omap_plane plane ,
2011-05-19 19:47:54 +05:30
u16 orig_width , u16 orig_height ,
u16 out_width , u16 out_height ,
bool ilace , bool five_taps ,
bool fieldmode , enum omap_color_mode color_mode ,
u8 rotation )
{
int scale_x = out_width ! = orig_width ;
int scale_y = out_height ! = orig_height ;
2012-08-24 11:11:14 +05:30
bool chroma_upscale = plane ! = OMAP_DSS_WB ? true : false ;
2011-05-19 19:47:54 +05:30
if ( ! dss_has_feature ( FEAT_HANDLE_UV_SEPARATE ) )
return ;
if ( ( color_mode ! = OMAP_DSS_COLOR_YUV2 & &
color_mode ! = OMAP_DSS_COLOR_UYVY & &
color_mode ! = OMAP_DSS_COLOR_NV12 ) ) {
/* reset chroma resampling for RGB formats */
2012-07-16 16:37:45 +05:30
if ( plane ! = OMAP_DSS_WB )
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES2 ( plane ) , 0 , 8 , 8 ) ;
2011-05-19 19:47:54 +05:30
return ;
}
2012-05-15 15:54:15 +03:00
dispc_ovl_set_accu_uv ( plane , orig_width , orig_height , out_width ,
out_height , ilace , color_mode , rotation ) ;
2011-05-19 19:47:54 +05:30
switch ( color_mode ) {
case OMAP_DSS_COLOR_NV12 :
2012-08-22 17:04:48 +05:30
if ( chroma_upscale ) {
/* UV is subsampled by 2 horizontally and vertically */
orig_height > > = 1 ;
orig_width > > = 1 ;
} else {
/* UV is downsampled by 2 horizontally and vertically */
orig_height < < = 1 ;
orig_width < < = 1 ;
}
2011-05-19 19:47:54 +05:30
break ;
case OMAP_DSS_COLOR_YUV2 :
case OMAP_DSS_COLOR_UYVY :
2012-08-22 17:04:48 +05:30
/* For YUV422 with 90/270 rotation, we don't upsample chroma */
2011-05-19 19:47:54 +05:30
if ( rotation = = OMAP_DSS_ROT_0 | |
2012-08-22 17:04:48 +05:30
rotation = = OMAP_DSS_ROT_180 ) {
if ( chroma_upscale )
/* UV is subsampled by 2 horizontally */
orig_width > > = 1 ;
else
/* UV is downsampled by 2 horizontally */
orig_width < < = 1 ;
}
2011-05-19 19:47:54 +05:30
/* must use FIR for YUV422 if rotated */
if ( rotation ! = OMAP_DSS_ROT_0 )
scale_x = scale_y = true ;
2012-08-22 17:04:48 +05:30
2011-05-19 19:47:54 +05:30
break ;
default :
BUG ( ) ;
2012-05-18 11:47:02 +03:00
return ;
2011-05-19 19:47:54 +05:30
}
if ( out_width ! = orig_width )
scale_x = true ;
if ( out_height ! = orig_height )
scale_y = true ;
2011-08-16 13:25:00 +03:00
dispc_ovl_set_scale_param ( plane , orig_width , orig_height ,
2011-05-19 19:47:54 +05:30
out_width , out_height , five_taps ,
rotation , DISPC_COLOR_COMPONENT_UV ) ;
2012-07-16 16:37:45 +05:30
if ( plane ! = OMAP_DSS_WB )
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES2 ( plane ) ,
( scale_x | | scale_y ) ? 1 : 0 , 8 , 8 ) ;
2011-05-19 19:47:54 +05:30
/* set H scaling */
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( plane ) , scale_x ? 1 : 0 , 5 , 5 ) ;
/* set V scaling */
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( plane ) , scale_y ? 1 : 0 , 6 , 6 ) ;
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_scaling ( enum omap_plane plane ,
2011-05-19 19:47:54 +05:30
u16 orig_width , u16 orig_height ,
u16 out_width , u16 out_height ,
bool ilace , bool five_taps ,
bool fieldmode , enum omap_color_mode color_mode ,
u8 rotation )
{
BUG_ON ( plane = = OMAP_DSS_GFX ) ;
2011-08-16 13:25:00 +03:00
dispc_ovl_set_scaling_common ( plane ,
2011-05-19 19:47:54 +05:30
orig_width , orig_height ,
out_width , out_height ,
ilace , five_taps ,
fieldmode , color_mode ,
rotation ) ;
2011-08-16 13:25:00 +03:00
dispc_ovl_set_scaling_uv ( plane ,
2011-05-19 19:47:54 +05:30
orig_width , orig_height ,
out_width , out_height ,
ilace , five_taps ,
fieldmode , color_mode ,
rotation ) ;
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_rotation_attrs ( enum omap_plane plane , u8 rotation ,
2009-11-12 11:41:42 +02:00
bool mirroring , enum omap_color_mode color_mode )
{
2011-03-02 11:19:50 +05:30
bool row_repeat = false ;
int vidrot = 0 ;
2009-11-12 11:41:42 +02:00
if ( color_mode = = OMAP_DSS_COLOR_YUV2 | |
color_mode = = OMAP_DSS_COLOR_UYVY ) {
if ( mirroring ) {
switch ( rotation ) {
case OMAP_DSS_ROT_0 :
vidrot = 2 ;
break ;
case OMAP_DSS_ROT_90 :
vidrot = 1 ;
break ;
case OMAP_DSS_ROT_180 :
vidrot = 0 ;
break ;
case OMAP_DSS_ROT_270 :
vidrot = 3 ;
break ;
}
} else {
switch ( rotation ) {
case OMAP_DSS_ROT_0 :
vidrot = 0 ;
break ;
case OMAP_DSS_ROT_90 :
vidrot = 1 ;
break ;
case OMAP_DSS_ROT_180 :
vidrot = 2 ;
break ;
case OMAP_DSS_ROT_270 :
vidrot = 3 ;
break ;
}
}
if ( rotation = = OMAP_DSS_ROT_90 | | rotation = = OMAP_DSS_ROT_270 )
2011-03-02 11:19:50 +05:30
row_repeat = true ;
2009-11-12 11:41:42 +02:00
else
2011-03-02 11:19:50 +05:30
row_repeat = false ;
2009-11-12 11:41:42 +02:00
}
2011-03-02 11:19:50 +05:30
2011-05-06 11:45:49 +05:30
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( plane ) , vidrot , 13 , 12 ) ;
2011-03-02 11:19:50 +05:30
if ( dss_has_feature ( FEAT_ROWREPEATENABLE ) )
2011-05-06 11:45:49 +05:30
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( plane ) ,
row_repeat ? 1 : 0 , 18 , 18 ) ;
2009-11-12 11:41:42 +02:00
}
static int color_mode_to_bpp ( enum omap_color_mode color_mode )
{
switch ( color_mode ) {
case OMAP_DSS_COLOR_CLUT1 :
return 1 ;
case OMAP_DSS_COLOR_CLUT2 :
return 2 ;
case OMAP_DSS_COLOR_CLUT4 :
return 4 ;
case OMAP_DSS_COLOR_CLUT8 :
2011-05-19 19:47:50 +05:30
case OMAP_DSS_COLOR_NV12 :
2009-11-12 11:41:42 +02:00
return 8 ;
case OMAP_DSS_COLOR_RGB12U :
case OMAP_DSS_COLOR_RGB16 :
case OMAP_DSS_COLOR_ARGB16 :
case OMAP_DSS_COLOR_YUV2 :
case OMAP_DSS_COLOR_UYVY :
2011-05-19 19:47:50 +05:30
case OMAP_DSS_COLOR_RGBA16 :
case OMAP_DSS_COLOR_RGBX16 :
case OMAP_DSS_COLOR_ARGB16_1555 :
case OMAP_DSS_COLOR_XRGB16_1555 :
2009-11-12 11:41:42 +02:00
return 16 ;
case OMAP_DSS_COLOR_RGB24P :
return 24 ;
case OMAP_DSS_COLOR_RGB24U :
case OMAP_DSS_COLOR_ARGB32 :
case OMAP_DSS_COLOR_RGBA32 :
case OMAP_DSS_COLOR_RGBX32 :
return 32 ;
default :
BUG ( ) ;
2012-05-18 11:47:02 +03:00
return 0 ;
2009-11-12 11:41:42 +02:00
}
}
static s32 pixinc ( int pixels , u8 ps )
{
if ( pixels = = 1 )
return 1 ;
else if ( pixels > 1 )
return 1 + ( pixels - 1 ) * ps ;
else if ( pixels < 0 )
return 1 - ( - pixels + 1 ) * ps ;
else
BUG ( ) ;
2012-05-18 11:47:02 +03:00
return 0 ;
2009-11-12 11:41:42 +02:00
}
static void calc_vrfb_rotation_offset ( u8 rotation , bool mirror ,
u16 screen_width ,
u16 width , u16 height ,
enum omap_color_mode color_mode , bool fieldmode ,
unsigned int field_offset ,
unsigned * offset0 , unsigned * offset1 ,
2012-04-02 20:43:16 +05:30
s32 * row_inc , s32 * pix_inc , int x_predecim , int y_predecim )
2009-11-12 11:41:42 +02:00
{
u8 ps ;
/* FIXME CLUT formats */
switch ( color_mode ) {
case OMAP_DSS_COLOR_CLUT1 :
case OMAP_DSS_COLOR_CLUT2 :
case OMAP_DSS_COLOR_CLUT4 :
case OMAP_DSS_COLOR_CLUT8 :
BUG ( ) ;
return ;
case OMAP_DSS_COLOR_YUV2 :
case OMAP_DSS_COLOR_UYVY :
ps = 4 ;
break ;
default :
ps = color_mode_to_bpp ( color_mode ) / 8 ;
break ;
}
DSSDBG ( " calc_rot(%d): scrw %d, %dx%d \n " , rotation , screen_width ,
width , height ) ;
/*
* field 0 = even field = bottom field
* field 1 = odd field = top field
*/
switch ( rotation + mirror * 4 ) {
case OMAP_DSS_ROT_0 :
case OMAP_DSS_ROT_180 :
/*
* If the pixel format is YUV or UYVY divide the width
* of the image by 2 for 0 and 180 degree rotation .
*/
if ( color_mode = = OMAP_DSS_COLOR_YUV2 | |
color_mode = = OMAP_DSS_COLOR_UYVY )
width = width > > 1 ;
case OMAP_DSS_ROT_90 :
case OMAP_DSS_ROT_270 :
* offset1 = 0 ;
if ( field_offset )
* offset0 = field_offset * screen_width * ps ;
else
* offset0 = 0 ;
2012-04-02 20:43:16 +05:30
* row_inc = pixinc ( 1 +
( y_predecim * screen_width - x_predecim * width ) +
( fieldmode ? screen_width : 0 ) , ps ) ;
* pix_inc = pixinc ( x_predecim , ps ) ;
2009-11-12 11:41:42 +02:00
break ;
case OMAP_DSS_ROT_0 + 4 :
case OMAP_DSS_ROT_180 + 4 :
/* If the pixel format is YUV or UYVY divide the width
* of the image by 2 for 0 degree and 180 degree
*/
if ( color_mode = = OMAP_DSS_COLOR_YUV2 | |
color_mode = = OMAP_DSS_COLOR_UYVY )
width = width > > 1 ;
case OMAP_DSS_ROT_90 + 4 :
case OMAP_DSS_ROT_270 + 4 :
* offset1 = 0 ;
if ( field_offset )
* offset0 = field_offset * screen_width * ps ;
else
* offset0 = 0 ;
2012-04-02 20:43:16 +05:30
* row_inc = pixinc ( 1 -
( y_predecim * screen_width + x_predecim * width ) -
( fieldmode ? screen_width : 0 ) , ps ) ;
* pix_inc = pixinc ( x_predecim , ps ) ;
2009-11-12 11:41:42 +02:00
break ;
default :
BUG ( ) ;
2012-05-18 11:47:02 +03:00
return ;
2009-11-12 11:41:42 +02:00
}
}
static void calc_dma_rotation_offset ( u8 rotation , bool mirror ,
u16 screen_width ,
u16 width , u16 height ,
enum omap_color_mode color_mode , bool fieldmode ,
unsigned int field_offset ,
unsigned * offset0 , unsigned * offset1 ,
2012-04-02 20:43:16 +05:30
s32 * row_inc , s32 * pix_inc , int x_predecim , int y_predecim )
2009-11-12 11:41:42 +02:00
{
u8 ps ;
u16 fbw , fbh ;
/* FIXME CLUT formats */
switch ( color_mode ) {
case OMAP_DSS_COLOR_CLUT1 :
case OMAP_DSS_COLOR_CLUT2 :
case OMAP_DSS_COLOR_CLUT4 :
case OMAP_DSS_COLOR_CLUT8 :
BUG ( ) ;
return ;
default :
ps = color_mode_to_bpp ( color_mode ) / 8 ;
break ;
}
DSSDBG ( " calc_rot(%d): scrw %d, %dx%d \n " , rotation , screen_width ,
width , height ) ;
/* width & height are overlay sizes, convert to fb sizes */
if ( rotation = = OMAP_DSS_ROT_0 | | rotation = = OMAP_DSS_ROT_180 ) {
fbw = width ;
fbh = height ;
} else {
fbw = height ;
fbh = width ;
}
/*
* field 0 = even field = bottom field
* field 1 = odd field = top field
*/
switch ( rotation + mirror * 4 ) {
case OMAP_DSS_ROT_0 :
* offset1 = 0 ;
if ( field_offset )
* offset0 = * offset1 + field_offset * screen_width * ps ;
else
* offset0 = * offset1 ;
2012-04-02 20:43:16 +05:30
* row_inc = pixinc ( 1 +
( y_predecim * screen_width - fbw * x_predecim ) +
( fieldmode ? screen_width : 0 ) , ps ) ;
if ( color_mode = = OMAP_DSS_COLOR_YUV2 | |
color_mode = = OMAP_DSS_COLOR_UYVY )
* pix_inc = pixinc ( x_predecim , 2 * ps ) ;
else
* pix_inc = pixinc ( x_predecim , ps ) ;
2009-11-12 11:41:42 +02:00
break ;
case OMAP_DSS_ROT_90 :
* offset1 = screen_width * ( fbh - 1 ) * ps ;
if ( field_offset )
* offset0 = * offset1 + field_offset * ps ;
else
* offset0 = * offset1 ;
2012-04-02 20:43:16 +05:30
* row_inc = pixinc ( screen_width * ( fbh * x_predecim - 1 ) +
y_predecim + ( fieldmode ? 1 : 0 ) , ps ) ;
* pix_inc = pixinc ( - x_predecim * screen_width , ps ) ;
2009-11-12 11:41:42 +02:00
break ;
case OMAP_DSS_ROT_180 :
* offset1 = ( screen_width * ( fbh - 1 ) + fbw - 1 ) * ps ;
if ( field_offset )
* offset0 = * offset1 - field_offset * screen_width * ps ;
else
* offset0 = * offset1 ;
* row_inc = pixinc ( - 1 -
2012-04-02 20:43:16 +05:30
( y_predecim * screen_width - fbw * x_predecim ) -
( fieldmode ? screen_width : 0 ) , ps ) ;
if ( color_mode = = OMAP_DSS_COLOR_YUV2 | |
color_mode = = OMAP_DSS_COLOR_UYVY )
* pix_inc = pixinc ( - x_predecim , 2 * ps ) ;
else
* pix_inc = pixinc ( - x_predecim , ps ) ;
2009-11-12 11:41:42 +02:00
break ;
case OMAP_DSS_ROT_270 :
* offset1 = ( fbw - 1 ) * ps ;
if ( field_offset )
* offset0 = * offset1 - field_offset * ps ;
else
* offset0 = * offset1 ;
2012-04-02 20:43:16 +05:30
* row_inc = pixinc ( - screen_width * ( fbh * x_predecim - 1 ) -
y_predecim - ( fieldmode ? 1 : 0 ) , ps ) ;
* pix_inc = pixinc ( x_predecim * screen_width , ps ) ;
2009-11-12 11:41:42 +02:00
break ;
/* mirroring */
case OMAP_DSS_ROT_0 + 4 :
* offset1 = ( fbw - 1 ) * ps ;
if ( field_offset )
* offset0 = * offset1 + field_offset * screen_width * ps ;
else
* offset0 = * offset1 ;
2012-04-02 20:43:16 +05:30
* row_inc = pixinc ( y_predecim * screen_width * 2 - 1 +
2009-11-12 11:41:42 +02:00
( fieldmode ? screen_width : 0 ) ,
ps ) ;
2012-04-02 20:43:16 +05:30
if ( color_mode = = OMAP_DSS_COLOR_YUV2 | |
color_mode = = OMAP_DSS_COLOR_UYVY )
* pix_inc = pixinc ( - x_predecim , 2 * ps ) ;
else
* pix_inc = pixinc ( - x_predecim , ps ) ;
2009-11-12 11:41:42 +02:00
break ;
case OMAP_DSS_ROT_90 + 4 :
* offset1 = 0 ;
if ( field_offset )
* offset0 = * offset1 + field_offset * ps ;
else
* offset0 = * offset1 ;
2012-04-02 20:43:16 +05:30
* row_inc = pixinc ( - screen_width * ( fbh * x_predecim - 1 ) +
y_predecim + ( fieldmode ? 1 : 0 ) ,
2009-11-12 11:41:42 +02:00
ps ) ;
2012-04-02 20:43:16 +05:30
* pix_inc = pixinc ( x_predecim * screen_width , ps ) ;
2009-11-12 11:41:42 +02:00
break ;
case OMAP_DSS_ROT_180 + 4 :
* offset1 = screen_width * ( fbh - 1 ) * ps ;
if ( field_offset )
* offset0 = * offset1 - field_offset * screen_width * ps ;
else
* offset0 = * offset1 ;
2012-04-02 20:43:16 +05:30
* row_inc = pixinc ( 1 - y_predecim * screen_width * 2 -
2009-11-12 11:41:42 +02:00
( fieldmode ? screen_width : 0 ) ,
ps ) ;
2012-04-02 20:43:16 +05:30
if ( color_mode = = OMAP_DSS_COLOR_YUV2 | |
color_mode = = OMAP_DSS_COLOR_UYVY )
* pix_inc = pixinc ( x_predecim , 2 * ps ) ;
else
* pix_inc = pixinc ( x_predecim , ps ) ;
2009-11-12 11:41:42 +02:00
break ;
case OMAP_DSS_ROT_270 + 4 :
* offset1 = ( screen_width * ( fbh - 1 ) + fbw - 1 ) * ps ;
if ( field_offset )
* offset0 = * offset1 - field_offset * ps ;
else
* offset0 = * offset1 ;
2012-04-02 20:43:16 +05:30
* row_inc = pixinc ( screen_width * ( fbh * x_predecim - 1 ) -
y_predecim - ( fieldmode ? 1 : 0 ) ,
2009-11-12 11:41:42 +02:00
ps ) ;
2012-04-02 20:43:16 +05:30
* pix_inc = pixinc ( - x_predecim * screen_width , ps ) ;
2009-11-12 11:41:42 +02:00
break ;
default :
BUG ( ) ;
2012-05-18 11:47:02 +03:00
return ;
2009-11-12 11:41:42 +02:00
}
}
2012-05-11 19:19:55 +05:30
static void calc_tiler_rotation_offset ( u16 screen_width , u16 width ,
enum omap_color_mode color_mode , bool fieldmode ,
unsigned int field_offset , unsigned * offset0 , unsigned * offset1 ,
s32 * row_inc , s32 * pix_inc , int x_predecim , int y_predecim )
{
u8 ps ;
switch ( color_mode ) {
case OMAP_DSS_COLOR_CLUT1 :
case OMAP_DSS_COLOR_CLUT2 :
case OMAP_DSS_COLOR_CLUT4 :
case OMAP_DSS_COLOR_CLUT8 :
BUG ( ) ;
return ;
default :
ps = color_mode_to_bpp ( color_mode ) / 8 ;
break ;
}
DSSDBG ( " scrw %d, width %d \n " , screen_width , width ) ;
/*
* field 0 = even field = bottom field
* field 1 = odd field = top field
*/
* offset1 = 0 ;
if ( field_offset )
* offset0 = * offset1 + field_offset * screen_width * ps ;
else
* offset0 = * offset1 ;
* row_inc = pixinc ( 1 + ( y_predecim * screen_width - width * x_predecim ) +
( fieldmode ? screen_width : 0 ) , ps ) ;
if ( color_mode = = OMAP_DSS_COLOR_YUV2 | |
color_mode = = OMAP_DSS_COLOR_UYVY )
* pix_inc = pixinc ( x_predecim , 2 * ps ) ;
else
* pix_inc = pixinc ( x_predecim , ps ) ;
}
2012-04-02 20:43:17 +05:30
/*
* This function is used to avoid synclosts in OMAP3 , because of some
* undocumented horizontal position and timing related limitations .
*/
2012-10-19 15:40:24 +03:00
static int check_horiz_timing_omap3 ( unsigned long pclk , unsigned long lclk ,
2012-05-08 15:53:20 +05:30
const struct omap_video_timings * t , u16 pos_x ,
2012-04-02 20:43:17 +05:30
u16 width , u16 height , u16 out_width , u16 out_height )
{
2012-11-05 14:40:19 +02:00
const int ds = DIV_ROUND_UP ( height , out_height ) ;
2012-09-26 16:58:52 +05:30
unsigned long nonactive ;
2012-04-02 20:43:17 +05:30
static const u8 limits [ 3 ] = { 8 , 10 , 20 } ;
u64 val , blank ;
int i ;
2012-05-08 15:53:20 +05:30
nonactive = t - > x_res + t - > hfp + t - > hsw + t - > hbp - out_width ;
2012-04-02 20:43:17 +05:30
i = 0 ;
if ( out_height < height )
i + + ;
if ( out_width < width )
i + + ;
2012-05-08 15:53:20 +05:30
blank = div_u64 ( ( u64 ) ( t - > hbp + t - > hsw + t - > hfp ) * lclk , pclk ) ;
2012-04-02 20:43:17 +05:30
DSSDBG ( " blanking period + ppl = %llu (limit = %u) \n " , blank , limits [ i ] ) ;
if ( blank < = limits [ i ] )
return - EINVAL ;
/*
* Pixel data should be prepared before visible display point starts .
* So , atleast DS - 2 lines must have already been fetched by DISPC
* during nonactive - pos_x period .
*/
val = div_u64 ( ( u64 ) ( nonactive - pos_x ) * lclk , pclk ) ;
DSSDBG ( " (nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d \n " ,
2012-11-05 14:40:19 +02:00
val , max ( 0 , ds - 2 ) * width ) ;
if ( val < max ( 0 , ds - 2 ) * width )
2012-04-02 20:43:17 +05:30
return - EINVAL ;
/*
* All lines need to be refilled during the nonactive period of which
* only one line can be loaded during the active period . So , atleast
* DS - 1 lines should be loaded during nonactive period .
*/
val = div_u64 ( ( u64 ) nonactive * lclk , pclk ) ;
DSSDBG ( " nonactive * pcd = %llu, max(0, DS - 1) * width = %d \n " ,
2012-11-05 14:40:19 +02:00
val , max ( 0 , ds - 1 ) * width ) ;
if ( val < max ( 0 , ds - 1 ) * width )
2012-04-02 20:43:17 +05:30
return - EINVAL ;
return 0 ;
}
2012-10-19 15:36:11 +03:00
static unsigned long calc_core_clk_five_taps ( unsigned long pclk ,
2012-05-08 15:53:20 +05:30
const struct omap_video_timings * mgr_timings , u16 width ,
u16 height , u16 out_width , u16 out_height ,
2010-12-02 11:27:11 +00:00
enum omap_color_mode color_mode )
2009-11-12 11:41:42 +02:00
{
2012-04-23 12:16:50 +05:30
u32 core_clk = 0 ;
2012-09-26 16:58:52 +05:30
u64 tmp ;
2009-11-12 11:41:42 +02:00
2011-12-19 14:03:56 +05:30
if ( height < = out_height & & width < = out_width )
return ( unsigned long ) pclk ;
2009-11-12 11:41:42 +02:00
if ( height > out_height ) {
2012-05-08 15:53:20 +05:30
unsigned int ppl = mgr_timings - > x_res ;
2009-11-12 11:41:42 +02:00
tmp = pclk * height * out_width ;
do_div ( tmp , 2 * out_height * ppl ) ;
2012-04-23 12:16:50 +05:30
core_clk = tmp ;
2009-11-12 11:41:42 +02:00
2010-01-08 11:56:41 +02:00
if ( height > 2 * out_height ) {
if ( ppl = = out_width )
return 0 ;
2009-11-12 11:41:42 +02:00
tmp = pclk * ( height - 2 * out_height ) * out_width ;
do_div ( tmp , 2 * out_height * ( ppl - out_width ) ) ;
2012-04-23 12:16:50 +05:30
core_clk = max_t ( u32 , core_clk , tmp ) ;
2009-11-12 11:41:42 +02:00
}
}
if ( width > out_width ) {
tmp = pclk * width ;
do_div ( tmp , out_width ) ;
2012-04-23 12:16:50 +05:30
core_clk = max_t ( u32 , core_clk , tmp ) ;
2009-11-12 11:41:42 +02:00
if ( color_mode = = OMAP_DSS_COLOR_RGB24U )
2012-04-23 12:16:50 +05:30
core_clk < < = 1 ;
2009-11-12 11:41:42 +02:00
}
2012-04-23 12:16:50 +05:30
return core_clk ;
2009-11-12 11:41:42 +02:00
}
2012-10-19 15:36:11 +03:00
static unsigned long calc_core_clk_24xx ( unsigned long pclk , u16 width ,
2012-09-26 17:00:37 +05:30
u16 height , u16 out_width , u16 out_height , bool mem_to_mem )
2012-07-03 12:26:51 +05:30
{
if ( height > out_height & & width > out_width )
return pclk * 4 ;
else
return pclk * 2 ;
}
2012-10-19 15:36:11 +03:00
static unsigned long calc_core_clk_34xx ( unsigned long pclk , u16 width ,
2012-09-26 17:00:37 +05:30
u16 height , u16 out_width , u16 out_height , bool mem_to_mem )
2009-11-12 11:41:42 +02:00
{
unsigned int hf , vf ;
/*
* FIXME how to determine the ' A ' factor
* for the no downscaling case ?
*/
if ( width > 3 * out_width )
hf = 4 ;
else if ( width > 2 * out_width )
hf = 3 ;
else if ( width > out_width )
hf = 2 ;
else
hf = 1 ;
if ( height > out_height )
vf = 2 ;
else
vf = 1 ;
2012-07-03 12:26:51 +05:30
return pclk * vf * hf ;
}
2012-10-19 15:36:11 +03:00
static unsigned long calc_core_clk_44xx ( unsigned long pclk , u16 width ,
2012-09-26 17:00:37 +05:30
u16 height , u16 out_width , u16 out_height , bool mem_to_mem )
2012-07-03 12:26:51 +05:30
{
2012-09-26 17:00:37 +05:30
/*
* If the overlay / writeback is in mem to mem mode , there are no
* downscaling limitations with respect to pixel clock , return 1 as
* required core clock to represent that we have sufficient enough
* core clock to do maximum downscaling
*/
if ( mem_to_mem )
return 1 ;
2012-07-03 12:26:51 +05:30
if ( width > out_width )
return DIV_ROUND_UP ( pclk , out_width ) * width ;
else
return pclk ;
}
2012-10-19 15:43:29 +03:00
static int dispc_ovl_calc_scaling_24xx ( unsigned long pclk , unsigned long lclk ,
2012-07-03 12:26:51 +05:30
const struct omap_video_timings * mgr_timings ,
u16 width , u16 height , u16 out_width , u16 out_height ,
enum omap_color_mode color_mode , bool * five_taps ,
int * x_predecim , int * y_predecim , int * decim_x , int * decim_y ,
2012-09-26 17:00:37 +05:30
u16 pos_x , unsigned long * core_clk , bool mem_to_mem )
2012-07-03 12:26:51 +05:30
{
int error ;
u16 in_width , in_height ;
int min_factor = min ( * decim_x , * decim_y ) ;
const int maxsinglelinewidth =
dss_feat_get_param_max ( FEAT_PARAM_LINEWIDTH ) ;
2012-09-26 16:58:52 +05:30
2012-07-03 12:26:51 +05:30
* five_taps = false ;
do {
in_height = DIV_ROUND_UP ( height , * decim_y ) ;
in_width = DIV_ROUND_UP ( width , * decim_x ) ;
2012-10-19 15:36:11 +03:00
* core_clk = dispc . feat - > calc_core_clk ( pclk , in_width ,
2012-09-26 17:00:37 +05:30
in_height , out_width , out_height , mem_to_mem ) ;
2012-07-03 12:26:51 +05:30
error = ( in_width > maxsinglelinewidth | | ! * core_clk | |
* core_clk > dispc_core_clk_rate ( ) ) ;
if ( error ) {
if ( * decim_x = = * decim_y ) {
* decim_x = min_factor ;
+ + * decim_y ;
} else {
swap ( * decim_x , * decim_y ) ;
if ( * decim_x < * decim_y )
+ + * decim_x ;
}
}
} while ( * decim_x < = * x_predecim & & * decim_y < = * y_predecim & & error ) ;
if ( in_width > maxsinglelinewidth ) {
DSSERR ( " Cannot scale max input width exceeded " ) ;
return - EINVAL ;
}
return 0 ;
}
2012-10-19 15:43:29 +03:00
static int dispc_ovl_calc_scaling_34xx ( unsigned long pclk , unsigned long lclk ,
2012-07-03 12:26:51 +05:30
const struct omap_video_timings * mgr_timings ,
u16 width , u16 height , u16 out_width , u16 out_height ,
enum omap_color_mode color_mode , bool * five_taps ,
int * x_predecim , int * y_predecim , int * decim_x , int * decim_y ,
2012-09-26 17:00:37 +05:30
u16 pos_x , unsigned long * core_clk , bool mem_to_mem )
2012-07-03 12:26:51 +05:30
{
int error ;
u16 in_width , in_height ;
int min_factor = min ( * decim_x , * decim_y ) ;
const int maxsinglelinewidth =
dss_feat_get_param_max ( FEAT_PARAM_LINEWIDTH ) ;
do {
in_height = DIV_ROUND_UP ( height , * decim_y ) ;
in_width = DIV_ROUND_UP ( width , * decim_x ) ;
2012-10-19 15:36:11 +03:00
* core_clk = calc_core_clk_five_taps ( pclk , mgr_timings ,
2012-07-03 12:26:51 +05:30
in_width , in_height , out_width , out_height , color_mode ) ;
2012-10-19 15:40:24 +03:00
error = check_horiz_timing_omap3 ( pclk , lclk , mgr_timings ,
2012-09-26 16:58:52 +05:30
pos_x , in_width , in_height , out_width ,
out_height ) ;
2012-07-03 12:26:51 +05:30
if ( in_width > maxsinglelinewidth )
if ( in_height > out_height & &
in_height < out_height * 2 )
* five_taps = false ;
if ( ! * five_taps )
2012-10-19 15:36:11 +03:00
* core_clk = dispc . feat - > calc_core_clk ( pclk , in_width ,
2012-09-26 17:00:37 +05:30
in_height , out_width , out_height ,
mem_to_mem ) ;
2012-07-03 12:26:51 +05:30
error = ( error | | in_width > maxsinglelinewidth * 2 | |
( in_width > maxsinglelinewidth & & * five_taps ) | |
! * core_clk | | * core_clk > dispc_core_clk_rate ( ) ) ;
if ( error ) {
if ( * decim_x = = * decim_y ) {
* decim_x = min_factor ;
+ + * decim_y ;
} else {
swap ( * decim_x , * decim_y ) ;
if ( * decim_x < * decim_y )
+ + * decim_x ;
}
}
} while ( * decim_x < = * x_predecim & & * decim_y < = * y_predecim & & error ) ;
2012-10-19 15:40:24 +03:00
if ( check_horiz_timing_omap3 ( pclk , lclk , mgr_timings , pos_x , width ,
height , out_width , out_height ) ) {
2012-07-03 12:26:51 +05:30
DSSERR ( " horizontal timing too tight \n " ) ;
return - EINVAL ;
2011-12-19 14:03:56 +05:30
}
2012-07-03 12:26:51 +05:30
if ( in_width > ( maxsinglelinewidth * 2 ) ) {
DSSERR ( " Cannot setup scaling " ) ;
DSSERR ( " width exceeds maximum width possible " ) ;
return - EINVAL ;
}
if ( in_width > maxsinglelinewidth & & * five_taps ) {
DSSERR ( " cannot setup scaling with five taps " ) ;
return - EINVAL ;
}
return 0 ;
}
2012-10-19 15:43:29 +03:00
static int dispc_ovl_calc_scaling_44xx ( unsigned long pclk , unsigned long lclk ,
2012-07-03 12:26:51 +05:30
const struct omap_video_timings * mgr_timings ,
u16 width , u16 height , u16 out_width , u16 out_height ,
enum omap_color_mode color_mode , bool * five_taps ,
int * x_predecim , int * y_predecim , int * decim_x , int * decim_y ,
2012-09-26 17:00:37 +05:30
u16 pos_x , unsigned long * core_clk , bool mem_to_mem )
2012-07-03 12:26:51 +05:30
{
u16 in_width , in_width_max ;
int decim_x_min = * decim_x ;
u16 in_height = DIV_ROUND_UP ( height , * decim_y ) ;
const int maxsinglelinewidth =
dss_feat_get_param_max ( FEAT_PARAM_LINEWIDTH ) ;
2012-09-26 17:00:37 +05:30
const int maxdownscale = dss_feat_get_param_max ( FEAT_PARAM_DOWNSCALE ) ;
2012-09-26 16:58:52 +05:30
2012-11-07 11:45:02 +05:30
if ( mem_to_mem ) {
in_width_max = out_width * maxdownscale ;
} else {
2012-09-26 17:00:37 +05:30
in_width_max = dispc_core_clk_rate ( ) /
DIV_ROUND_UP ( pclk , out_width ) ;
2012-11-07 11:45:02 +05:30
}
2012-07-03 12:26:51 +05:30
* decim_x = DIV_ROUND_UP ( width , in_width_max ) ;
* decim_x = * decim_x > decim_x_min ? * decim_x : decim_x_min ;
if ( * decim_x > * x_predecim )
return - EINVAL ;
do {
in_width = DIV_ROUND_UP ( width , * decim_x ) ;
} while ( * decim_x < = * x_predecim & &
in_width > maxsinglelinewidth & & + + * decim_x ) ;
if ( in_width > maxsinglelinewidth ) {
DSSERR ( " Cannot scale width exceeds max line width " ) ;
return - EINVAL ;
}
2012-10-19 15:36:11 +03:00
* core_clk = dispc . feat - > calc_core_clk ( pclk , in_width , in_height ,
2012-09-26 17:00:37 +05:30
out_width , out_height , mem_to_mem ) ;
2012-07-03 12:26:51 +05:30
return 0 ;
2009-11-12 11:41:42 +02:00
}
2011-09-08 13:15:11 +05:30
static int dispc_ovl_calc_scaling ( enum omap_plane plane ,
2012-09-26 16:58:52 +05:30
enum omap_overlay_caps caps ,
2012-05-08 15:53:20 +05:30
const struct omap_video_timings * mgr_timings ,
u16 width , u16 height , u16 out_width , u16 out_height ,
2012-04-02 20:43:16 +05:30
enum omap_color_mode color_mode , bool * five_taps ,
2012-09-24 12:08:27 +05:30
int * x_predecim , int * y_predecim , u16 pos_x ,
2012-09-26 17:00:37 +05:30
enum omap_dss_rotation_type rotation_type , bool mem_to_mem )
2011-09-08 13:15:11 +05:30
{
2011-09-08 13:25:17 +05:30
const int maxdownscale = dss_feat_get_param_max ( FEAT_PARAM_DOWNSCALE ) ;
2012-04-02 20:43:16 +05:30
const int max_decim_limit = 16 ;
2012-04-23 12:16:50 +05:30
unsigned long core_clk = 0 ;
2012-07-03 12:26:51 +05:30
int decim_x , decim_y , ret ;
2012-10-19 15:43:29 +03:00
unsigned long pclk = dispc_plane_pclk_rate ( plane ) ;
unsigned long lclk = dispc_plane_lclk_rate ( plane ) ;
2011-09-08 13:15:11 +05:30
2011-11-01 10:50:45 +02:00
if ( width = = out_width & & height = = out_height )
return 0 ;
2012-09-26 16:55:27 +05:30
if ( ( caps & OMAP_DSS_OVL_CAP_SCALE ) = = 0 )
2011-11-01 10:50:45 +02:00
return - EINVAL ;
2011-09-08 13:15:11 +05:30
2012-11-07 11:45:03 +05:30
if ( plane = = OMAP_DSS_WB ) {
* x_predecim = * y_predecim = 1 ;
} else {
* x_predecim = max_decim_limit ;
* y_predecim = ( rotation_type = = OMAP_DSS_ROT_TILER & &
dss_has_feature ( FEAT_BURST_2D ) ) ?
2 : max_decim_limit ;
}
2012-04-02 20:43:16 +05:30
if ( color_mode = = OMAP_DSS_COLOR_CLUT1 | |
color_mode = = OMAP_DSS_COLOR_CLUT2 | |
color_mode = = OMAP_DSS_COLOR_CLUT4 | |
color_mode = = OMAP_DSS_COLOR_CLUT8 ) {
* x_predecim = 1 ;
* y_predecim = 1 ;
* five_taps = false ;
return 0 ;
}
decim_x = DIV_ROUND_UP ( DIV_ROUND_UP ( width , out_width ) , maxdownscale ) ;
decim_y = DIV_ROUND_UP ( DIV_ROUND_UP ( height , out_height ) , maxdownscale ) ;
if ( decim_x > * x_predecim | | out_width > width * 8 )
2011-09-08 13:15:11 +05:30
return - EINVAL ;
2012-04-02 20:43:16 +05:30
if ( decim_y > * y_predecim | | out_height > height * 8 )
2011-09-08 13:15:11 +05:30
return - EINVAL ;
2012-10-19 15:43:29 +03:00
ret = dispc . feat - > calc_scaling ( pclk , lclk , mgr_timings , width , height ,
2012-09-26 16:58:52 +05:30
out_width , out_height , color_mode , five_taps ,
2012-09-26 17:00:37 +05:30
x_predecim , y_predecim , & decim_x , & decim_y , pos_x , & core_clk ,
mem_to_mem ) ;
2012-07-03 12:26:51 +05:30
if ( ret )
return ret ;
2011-09-08 13:15:11 +05:30
2012-04-23 12:16:50 +05:30
DSSDBG ( " required core clk rate = %lu Hz \n " , core_clk ) ;
DSSDBG ( " current core clk rate = %lu Hz \n " , dispc_core_clk_rate ( ) ) ;
2011-09-08 13:15:11 +05:30
2012-04-23 12:16:50 +05:30
if ( ! core_clk | | core_clk > dispc_core_clk_rate ( ) ) {
2011-09-08 13:15:11 +05:30
DSSERR ( " failed to set up scaling, "
2012-04-23 12:16:50 +05:30
" required core clk rate = %lu Hz, "
" current core clk rate = %lu Hz \n " ,
core_clk , dispc_core_clk_rate ( ) ) ;
2011-09-08 13:15:11 +05:30
return - EINVAL ;
}
2012-04-02 20:43:16 +05:30
* x_predecim = decim_x ;
* y_predecim = decim_y ;
2011-09-08 13:15:11 +05:30
return 0 ;
}
2012-09-26 16:57:37 +05:30
static int dispc_ovl_setup_common ( enum omap_plane plane ,
2012-09-26 16:58:52 +05:30
enum omap_overlay_caps caps , u32 paddr , u32 p_uv_addr ,
u16 screen_width , int pos_x , int pos_y , u16 width , u16 height ,
u16 out_width , u16 out_height , enum omap_color_mode color_mode ,
u8 rotation , bool mirror , u8 zorder , u8 pre_mult_alpha ,
u8 global_alpha , enum omap_dss_rotation_type rotation_type ,
2012-09-26 17:00:37 +05:30
bool replication , const struct omap_video_timings * mgr_timings ,
bool mem_to_mem )
2009-11-12 11:41:42 +02:00
{
2011-12-19 14:03:56 +05:30
bool five_taps = true ;
2009-11-12 11:41:42 +02:00
bool fieldmode = 0 ;
2011-09-08 13:15:11 +05:30
int r , cconv = 0 ;
2009-11-12 11:41:42 +02:00
unsigned offset0 , offset1 ;
s32 row_inc ;
s32 pix_inc ;
2012-11-07 11:45:04 +05:30
u16 frame_width , frame_height ;
2009-11-12 11:41:42 +02:00
unsigned int field_offset = 0 ;
2012-09-26 16:57:37 +05:30
u16 in_height = height ;
u16 in_width = width ;
2012-04-02 20:43:16 +05:30
int x_predecim = 1 , y_predecim = 1 ;
2012-06-06 16:25:52 +05:30
bool ilace = mgr_timings - > interlace ;
2011-05-19 14:12:26 +03:00
2012-09-26 16:57:37 +05:30
if ( paddr = = 0 )
2009-11-12 11:41:42 +02:00
return - EINVAL ;
2012-09-26 16:57:37 +05:30
out_width = out_width = = 0 ? width : out_width ;
out_height = out_height = = 0 ? height : out_height ;
2011-11-03 16:08:27 +02:00
2012-09-26 16:57:37 +05:30
if ( ilace & & height = = out_height )
2009-11-12 11:41:42 +02:00
fieldmode = 1 ;
if ( ilace ) {
if ( fieldmode )
2012-04-02 20:43:16 +05:30
in_height / = 2 ;
2012-08-22 12:33:49 +05:30
pos_y / = 2 ;
2012-04-02 20:43:16 +05:30
out_height / = 2 ;
2009-11-12 11:41:42 +02:00
DSSDBG ( " adjusting for ilace: height %d, pos_y %d, "
2012-09-26 16:57:37 +05:30
" out_height %d \n " , in_height , pos_y ,
out_height ) ;
2009-11-12 11:41:42 +02:00
}
2012-09-26 16:57:37 +05:30
if ( ! dss_feat_color_mode_supported ( plane , color_mode ) )
2010-11-25 17:58:10 +05:30
return - EINVAL ;
2012-09-26 16:58:52 +05:30
r = dispc_ovl_calc_scaling ( plane , caps , mgr_timings , in_width ,
2012-09-26 16:57:37 +05:30
in_height , out_width , out_height , color_mode ,
& five_taps , & x_predecim , & y_predecim , pos_x ,
2012-09-26 17:00:37 +05:30
rotation_type , mem_to_mem ) ;
2011-09-08 13:15:11 +05:30
if ( r )
return r ;
2009-11-12 11:41:42 +02:00
2012-04-02 20:43:16 +05:30
in_width = DIV_ROUND_UP ( in_width , x_predecim ) ;
in_height = DIV_ROUND_UP ( in_height , y_predecim ) ;
2012-09-26 16:57:37 +05:30
if ( color_mode = = OMAP_DSS_COLOR_YUV2 | |
color_mode = = OMAP_DSS_COLOR_UYVY | |
color_mode = = OMAP_DSS_COLOR_NV12 )
2011-09-08 13:15:11 +05:30
cconv = 1 ;
2009-11-12 11:41:42 +02:00
if ( ilace & & ! fieldmode ) {
/*
* when downscaling the bottom field may have to start several
* source lines below the top field . Unfortunately ACCUI
* registers will only hold the fractional part of the offset
* so the integer part must be added to the base address of the
* bottom field .
*/
2012-04-02 20:43:16 +05:30
if ( ! in_height | | in_height = = out_height )
2009-11-12 11:41:42 +02:00
field_offset = 0 ;
else
2012-04-02 20:43:16 +05:30
field_offset = in_height / out_height / 2 ;
2009-11-12 11:41:42 +02:00
}
/* Fields are independent but interleaved in memory. */
if ( fieldmode )
field_offset = 1 ;
2012-05-18 11:47:02 +03:00
offset0 = 0 ;
offset1 = 0 ;
row_inc = 0 ;
pix_inc = 0 ;
2012-11-07 11:45:04 +05:30
if ( plane = = OMAP_DSS_WB ) {
frame_width = out_width ;
frame_height = out_height ;
} else {
frame_width = in_width ;
frame_height = height ;
}
2012-09-26 16:57:37 +05:30
if ( rotation_type = = OMAP_DSS_ROT_TILER )
2012-11-07 11:45:04 +05:30
calc_tiler_rotation_offset ( screen_width , frame_width ,
2012-09-26 16:57:37 +05:30
color_mode , fieldmode , field_offset ,
2012-05-11 19:19:55 +05:30
& offset0 , & offset1 , & row_inc , & pix_inc ,
x_predecim , y_predecim ) ;
2012-09-26 16:57:37 +05:30
else if ( rotation_type = = OMAP_DSS_ROT_DMA )
2012-11-07 11:45:04 +05:30
calc_dma_rotation_offset ( rotation , mirror , screen_width ,
frame_width , frame_height ,
2012-09-26 16:57:37 +05:30
color_mode , fieldmode , field_offset ,
2012-04-02 20:43:16 +05:30
& offset0 , & offset1 , & row_inc , & pix_inc ,
x_predecim , y_predecim ) ;
2009-11-12 11:41:42 +02:00
else
2012-09-26 16:57:37 +05:30
calc_vrfb_rotation_offset ( rotation , mirror ,
2012-11-07 11:45:04 +05:30
screen_width , frame_width , frame_height ,
2012-09-26 16:57:37 +05:30
color_mode , fieldmode , field_offset ,
2012-04-02 20:43:16 +05:30
& offset0 , & offset1 , & row_inc , & pix_inc ,
x_predecim , y_predecim ) ;
2009-11-12 11:41:42 +02:00
DSSDBG ( " offset0 %u, offset1 %u, row_inc %d, pix_inc %d \n " ,
offset0 , offset1 , row_inc , pix_inc ) ;
2012-09-26 16:57:37 +05:30
dispc_ovl_set_color_mode ( plane , color_mode ) ;
2009-11-12 11:41:42 +02:00
2012-09-26 16:57:37 +05:30
dispc_ovl_configure_burst_type ( plane , rotation_type ) ;
2012-05-11 19:19:55 +05:30
2012-09-26 16:57:37 +05:30
dispc_ovl_set_ba0 ( plane , paddr + offset0 ) ;
dispc_ovl_set_ba1 ( plane , paddr + offset1 ) ;
2009-11-12 11:41:42 +02:00
2012-09-26 16:57:37 +05:30
if ( OMAP_DSS_COLOR_NV12 = = color_mode ) {
dispc_ovl_set_ba0_uv ( plane , p_uv_addr + offset0 ) ;
dispc_ovl_set_ba1_uv ( plane , p_uv_addr + offset1 ) ;
2011-05-19 19:47:54 +05:30
}
2011-08-16 13:25:00 +03:00
dispc_ovl_set_row_inc ( plane , row_inc ) ;
dispc_ovl_set_pix_inc ( plane , pix_inc ) ;
2009-11-12 11:41:42 +02:00
2012-09-26 16:57:37 +05:30
DSSDBG ( " %d,%d %dx%d -> %dx%d \n " , pos_x , pos_y , in_width ,
2012-04-02 20:43:16 +05:30
in_height , out_width , out_height ) ;
2009-11-12 11:41:42 +02:00
2012-09-26 16:57:37 +05:30
dispc_ovl_set_pos ( plane , caps , pos_x , pos_y ) ;
2009-11-12 11:41:42 +02:00
2012-09-21 14:51:49 +05:30
dispc_ovl_set_input_size ( plane , in_width , in_height ) ;
2009-11-12 11:41:42 +02:00
2012-09-26 16:55:27 +05:30
if ( caps & OMAP_DSS_OVL_CAP_SCALE ) {
2012-04-02 20:43:16 +05:30
dispc_ovl_set_scaling ( plane , in_width , in_height , out_width ,
out_height , ilace , five_taps , fieldmode ,
2012-09-26 16:57:37 +05:30
color_mode , rotation ) ;
2012-09-21 14:51:49 +05:30
dispc_ovl_set_output_size ( plane , out_width , out_height ) ;
2011-08-16 13:25:00 +03:00
dispc_ovl_set_vid_color_conv ( plane , cconv ) ;
2009-11-12 11:41:42 +02:00
}
2012-09-26 16:57:37 +05:30
dispc_ovl_set_rotation_attrs ( plane , rotation , mirror , color_mode ) ;
2009-11-12 11:41:42 +02:00
2012-09-26 16:57:37 +05:30
dispc_ovl_set_zorder ( plane , caps , zorder ) ;
dispc_ovl_set_pre_mult_alpha ( plane , caps , pre_mult_alpha ) ;
dispc_ovl_setup_global_alpha ( plane , caps , global_alpha ) ;
2009-11-12 11:41:42 +02:00
2012-09-22 12:30:17 +05:30
dispc_ovl_enable_replication ( plane , caps , replication ) ;
2011-09-14 11:52:54 +05:30
2009-11-12 11:41:42 +02:00
return 0 ;
}
2012-09-26 16:57:37 +05:30
int dispc_ovl_setup ( enum omap_plane plane , const struct omap_overlay_info * oi ,
2012-09-26 17:00:37 +05:30
bool replication , const struct omap_video_timings * mgr_timings ,
bool mem_to_mem )
2012-09-26 16:57:37 +05:30
{
int r ;
2012-10-15 15:33:22 +03:00
enum omap_overlay_caps caps = dss_feat_get_overlay_caps ( plane ) ;
2012-09-26 16:57:37 +05:30
enum omap_channel channel ;
channel = dispc_ovl_get_channel_out ( plane ) ;
DSSDBG ( " dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
" %dx%d, cmode %x, rot %d, mir %d, chan %d repl %d \n " ,
plane , oi - > paddr , oi - > p_uv_addr , oi - > screen_width , oi - > pos_x ,
oi - > pos_y , oi - > width , oi - > height , oi - > out_width , oi - > out_height ,
oi - > color_mode , oi - > rotation , oi - > mirror , channel , replication ) ;
2012-10-15 15:33:22 +03:00
r = dispc_ovl_setup_common ( plane , caps , oi - > paddr , oi - > p_uv_addr ,
2012-09-26 16:58:52 +05:30
oi - > screen_width , oi - > pos_x , oi - > pos_y , oi - > width , oi - > height ,
oi - > out_width , oi - > out_height , oi - > color_mode , oi - > rotation ,
oi - > mirror , oi - > zorder , oi - > pre_mult_alpha , oi - > global_alpha ,
2012-09-26 17:00:37 +05:30
oi - > rotation_type , replication , mgr_timings , mem_to_mem ) ;
2012-09-26 16:57:37 +05:30
return r ;
}
2012-08-31 12:32:52 +05:30
int dispc_wb_setup ( const struct omap_dss_writeback_info * wi ,
2012-08-24 16:59:26 +05:30
bool mem_to_mem , const struct omap_video_timings * mgr_timings )
2012-08-31 12:32:52 +05:30
{
int r ;
2012-08-24 16:59:26 +05:30
u32 l ;
2012-08-31 12:32:52 +05:30
enum omap_plane plane = OMAP_DSS_WB ;
const int pos_x = 0 , pos_y = 0 ;
const u8 zorder = 0 , global_alpha = 0 ;
const bool replication = false ;
2012-08-24 16:59:26 +05:30
bool truncation ;
2012-08-31 12:32:52 +05:30
int in_width = mgr_timings - > x_res ;
int in_height = mgr_timings - > y_res ;
enum omap_overlay_caps caps =
OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA ;
DSSDBG ( " dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, "
" rot %d, mir %d \n " , wi - > paddr , wi - > p_uv_addr , in_width ,
in_height , wi - > width , wi - > height , wi - > color_mode , wi - > rotation ,
wi - > mirror ) ;
r = dispc_ovl_setup_common ( plane , caps , wi - > paddr , wi - > p_uv_addr ,
wi - > buf_width , pos_x , pos_y , in_width , in_height , wi - > width ,
wi - > height , wi - > color_mode , wi - > rotation , wi - > mirror , zorder ,
wi - > pre_mult_alpha , global_alpha , wi - > rotation_type ,
2012-08-24 16:59:26 +05:30
replication , mgr_timings , mem_to_mem ) ;
switch ( wi - > color_mode ) {
case OMAP_DSS_COLOR_RGB16 :
case OMAP_DSS_COLOR_RGB24P :
case OMAP_DSS_COLOR_ARGB16 :
case OMAP_DSS_COLOR_RGBA16 :
case OMAP_DSS_COLOR_RGB12U :
case OMAP_DSS_COLOR_ARGB16_1555 :
case OMAP_DSS_COLOR_XRGB16_1555 :
case OMAP_DSS_COLOR_RGBX16 :
truncation = true ;
break ;
default :
truncation = false ;
break ;
}
/* setup extra DISPC_WB_ATTRIBUTES */
l = dispc_read_reg ( DISPC_OVL_ATTRIBUTES ( plane ) ) ;
l = FLD_MOD ( l , truncation , 10 , 10 ) ; /* TRUNCATIONENABLE */
l = FLD_MOD ( l , mem_to_mem , 19 , 19 ) ; /* WRITEBACKMODE */
dispc_write_reg ( DISPC_OVL_ATTRIBUTES ( plane ) , l ) ;
2012-08-31 12:32:52 +05:30
return r ;
}
2011-08-16 13:25:00 +03:00
int dispc_ovl_enable ( enum omap_plane plane , bool enable )
2009-11-12 11:41:42 +02:00
{
2011-05-19 14:12:26 +03:00
DSSDBG ( " dispc_enable_plane %d, %d \n " , plane , enable ) ;
2011-05-06 11:45:49 +05:30
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( plane ) , enable ? 1 : 0 , 0 , 0 ) ;
2011-05-19 14:12:26 +03:00
return 0 ;
2009-11-12 11:41:42 +02:00
}
2012-10-10 14:13:15 +03:00
bool dispc_ovl_enabled ( enum omap_plane plane )
{
return REG_GET ( DISPC_OVL_ATTRIBUTES ( plane ) , 0 , 0 ) ;
}
2012-10-10 12:48:31 +03:00
static void dispc_mgr_disable_isr ( void * data , u32 mask )
2009-11-12 11:41:42 +02:00
{
struct completion * compl = data ;
complete ( compl ) ;
}
2012-10-19 14:16:06 +03:00
void dispc_mgr_enable ( enum omap_channel channel , bool enable )
2009-11-12 11:41:42 +02:00
{
2012-06-21 11:07:44 +05:30
mgr_fld_write ( channel , DISPC_MGR_FLD_ENABLE , enable ) ;
/* flush posted write */
mgr_fld_read ( channel , DISPC_MGR_FLD_ENABLE ) ;
2009-11-12 11:41:42 +02:00
}
2012-10-10 11:44:17 +03:00
bool dispc_mgr_is_enabled ( enum omap_channel channel )
{
return ! ! mgr_fld_read ( channel , DISPC_MGR_FLD_ENABLE ) ;
}
2012-10-10 12:48:31 +03:00
static void dispc_mgr_enable_lcd_out ( enum omap_channel channel )
2009-11-12 11:41:42 +02:00
{
2012-10-19 14:16:06 +03:00
dispc_mgr_enable ( channel , true ) ;
2012-10-10 12:48:31 +03:00
}
static void dispc_mgr_disable_lcd_out ( enum omap_channel channel )
{
DECLARE_COMPLETION_ONSTACK ( framedone_compl ) ;
2009-11-12 11:41:42 +02:00
int r ;
2010-12-02 11:27:12 +00:00
u32 irq ;
2009-11-12 11:41:42 +02:00
2012-10-10 12:48:31 +03:00
if ( dispc_mgr_is_enabled ( channel ) = = false )
return ;
2010-12-02 11:27:12 +00:00
2012-10-10 12:48:31 +03:00
/*
* When we disable LCD output , we need to wait for FRAMEDONE to know
* that DISPC has finished with the LCD output .
*/
2009-11-12 11:41:42 +02:00
2012-10-10 12:48:31 +03:00
irq = dispc_mgr_get_framedone_irq ( channel ) ;
2009-11-12 11:41:42 +02:00
2012-10-10 12:48:31 +03:00
r = omap_dispc_register_isr ( dispc_mgr_disable_isr , & framedone_compl ,
irq ) ;
if ( r )
DSSERR ( " failed to register FRAMEDONE isr \n " ) ;
2009-11-12 11:41:42 +02:00
2012-10-19 14:16:06 +03:00
dispc_mgr_enable ( channel , false ) ;
2012-10-10 12:48:31 +03:00
/* if we couldn't register for framedone, just sleep and exit */
if ( r ) {
msleep ( 100 ) ;
return ;
2009-11-12 11:41:42 +02:00
}
2012-10-10 12:48:31 +03:00
if ( ! wait_for_completion_timeout ( & framedone_compl ,
msecs_to_jiffies ( 100 ) ) )
DSSERR ( " timeout waiting for FRAME DONE \n " ) ;
2009-11-12 11:41:42 +02:00
2012-10-10 12:48:31 +03:00
r = omap_dispc_unregister_isr ( dispc_mgr_disable_isr , & framedone_compl ,
irq ) ;
if ( r )
DSSERR ( " failed to unregister FRAMEDONE isr \n " ) ;
}
2009-11-12 11:41:42 +02:00
2012-10-10 12:48:31 +03:00
static void dispc_digit_out_enable_isr ( void * data , u32 mask )
{
struct completion * compl = data ;
2009-11-12 11:41:42 +02:00
2012-10-10 12:48:31 +03:00
/* ignore any sync lost interrupts */
if ( mask & ( DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD ) )
complete ( compl ) ;
}
static void dispc_mgr_enable_digit_out ( void )
{
DECLARE_COMPLETION_ONSTACK ( vsync_compl ) ;
int r ;
u32 irq_mask ;
if ( dispc_mgr_is_enabled ( OMAP_DSS_CHANNEL_DIGIT ) = = true )
return ;
/*
* Digit output produces some sync lost interrupts during the first
* frame when enabling . Those need to be ignored , so we register for the
* sync lost irq to prevent the error handler from triggering .
*/
irq_mask = dispc_mgr_get_vsync_irq ( OMAP_DSS_CHANNEL_DIGIT ) |
dispc_mgr_get_sync_lost_irq ( OMAP_DSS_CHANNEL_DIGIT ) ;
r = omap_dispc_register_isr ( dispc_digit_out_enable_isr , & vsync_compl ,
irq_mask ) ;
if ( r ) {
DSSERR ( " failed to register %x isr \n " , irq_mask ) ;
return ;
2009-11-12 11:41:42 +02:00
}
2012-10-10 12:48:31 +03:00
2012-10-19 14:16:06 +03:00
dispc_mgr_enable ( OMAP_DSS_CHANNEL_DIGIT , true ) ;
2012-10-10 12:48:31 +03:00
/* wait for the first evsync */
if ( ! wait_for_completion_timeout ( & vsync_compl , msecs_to_jiffies ( 100 ) ) )
DSSERR ( " timeout waiting for digit out to start \n " ) ;
r = omap_dispc_unregister_isr ( dispc_digit_out_enable_isr , & vsync_compl ,
irq_mask ) ;
if ( r )
DSSERR ( " failed to unregister %x isr \n " , irq_mask ) ;
2009-11-12 11:41:42 +02:00
}
2012-10-10 12:48:31 +03:00
static void dispc_mgr_disable_digit_out ( void )
2009-11-12 11:41:42 +02:00
{
2012-10-10 12:48:31 +03:00
DECLARE_COMPLETION_ONSTACK ( framedone_compl ) ;
2011-08-31 14:42:49 +03:00
int r , i ;
u32 irq_mask ;
int num_irqs ;
2009-11-12 11:41:42 +02:00
2012-10-10 12:48:31 +03:00
if ( dispc_mgr_is_enabled ( OMAP_DSS_CHANNEL_DIGIT ) = = false )
2009-11-12 11:41:42 +02:00
return ;
2012-10-10 12:48:31 +03:00
/*
* When we disable the digit output , we need to wait for FRAMEDONE to
2012-11-08 10:05:31 +02:00
* know that DISPC has finished with the output .
2012-10-10 12:48:31 +03:00
*/
2009-11-12 11:41:42 +02:00
2012-11-08 10:05:31 +02:00
irq_mask = dispc_mgr_get_framedone_irq ( OMAP_DSS_CHANNEL_DIGIT ) ;
num_irqs = 1 ;
if ( ! irq_mask ) {
/*
* omap 2 / 3 don ' t have framedone irq for TV , so we need to use
* vsyncs for this .
*/
2012-10-10 12:48:31 +03:00
irq_mask = dispc_mgr_get_vsync_irq ( OMAP_DSS_CHANNEL_DIGIT ) ;
/*
* We need to wait for both even and odd vsyncs . Note that this
* is not totally reliable , as we could get a vsync interrupt
* before we disable the output , which leads to timeout in the
* wait_for_completion .
*/
2011-08-31 14:42:49 +03:00
num_irqs = 2 ;
}
2012-10-10 12:48:31 +03:00
r = omap_dispc_register_isr ( dispc_mgr_disable_isr , & framedone_compl ,
2011-08-31 14:42:49 +03:00
irq_mask ) ;
2009-11-12 11:41:42 +02:00
if ( r )
2011-08-31 14:42:49 +03:00
DSSERR ( " failed to register %x isr \n " , irq_mask ) ;
2009-11-12 11:41:42 +02:00
2012-10-19 14:16:06 +03:00
dispc_mgr_enable ( OMAP_DSS_CHANNEL_DIGIT , false ) ;
2012-10-10 12:48:31 +03:00
/* if we couldn't register the irq, just sleep and exit */
if ( r ) {
msleep ( 100 ) ;
return ;
}
2009-11-12 11:41:42 +02:00
2011-08-31 14:42:49 +03:00
for ( i = 0 ; i < num_irqs ; + + i ) {
2012-10-10 12:48:31 +03:00
if ( ! wait_for_completion_timeout ( & framedone_compl ,
2011-08-31 14:42:49 +03:00
msecs_to_jiffies ( 100 ) ) )
2012-10-10 12:48:31 +03:00
DSSERR ( " timeout waiting for digit out to stop \n " ) ;
2011-08-31 14:42:49 +03:00
}
2009-11-12 11:41:42 +02:00
2012-10-10 12:48:31 +03:00
r = omap_dispc_unregister_isr ( dispc_mgr_disable_isr , & framedone_compl ,
2011-08-31 14:42:49 +03:00
irq_mask ) ;
2009-11-12 11:41:42 +02:00
if ( r )
2011-08-31 14:42:49 +03:00
DSSERR ( " failed to unregister %x isr \n " , irq_mask ) ;
2012-10-10 12:48:31 +03:00
}
2009-11-12 11:41:42 +02:00
2012-10-19 14:14:38 +03:00
void dispc_mgr_enable_sync ( enum omap_channel channel )
2012-10-10 12:48:31 +03:00
{
if ( dss_mgr_is_lcd ( channel ) )
dispc_mgr_enable_lcd_out ( channel ) ;
else if ( channel = = OMAP_DSS_CHANNEL_DIGIT )
dispc_mgr_enable_digit_out ( ) ;
else
WARN_ON ( 1 ) ;
2009-11-12 11:41:42 +02:00
}
2012-10-19 14:14:38 +03:00
void dispc_mgr_disable_sync ( enum omap_channel channel )
2010-01-08 17:14:53 +02:00
{
2012-06-29 14:41:30 +05:30
if ( dss_mgr_is_lcd ( channel ) )
2012-10-10 12:48:31 +03:00
dispc_mgr_disable_lcd_out ( channel ) ;
2010-01-08 17:14:53 +02:00
else if ( channel = = OMAP_DSS_CHANNEL_DIGIT )
2012-10-10 12:48:31 +03:00
dispc_mgr_disable_digit_out ( ) ;
2010-01-08 17:14:53 +02:00
else
2012-10-10 12:48:31 +03:00
WARN_ON ( 1 ) ;
2010-01-08 17:14:53 +02:00
}
2012-09-22 12:39:33 +05:30
void dispc_wb_enable ( bool enable )
{
2012-10-10 14:13:26 +03:00
dispc_ovl_enable ( OMAP_DSS_WB , enable ) ;
2012-09-22 12:39:33 +05:30
}
bool dispc_wb_is_enabled ( void )
{
2012-10-10 14:13:26 +03:00
return dispc_ovl_enabled ( OMAP_DSS_WB ) ;
2012-09-22 12:39:33 +05:30
}
2012-09-12 13:30:39 +03:00
static void dispc_lcd_enable_signal_polarity ( bool act_high )
2009-11-12 11:41:42 +02:00
{
2010-12-02 11:27:13 +00:00
if ( ! dss_has_feature ( FEAT_LCDENABLEPOL ) )
return ;
2009-11-12 11:41:42 +02:00
REG_FLD_MOD ( DISPC_CONTROL , act_high ? 1 : 0 , 29 , 29 ) ;
}
void dispc_lcd_enable_signal ( bool enable )
{
2010-12-02 11:27:13 +00:00
if ( ! dss_has_feature ( FEAT_LCDENABLESIGNAL ) )
return ;
2009-11-12 11:41:42 +02:00
REG_FLD_MOD ( DISPC_CONTROL , enable ? 1 : 0 , 28 , 28 ) ;
}
void dispc_pck_free_enable ( bool enable )
{
2010-12-02 11:27:13 +00:00
if ( ! dss_has_feature ( FEAT_PCKFREEENABLE ) )
return ;
2009-11-12 11:41:42 +02:00
REG_FLD_MOD ( DISPC_CONTROL , enable ? 1 : 0 , 27 , 27 ) ;
}
2012-09-12 13:30:39 +03:00
static void dispc_mgr_enable_fifohandcheck ( enum omap_channel channel , bool enable )
2009-11-12 11:41:42 +02:00
{
2012-06-21 11:07:44 +05:30
mgr_fld_write ( channel , DISPC_MGR_FLD_FIFOHANDCHECK , enable ) ;
2009-11-12 11:41:42 +02:00
}
2012-09-12 13:30:39 +03:00
static void dispc_mgr_set_lcd_type_tft ( enum omap_channel channel )
2009-11-12 11:41:42 +02:00
{
2012-06-21 09:45:11 +05:30
mgr_fld_write ( channel , DISPC_MGR_FLD_STNTFT , 1 ) ;
2009-11-12 11:41:42 +02:00
}
void dispc_set_loadmode ( enum omap_dss_load_mode mode )
{
REG_FLD_MOD ( DISPC_CONFIG , mode , 2 , 1 ) ;
}
2011-11-04 18:14:20 +02:00
static void dispc_mgr_set_default_color ( enum omap_channel channel , u32 color )
2009-11-12 11:41:42 +02:00
{
OMAP: DSS2: Represent DISPC register defines with channel as parameter
On OMAP4, we have a new DISPC channel for Overlay Manager LCD2. There is a set
of regsiters for LCD2 channel similar to the existing LCD channel, like
DISPC_CONTROL2, DISPC_DIVISOR2, DISPC_CONFIG2 and so on.
Introduce new enum members for LCD2 Channel and corresponding Overlay Manager
in display.h.
Represent the following DISPC register defines with channel as a parameter
to differentiate between LCD and LCD2 registers (and also DIGIT in some cases):
DISPC_DEFAULT_COLOR, DISPC_TRANS_COLOR, DISPC_TIMING_H, DISPC_TIMING_V,
DISPC_POL_FREQ, DISPC_DIVISOR, DISPC_SIZE_LCD, DISPC_DATA_CYCLEk,
DISPC_CPR_COEF_R, DISPC_CPR_COEF_G and DISPC_CPR_COEF_B
This parametrization helps in reducing the number of register defines for DISPC.
Replace the existing reads/writes to these registers in this new way.
Also, Introduce defines for registers DISPC_CONTROL2 and DISPC_CONFIG2 which
are used exclusively for LCD2 channel.
Signed-off-by: Sumit Semwal <sumit.semwal@ti.com>
Signed-off-by: Mukund Mittal <mmittal@ti.com>
Signed-off-by: Samreen <samreen@ti.com>
Signed-off-by: Archit Taneja <archit@ti.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
2010-12-02 11:27:09 +00:00
dispc_write_reg ( DISPC_DEFAULT_COLOR ( channel ) , color ) ;
2009-11-12 11:41:42 +02:00
}
2011-11-04 18:14:20 +02:00
static void dispc_mgr_set_trans_key ( enum omap_channel ch ,
2009-11-12 11:41:42 +02:00
enum omap_dss_trans_key_type type ,
u32 trans_key )
{
2012-06-21 11:07:44 +05:30
mgr_fld_write ( ch , DISPC_MGR_FLD_TCKSELECTION , type ) ;
2009-11-12 11:41:42 +02:00
OMAP: DSS2: Represent DISPC register defines with channel as parameter
On OMAP4, we have a new DISPC channel for Overlay Manager LCD2. There is a set
of regsiters for LCD2 channel similar to the existing LCD channel, like
DISPC_CONTROL2, DISPC_DIVISOR2, DISPC_CONFIG2 and so on.
Introduce new enum members for LCD2 Channel and corresponding Overlay Manager
in display.h.
Represent the following DISPC register defines with channel as a parameter
to differentiate between LCD and LCD2 registers (and also DIGIT in some cases):
DISPC_DEFAULT_COLOR, DISPC_TRANS_COLOR, DISPC_TIMING_H, DISPC_TIMING_V,
DISPC_POL_FREQ, DISPC_DIVISOR, DISPC_SIZE_LCD, DISPC_DATA_CYCLEk,
DISPC_CPR_COEF_R, DISPC_CPR_COEF_G and DISPC_CPR_COEF_B
This parametrization helps in reducing the number of register defines for DISPC.
Replace the existing reads/writes to these registers in this new way.
Also, Introduce defines for registers DISPC_CONTROL2 and DISPC_CONFIG2 which
are used exclusively for LCD2 channel.
Signed-off-by: Sumit Semwal <sumit.semwal@ti.com>
Signed-off-by: Mukund Mittal <mmittal@ti.com>
Signed-off-by: Samreen <samreen@ti.com>
Signed-off-by: Archit Taneja <archit@ti.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
2010-12-02 11:27:09 +00:00
dispc_write_reg ( DISPC_TRANS_COLOR ( ch ) , trans_key ) ;
2009-11-12 11:41:42 +02:00
}
2011-11-04 18:14:20 +02:00
static void dispc_mgr_enable_trans_key ( enum omap_channel ch , bool enable )
2009-11-12 11:41:42 +02:00
{
2012-06-21 11:07:44 +05:30
mgr_fld_write ( ch , DISPC_MGR_FLD_TCKENABLE , enable ) ;
2009-11-12 11:41:42 +02:00
}
2011-09-26 11:47:29 +05:30
2011-11-04 18:14:20 +02:00
static void dispc_mgr_enable_alpha_fixed_zorder ( enum omap_channel ch ,
bool enable )
2009-11-12 11:41:42 +02:00
{
2011-09-26 11:47:29 +05:30
if ( ! dss_has_feature ( FEAT_ALPHA_FIXED_ZORDER ) )
2009-11-12 11:41:42 +02:00
return ;
if ( ch = = OMAP_DSS_CHANNEL_LCD )
REG_FLD_MOD ( DISPC_CONFIG , enable , 18 , 18 ) ;
2010-12-02 11:27:12 +00:00
else if ( ch = = OMAP_DSS_CHANNEL_DIGIT )
2009-11-12 11:41:42 +02:00
REG_FLD_MOD ( DISPC_CONFIG , enable , 19 , 19 ) ;
}
2011-09-26 11:47:29 +05:30
2011-11-04 18:14:20 +02:00
void dispc_mgr_setup ( enum omap_channel channel ,
2012-10-03 09:09:11 +02:00
const struct omap_overlay_manager_info * info )
2011-11-04 18:14:20 +02:00
{
dispc_mgr_set_default_color ( channel , info - > default_color ) ;
dispc_mgr_set_trans_key ( channel , info - > trans_key_type , info - > trans_key ) ;
dispc_mgr_enable_trans_key ( channel , info - > trans_enabled ) ;
dispc_mgr_enable_alpha_fixed_zorder ( channel ,
info - > partial_alpha_enabled ) ;
if ( dss_has_feature ( FEAT_CPR ) ) {
dispc_mgr_enable_cpr ( channel , info - > cpr_enable ) ;
dispc_mgr_set_cpr_coef ( channel , & info - > cpr_coefs ) ;
}
}
2009-11-12 11:41:42 +02:00
2012-09-12 13:30:39 +03:00
static void dispc_mgr_set_tft_data_lines ( enum omap_channel channel , u8 data_lines )
2009-11-12 11:41:42 +02:00
{
int code ;
switch ( data_lines ) {
case 12 :
code = 0 ;
break ;
case 16 :
code = 1 ;
break ;
case 18 :
code = 2 ;
break ;
case 24 :
code = 3 ;
break ;
default :
BUG ( ) ;
return ;
}
2012-06-21 11:07:44 +05:30
mgr_fld_write ( channel , DISPC_MGR_FLD_TFTDATALINES , code ) ;
2009-11-12 11:41:42 +02:00
}
2012-09-12 13:30:39 +03:00
static void dispc_mgr_set_io_pad_mode ( enum dss_io_pad_mode mode )
2009-11-12 11:41:42 +02:00
{
u32 l ;
2011-08-22 17:41:57 +05:30
int gpout0 , gpout1 ;
2009-11-12 11:41:42 +02:00
switch ( mode ) {
2011-08-22 17:41:57 +05:30
case DSS_IO_PAD_MODE_RESET :
gpout0 = 0 ;
gpout1 = 0 ;
2009-11-12 11:41:42 +02:00
break ;
2011-08-22 17:41:57 +05:30
case DSS_IO_PAD_MODE_RFBI :
gpout0 = 1 ;
2009-11-12 11:41:42 +02:00
gpout1 = 0 ;
break ;
2011-08-22 17:41:57 +05:30
case DSS_IO_PAD_MODE_BYPASS :
gpout0 = 1 ;
2009-11-12 11:41:42 +02:00
gpout1 = 1 ;
break ;
default :
BUG ( ) ;
return ;
}
2011-08-22 17:41:57 +05:30
l = dispc_read_reg ( DISPC_CONTROL ) ;
l = FLD_MOD ( l , gpout0 , 15 , 15 ) ;
l = FLD_MOD ( l , gpout1 , 16 , 16 ) ;
dispc_write_reg ( DISPC_CONTROL , l ) ;
}
2012-09-12 13:30:39 +03:00
static void dispc_mgr_enable_stallmode ( enum omap_channel channel , bool enable )
2011-08-22 17:41:57 +05:30
{
2012-06-21 11:07:44 +05:30
mgr_fld_write ( channel , DISPC_MGR_FLD_STALLMODE , enable ) ;
2009-11-12 11:41:42 +02:00
}
2012-09-12 13:30:39 +03:00
void dispc_mgr_set_lcd_config ( enum omap_channel channel ,
const struct dss_lcd_mgr_config * config )
{
dispc_mgr_set_io_pad_mode ( config - > io_pad_mode ) ;
dispc_mgr_enable_stallmode ( channel , config - > stallmode ) ;
dispc_mgr_enable_fifohandcheck ( channel , config - > fifohandcheck ) ;
dispc_mgr_set_clock_div ( channel , & config - > clock_info ) ;
dispc_mgr_set_tft_data_lines ( channel , config - > video_port_width ) ;
dispc_lcd_enable_signal_polarity ( config - > lcden_sig_polarity ) ;
dispc_mgr_set_lcd_type_tft ( channel ) ;
}
2012-04-16 12:53:44 +05:30
static bool _dispc_mgr_size_ok ( u16 width , u16 height )
{
2012-11-14 13:50:15 +05:30
return width < = dispc . feat - > mgr_width_max & &
height < = dispc . feat - > mgr_height_max ;
2012-04-16 12:53:44 +05:30
}
2009-11-12 11:41:42 +02:00
static bool _dispc_lcd_timings_ok ( int hsw , int hfp , int hbp ,
int vsw , int vfp , int vbp )
{
2012-07-03 12:26:51 +05:30
if ( hsw < 1 | | hsw > dispc . feat - > sw_max | |
hfp < 1 | | hfp > dispc . feat - > hp_max | |
hbp < 1 | | hbp > dispc . feat - > hp_max | |
vsw < 1 | | vsw > dispc . feat - > sw_max | |
vfp < 0 | | vfp > dispc . feat - > vp_max | |
vbp < 0 | | vbp > dispc . feat - > vp_max )
return false ;
2009-11-12 11:41:42 +02:00
return true ;
}
2012-04-16 12:53:44 +05:30
bool dispc_mgr_timings_ok ( enum omap_channel channel ,
2012-04-27 01:07:28 +05:30
const struct omap_video_timings * timings )
2009-11-12 11:41:42 +02:00
{
2012-04-16 12:53:44 +05:30
bool timings_ok ;
timings_ok = _dispc_mgr_size_ok ( timings - > x_res , timings - > y_res ) ;
2012-06-29 14:41:30 +05:30
if ( dss_mgr_is_lcd ( channel ) )
2012-04-16 12:53:44 +05:30
timings_ok = timings_ok & & _dispc_lcd_timings_ok ( timings - > hsw ,
timings - > hfp , timings - > hbp ,
timings - > vsw , timings - > vfp ,
timings - > vbp ) ;
return timings_ok ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:45:15 +03:00
static void _dispc_mgr_set_lcd_timings ( enum omap_channel channel , int hsw ,
2012-06-21 10:37:43 +05:30
int hfp , int hbp , int vsw , int vfp , int vbp ,
enum omap_dss_signal_level vsync_level ,
enum omap_dss_signal_level hsync_level ,
enum omap_dss_signal_edge data_pclk_edge ,
enum omap_dss_signal_level de_level ,
enum omap_dss_signal_edge sync_pclk_edge )
2009-11-12 11:41:42 +02:00
{
2012-06-21 10:37:43 +05:30
u32 timing_h , timing_v , l ;
bool onoff , rf , ipc ;
2009-11-12 11:41:42 +02:00
2012-07-03 12:26:51 +05:30
timing_h = FLD_VAL ( hsw - 1 , dispc . feat - > sw_start , 0 ) |
FLD_VAL ( hfp - 1 , dispc . feat - > fp_start , 8 ) |
FLD_VAL ( hbp - 1 , dispc . feat - > bp_start , 20 ) ;
timing_v = FLD_VAL ( vsw - 1 , dispc . feat - > sw_start , 0 ) |
FLD_VAL ( vfp , dispc . feat - > fp_start , 8 ) |
FLD_VAL ( vbp , dispc . feat - > bp_start , 20 ) ;
2009-11-12 11:41:42 +02:00
2010-12-02 11:27:10 +00:00
dispc_write_reg ( DISPC_TIMING_H ( channel ) , timing_h ) ;
dispc_write_reg ( DISPC_TIMING_V ( channel ) , timing_v ) ;
2012-06-21 10:37:43 +05:30
switch ( data_pclk_edge ) {
case OMAPDSS_DRIVE_SIG_RISING_EDGE :
ipc = false ;
break ;
case OMAPDSS_DRIVE_SIG_FALLING_EDGE :
ipc = true ;
break ;
case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES :
default :
BUG ( ) ;
}
switch ( sync_pclk_edge ) {
case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES :
onoff = false ;
rf = false ;
break ;
case OMAPDSS_DRIVE_SIG_FALLING_EDGE :
onoff = true ;
rf = false ;
break ;
case OMAPDSS_DRIVE_SIG_RISING_EDGE :
onoff = true ;
rf = true ;
break ;
default :
BUG ( ) ;
} ;
l = dispc_read_reg ( DISPC_POL_FREQ ( channel ) ) ;
l | = FLD_VAL ( onoff , 17 , 17 ) ;
l | = FLD_VAL ( rf , 16 , 16 ) ;
l | = FLD_VAL ( de_level , 15 , 15 ) ;
l | = FLD_VAL ( ipc , 14 , 14 ) ;
l | = FLD_VAL ( hsync_level , 13 , 13 ) ;
l | = FLD_VAL ( vsync_level , 12 , 12 ) ;
dispc_write_reg ( DISPC_POL_FREQ ( channel ) , l ) ;
2009-11-12 11:41:42 +02:00
}
/* change name to mode? */
2012-04-16 12:53:43 +05:30
void dispc_mgr_set_timings ( enum omap_channel channel ,
2012-10-03 09:09:11 +02:00
const struct omap_video_timings * timings )
2009-11-12 11:41:42 +02:00
{
unsigned xtot , ytot ;
unsigned long ht , vt ;
2012-05-18 14:36:54 +05:30
struct omap_video_timings t = * timings ;
2009-11-12 11:41:42 +02:00
2012-05-18 14:36:54 +05:30
DSSDBG ( " channel %d xres %u yres %u \n " , channel , t . x_res , t . y_res ) ;
2009-11-12 11:41:42 +02:00
2012-05-18 14:36:54 +05:30
if ( ! dispc_mgr_timings_ok ( channel , & t ) ) {
2012-04-16 12:53:44 +05:30
BUG ( ) ;
2012-05-18 11:47:02 +03:00
return ;
}
2009-11-12 11:41:42 +02:00
2012-06-29 14:41:30 +05:30
if ( dss_mgr_is_lcd ( channel ) ) {
2012-05-18 14:36:54 +05:30
_dispc_mgr_set_lcd_timings ( channel , t . hsw , t . hfp , t . hbp , t . vsw ,
2012-06-21 10:37:43 +05:30
t . vfp , t . vbp , t . vsync_level , t . hsync_level ,
t . data_pclk_edge , t . de_level , t . sync_pclk_edge ) ;
2009-11-12 11:41:42 +02:00
2012-05-18 14:36:54 +05:30
xtot = t . x_res + t . hfp + t . hsw + t . hbp ;
ytot = t . y_res + t . vfp + t . vsw + t . vbp ;
2009-11-12 11:41:42 +02:00
2012-04-16 12:53:43 +05:30
ht = ( timings - > pixel_clock * 1000 ) / xtot ;
vt = ( timings - > pixel_clock * 1000 ) / xtot / ytot ;
DSSDBG ( " pck %u \n " , timings - > pixel_clock ) ;
DSSDBG ( " hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d \n " ,
2012-05-18 14:36:54 +05:30
t . hsw , t . hfp , t . hbp , t . vsw , t . vfp , t . vbp ) ;
2012-06-21 10:37:43 +05:30
DSSDBG ( " vsync_level %d hsync_level %d data_pclk_edge %d de_level %d sync_pclk_edge %d \n " ,
t . vsync_level , t . hsync_level , t . data_pclk_edge ,
t . de_level , t . sync_pclk_edge ) ;
2009-11-12 11:41:42 +02:00
2012-04-16 12:53:43 +05:30
DSSDBG ( " hsync %luHz, vsync %luHz \n " , ht , vt ) ;
2012-05-18 14:36:54 +05:30
} else {
2012-06-28 11:15:51 +05:30
if ( t . interlace = = true )
2012-05-18 14:36:54 +05:30
t . y_res / = 2 ;
2012-04-16 12:53:43 +05:30
}
2012-04-16 12:53:44 +05:30
2012-05-18 14:36:54 +05:30
dispc_mgr_set_size ( channel , t . x_res , t . y_res ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:45:15 +03:00
static void dispc_mgr_set_lcd_divisor ( enum omap_channel channel , u16 lck_div ,
2010-12-02 11:27:11 +00:00
u16 pck_div )
2009-11-12 11:41:42 +02:00
{
BUG_ON ( lck_div < 1 ) ;
2011-08-29 15:56:04 +03:00
BUG_ON ( pck_div < 1 ) ;
2009-11-12 11:41:42 +02:00
2011-03-03 09:27:59 -06:00
dispc_write_reg ( DISPC_DIVISORo ( channel ) ,
2009-11-12 11:41:42 +02:00
FLD_VAL ( lck_div , 23 , 16 ) | FLD_VAL ( pck_div , 7 , 0 ) ) ;
}
2011-08-16 13:45:15 +03:00
static void dispc_mgr_get_lcd_divisor ( enum omap_channel channel , int * lck_div ,
2010-12-02 11:27:12 +00:00
int * pck_div )
2009-11-12 11:41:42 +02:00
{
u32 l ;
2011-03-03 09:27:59 -06:00
l = dispc_read_reg ( DISPC_DIVISORo ( channel ) ) ;
2009-11-12 11:41:42 +02:00
* lck_div = FLD_GET ( l , 23 , 16 ) ;
* pck_div = FLD_GET ( l , 7 , 0 ) ;
}
unsigned long dispc_fclk_rate ( void )
{
2011-05-12 17:26:26 +05:30
struct platform_device * dsidev ;
2009-11-12 11:41:42 +02:00
unsigned long r = 0 ;
2011-03-08 05:50:34 -06:00
switch ( dss_get_dispc_clk_source ( ) ) {
2011-04-12 13:52:23 +05:30
case OMAP_DSS_CLK_SRC_FCK :
2011-05-27 10:52:19 +03:00
r = clk_get_rate ( dispc . dss_clk ) ;
2011-03-08 05:50:34 -06:00
break ;
2011-04-12 13:52:23 +05:30
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
2011-05-12 17:26:26 +05:30
dsidev = dsi_get_dsidev_from_id ( 0 ) ;
r = dsi_get_pll_hsdiv_dispc_rate ( dsidev ) ;
2011-03-08 05:50:34 -06:00
break ;
2011-05-12 17:26:29 +05:30
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC :
dsidev = dsi_get_dsidev_from_id ( 1 ) ;
r = dsi_get_pll_hsdiv_dispc_rate ( dsidev ) ;
break ;
2011-03-08 05:50:34 -06:00
default :
BUG ( ) ;
2012-05-18 11:47:02 +03:00
return 0 ;
2011-03-08 05:50:34 -06:00
}
2009-11-12 11:41:42 +02:00
return r ;
}
2011-08-16 13:45:15 +03:00
unsigned long dispc_mgr_lclk_rate ( enum omap_channel channel )
2009-11-12 11:41:42 +02:00
{
2011-05-12 17:26:26 +05:30
struct platform_device * dsidev ;
2009-11-12 11:41:42 +02:00
int lcd ;
unsigned long r ;
u32 l ;
2012-10-23 11:50:10 +03:00
if ( dss_mgr_is_lcd ( channel ) ) {
l = dispc_read_reg ( DISPC_DIVISORo ( channel ) ) ;
2009-11-12 11:41:42 +02:00
2012-10-23 11:50:10 +03:00
lcd = FLD_GET ( l , 23 , 16 ) ;
2009-11-12 11:41:42 +02:00
2012-10-23 11:50:10 +03:00
switch ( dss_get_lcd_clk_source ( channel ) ) {
case OMAP_DSS_CLK_SRC_FCK :
r = clk_get_rate ( dispc . dss_clk ) ;
break ;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
dsidev = dsi_get_dsidev_from_id ( 0 ) ;
r = dsi_get_pll_hsdiv_dispc_rate ( dsidev ) ;
break ;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC :
dsidev = dsi_get_dsidev_from_id ( 1 ) ;
r = dsi_get_pll_hsdiv_dispc_rate ( dsidev ) ;
break ;
default :
BUG ( ) ;
return 0 ;
}
2009-11-12 11:41:42 +02:00
2012-10-23 11:50:10 +03:00
return r / lcd ;
} else {
return dispc_fclk_rate ( ) ;
}
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:45:15 +03:00
unsigned long dispc_mgr_pclk_rate ( enum omap_channel channel )
2009-11-12 11:41:42 +02:00
{
unsigned long r ;
2012-06-29 14:41:30 +05:30
if ( dss_mgr_is_lcd ( channel ) ) {
2011-09-13 18:28:41 +05:30
int pcd ;
u32 l ;
2009-11-12 11:41:42 +02:00
2011-09-13 18:28:41 +05:30
l = dispc_read_reg ( DISPC_DIVISORo ( channel ) ) ;
2009-11-12 11:41:42 +02:00
2011-09-13 18:28:41 +05:30
pcd = FLD_GET ( l , 7 , 0 ) ;
2009-11-12 11:41:42 +02:00
2011-09-13 18:28:41 +05:30
r = dispc_mgr_lclk_rate ( channel ) ;
return r / pcd ;
} else {
2012-04-09 15:06:41 +05:30
enum dss_hdmi_venc_clk_source_select source ;
2011-09-13 18:28:41 +05:30
2012-04-09 15:06:41 +05:30
source = dss_get_hdmi_venc_clk_source ( ) ;
switch ( source ) {
case DSS_VENC_TV_CLK :
2011-09-13 18:28:41 +05:30
return venc_get_pixel_clock ( ) ;
2012-04-09 15:06:41 +05:30
case DSS_HDMI_M_PCLK :
2011-09-13 18:28:41 +05:30
return hdmi_get_pixel_clock ( ) ;
default :
BUG ( ) ;
2012-05-18 11:47:02 +03:00
return 0 ;
2011-09-13 18:28:41 +05:30
}
}
2009-11-12 11:41:42 +02:00
}
2012-04-23 12:16:50 +05:30
unsigned long dispc_core_clk_rate ( void )
{
int lcd ;
unsigned long fclk = dispc_fclk_rate ( ) ;
if ( dss_has_feature ( FEAT_CORE_CLK_DIV ) )
lcd = REG_GET ( DISPC_DIVISOR , 23 , 16 ) ;
else
lcd = REG_GET ( DISPC_DIVISORo ( OMAP_DSS_CHANNEL_LCD ) , 23 , 16 ) ;
return fclk / lcd ;
}
2012-09-26 16:58:52 +05:30
static unsigned long dispc_plane_pclk_rate ( enum omap_plane plane )
{
2012-11-15 13:20:02 +02:00
enum omap_channel channel ;
if ( plane = = OMAP_DSS_WB )
return 0 ;
channel = dispc_ovl_get_channel_out ( plane ) ;
2012-09-26 16:58:52 +05:30
return dispc_mgr_pclk_rate ( channel ) ;
}
static unsigned long dispc_plane_lclk_rate ( enum omap_plane plane )
{
2012-11-15 13:20:02 +02:00
enum omap_channel channel ;
if ( plane = = OMAP_DSS_WB )
return 0 ;
channel = dispc_ovl_get_channel_out ( plane ) ;
2012-09-26 16:58:52 +05:30
2012-10-23 11:50:10 +03:00
return dispc_mgr_lclk_rate ( channel ) ;
2012-09-26 16:58:52 +05:30
}
2012-10-23 11:50:10 +03:00
2012-06-21 11:23:56 +05:30
static void dispc_dump_clocks_channel ( struct seq_file * s , enum omap_channel channel )
2009-11-12 11:41:42 +02:00
{
int lcd , pcd ;
2012-06-21 11:23:56 +05:30
enum omap_dss_clk_source lcd_clk_src ;
seq_printf ( s , " - %s - \n " , mgr_desc [ channel ] . name ) ;
lcd_clk_src = dss_get_lcd_clk_source ( channel ) ;
seq_printf ( s , " %s clk source = %s (%s) \n " , mgr_desc [ channel ] . name ,
dss_get_generic_clk_source_name ( lcd_clk_src ) ,
dss_feat_get_clk_source_name ( lcd_clk_src ) ) ;
dispc_mgr_get_lcd_divisor ( channel , & lcd , & pcd ) ;
seq_printf ( s , " lck \t \t %-16lulck div \t %u \n " ,
dispc_mgr_lclk_rate ( channel ) , lcd ) ;
seq_printf ( s , " pck \t \t %-16lupck div \t %u \n " ,
dispc_mgr_pclk_rate ( channel ) , pcd ) ;
}
void dispc_dump_clocks ( struct seq_file * s )
{
int lcd ;
2011-03-03 09:28:00 -06:00
u32 l ;
2011-04-12 13:52:23 +05:30
enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source ( ) ;
2009-11-12 11:41:42 +02:00
2011-05-27 10:52:19 +03:00
if ( dispc_runtime_get ( ) )
return ;
2009-11-12 11:41:42 +02:00
seq_printf ( s , " - DISPC - \n " ) ;
2011-03-02 11:57:25 +05:30
seq_printf ( s , " dispc fclk source = %s (%s) \n " ,
dss_get_generic_clk_source_name ( dispc_clk_src ) ,
dss_feat_get_clk_source_name ( dispc_clk_src ) ) ;
2009-11-12 11:41:42 +02:00
seq_printf ( s , " fck \t \t %-16lu \n " , dispc_fclk_rate ( ) ) ;
2010-12-02 11:27:12 +00:00
2011-03-03 09:28:00 -06:00
if ( dss_has_feature ( FEAT_CORE_CLK_DIV ) ) {
seq_printf ( s , " - DISPC-CORE-CLK - \n " ) ;
l = dispc_read_reg ( DISPC_DIVISOR ) ;
lcd = FLD_GET ( l , 23 , 16 ) ;
seq_printf ( s , " lck \t \t %-16lulck div \t %u \n " ,
( dispc_fclk_rate ( ) / lcd ) , lcd ) ;
}
2010-12-02 11:27:12 +00:00
2012-06-21 11:23:56 +05:30
dispc_dump_clocks_channel ( s , OMAP_DSS_CHANNEL_LCD ) ;
2011-03-08 05:50:35 -06:00
2012-06-21 11:23:56 +05:30
if ( dss_has_feature ( FEAT_MGR_LCD2 ) )
dispc_dump_clocks_channel ( s , OMAP_DSS_CHANNEL_LCD2 ) ;
if ( dss_has_feature ( FEAT_MGR_LCD3 ) )
dispc_dump_clocks_channel ( s , OMAP_DSS_CHANNEL_LCD3 ) ;
2011-05-27 10:52:19 +03:00
dispc_runtime_put ( ) ;
2009-11-12 11:41:42 +02:00
}
2009-12-17 14:35:21 +02:00
# ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2012-11-07 08:52:44 +02:00
static void dispc_dump_irqs ( struct seq_file * s )
2009-12-17 14:35:21 +02:00
{
unsigned long flags ;
struct dispc_irq_stats stats ;
spin_lock_irqsave ( & dispc . irq_stats_lock , flags ) ;
stats = dispc . irq_stats ;
memset ( & dispc . irq_stats , 0 , sizeof ( dispc . irq_stats ) ) ;
dispc . irq_stats . last_reset = jiffies ;
spin_unlock_irqrestore ( & dispc . irq_stats_lock , flags ) ;
seq_printf ( s , " period %u ms \n " ,
jiffies_to_msecs ( jiffies - stats . last_reset ) ) ;
seq_printf ( s , " irqs %d \n " , stats . irq_count ) ;
# define PIS(x) \
seq_printf ( s , " %-20s %10d \n " , # x , stats . irqs [ ffs ( DISPC_IRQ_ # # x ) - 1 ] ) ;
PIS ( FRAMEDONE ) ;
PIS ( VSYNC ) ;
PIS ( EVSYNC_EVEN ) ;
PIS ( EVSYNC_ODD ) ;
PIS ( ACBIAS_COUNT_STAT ) ;
PIS ( PROG_LINE_NUM ) ;
PIS ( GFX_FIFO_UNDERFLOW ) ;
PIS ( GFX_END_WIN ) ;
PIS ( PAL_GAMMA_MASK ) ;
PIS ( OCP_ERR ) ;
PIS ( VID1_FIFO_UNDERFLOW ) ;
PIS ( VID1_END_WIN ) ;
PIS ( VID2_FIFO_UNDERFLOW ) ;
PIS ( VID2_END_WIN ) ;
2011-09-13 18:20:33 +05:30
if ( dss_feat_get_num_ovls ( ) > 3 ) {
PIS ( VID3_FIFO_UNDERFLOW ) ;
PIS ( VID3_END_WIN ) ;
}
2009-12-17 14:35:21 +02:00
PIS ( SYNC_LOST ) ;
PIS ( SYNC_LOST_DIGIT ) ;
PIS ( WAKEUP ) ;
2010-12-02 11:27:12 +00:00
if ( dss_has_feature ( FEAT_MGR_LCD2 ) ) {
PIS ( FRAMEDONE2 ) ;
PIS ( VSYNC2 ) ;
PIS ( ACBIAS_COUNT_STAT2 ) ;
PIS ( SYNC_LOST2 ) ;
}
2012-06-21 11:23:56 +05:30
if ( dss_has_feature ( FEAT_MGR_LCD3 ) ) {
PIS ( FRAMEDONE3 ) ;
PIS ( VSYNC3 ) ;
PIS ( ACBIAS_COUNT_STAT3 ) ;
PIS ( SYNC_LOST3 ) ;
}
2009-12-17 14:35:21 +02:00
# undef PIS
}
# endif
2012-03-02 18:01:07 +02:00
static void dispc_dump_regs ( struct seq_file * s )
2009-11-12 11:41:42 +02:00
{
2011-08-05 19:06:01 +05:30
int i , j ;
const char * mgr_names [ ] = {
[ OMAP_DSS_CHANNEL_LCD ] = " LCD " ,
[ OMAP_DSS_CHANNEL_DIGIT ] = " TV " ,
[ OMAP_DSS_CHANNEL_LCD2 ] = " LCD2 " ,
2012-06-21 11:23:56 +05:30
[ OMAP_DSS_CHANNEL_LCD3 ] = " LCD3 " ,
2011-08-05 19:06:01 +05:30
} ;
const char * ovl_names [ ] = {
[ OMAP_DSS_GFX ] = " GFX " ,
[ OMAP_DSS_VIDEO1 ] = " VID1 " ,
[ OMAP_DSS_VIDEO2 ] = " VID2 " ,
2011-09-13 18:20:33 +05:30
[ OMAP_DSS_VIDEO3 ] = " VID3 " ,
2011-08-05 19:06:01 +05:30
} ;
const char * * p_names ;
2011-05-06 11:45:49 +05:30
# define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
2009-11-12 11:41:42 +02:00
2011-05-27 10:52:19 +03:00
if ( dispc_runtime_get ( ) )
return ;
2009-11-12 11:41:42 +02:00
2011-08-05 19:06:00 +05:30
/* DISPC common registers */
2009-11-12 11:41:42 +02:00
DUMPREG ( DISPC_REVISION ) ;
DUMPREG ( DISPC_SYSCONFIG ) ;
DUMPREG ( DISPC_SYSSTATUS ) ;
DUMPREG ( DISPC_IRQSTATUS ) ;
DUMPREG ( DISPC_IRQENABLE ) ;
DUMPREG ( DISPC_CONTROL ) ;
DUMPREG ( DISPC_CONFIG ) ;
DUMPREG ( DISPC_CAPABLE ) ;
DUMPREG ( DISPC_LINE_STATUS ) ;
DUMPREG ( DISPC_LINE_NUMBER ) ;
2011-09-26 11:47:29 +05:30
if ( dss_has_feature ( FEAT_ALPHA_FIXED_ZORDER ) | |
dss_has_feature ( FEAT_ALPHA_FREE_ZORDER ) )
2011-05-27 14:22:16 +03:00
DUMPREG ( DISPC_GLOBAL_ALPHA ) ;
2010-12-02 11:27:12 +00:00
if ( dss_has_feature ( FEAT_MGR_LCD2 ) ) {
DUMPREG ( DISPC_CONTROL2 ) ;
DUMPREG ( DISPC_CONFIG2 ) ;
2011-08-05 19:06:00 +05:30
}
2012-06-21 11:23:56 +05:30
if ( dss_has_feature ( FEAT_MGR_LCD3 ) ) {
DUMPREG ( DISPC_CONTROL3 ) ;
DUMPREG ( DISPC_CONFIG3 ) ;
}
2011-08-05 19:06:00 +05:30
# undef DUMPREG
# define DISPC_REG(i, name) name(i)
2011-08-05 19:06:01 +05:30
# define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \
2012-09-28 13:58:14 +03:00
( int ) ( 48 - strlen ( # r ) - strlen ( p_names [ i ] ) ) , " " , \
2011-08-05 19:06:00 +05:30
dispc_read_reg ( DISPC_REG ( i , r ) ) )
2011-08-05 19:06:01 +05:30
p_names = mgr_names ;
2011-08-05 19:06:00 +05:30
2011-08-05 19:06:01 +05:30
/* DISPC channel specific registers */
for ( i = 0 ; i < dss_feat_get_num_mgrs ( ) ; i + + ) {
DUMPREG ( i , DISPC_DEFAULT_COLOR ) ;
DUMPREG ( i , DISPC_TRANS_COLOR ) ;
DUMPREG ( i , DISPC_SIZE_MGR ) ;
2009-11-12 11:41:42 +02:00
2011-08-05 19:06:01 +05:30
if ( i = = OMAP_DSS_CHANNEL_DIGIT )
continue ;
2011-08-05 19:06:00 +05:30
2011-08-05 19:06:01 +05:30
DUMPREG ( i , DISPC_DEFAULT_COLOR ) ;
DUMPREG ( i , DISPC_TRANS_COLOR ) ;
DUMPREG ( i , DISPC_TIMING_H ) ;
DUMPREG ( i , DISPC_TIMING_V ) ;
DUMPREG ( i , DISPC_POL_FREQ ) ;
DUMPREG ( i , DISPC_DIVISORo ) ;
DUMPREG ( i , DISPC_SIZE_MGR ) ;
2011-08-05 19:06:00 +05:30
2011-08-05 19:06:01 +05:30
DUMPREG ( i , DISPC_DATA_CYCLE1 ) ;
DUMPREG ( i , DISPC_DATA_CYCLE2 ) ;
DUMPREG ( i , DISPC_DATA_CYCLE3 ) ;
2010-12-02 11:27:12 +00:00
2011-05-27 14:22:16 +03:00
if ( dss_has_feature ( FEAT_CPR ) ) {
2011-08-05 19:06:01 +05:30
DUMPREG ( i , DISPC_CPR_COEF_R ) ;
DUMPREG ( i , DISPC_CPR_COEF_G ) ;
DUMPREG ( i , DISPC_CPR_COEF_B ) ;
2011-05-27 14:22:16 +03:00
}
2010-12-02 11:27:12 +00:00
}
2009-11-12 11:41:42 +02:00
2011-08-05 19:06:01 +05:30
p_names = ovl_names ;
for ( i = 0 ; i < dss_feat_get_num_ovls ( ) ; i + + ) {
DUMPREG ( i , DISPC_OVL_BA0 ) ;
DUMPREG ( i , DISPC_OVL_BA1 ) ;
DUMPREG ( i , DISPC_OVL_POSITION ) ;
DUMPREG ( i , DISPC_OVL_SIZE ) ;
DUMPREG ( i , DISPC_OVL_ATTRIBUTES ) ;
DUMPREG ( i , DISPC_OVL_FIFO_THRESHOLD ) ;
DUMPREG ( i , DISPC_OVL_FIFO_SIZE_STATUS ) ;
DUMPREG ( i , DISPC_OVL_ROW_INC ) ;
DUMPREG ( i , DISPC_OVL_PIXEL_INC ) ;
if ( dss_has_feature ( FEAT_PRELOAD ) )
DUMPREG ( i , DISPC_OVL_PRELOAD ) ;
if ( i = = OMAP_DSS_GFX ) {
DUMPREG ( i , DISPC_OVL_WINDOW_SKIP ) ;
DUMPREG ( i , DISPC_OVL_TABLE_BA ) ;
continue ;
}
DUMPREG ( i , DISPC_OVL_FIR ) ;
DUMPREG ( i , DISPC_OVL_PICTURE_SIZE ) ;
DUMPREG ( i , DISPC_OVL_ACCU0 ) ;
DUMPREG ( i , DISPC_OVL_ACCU1 ) ;
if ( dss_has_feature ( FEAT_HANDLE_UV_SEPARATE ) ) {
DUMPREG ( i , DISPC_OVL_BA0_UV ) ;
DUMPREG ( i , DISPC_OVL_BA1_UV ) ;
DUMPREG ( i , DISPC_OVL_FIR2 ) ;
DUMPREG ( i , DISPC_OVL_ACCU2_0 ) ;
DUMPREG ( i , DISPC_OVL_ACCU2_1 ) ;
}
if ( dss_has_feature ( FEAT_ATTR2 ) )
DUMPREG ( i , DISPC_OVL_ATTRIBUTES2 ) ;
if ( dss_has_feature ( FEAT_PRELOAD ) )
DUMPREG ( i , DISPC_OVL_PRELOAD ) ;
2011-05-19 19:47:53 +05:30
}
2011-08-05 19:06:00 +05:30
# undef DISPC_REG
# undef DUMPREG
# define DISPC_REG(plane, name, i) name(plane, i)
# define DUMPREG(plane, name, i) \
2011-08-05 19:06:01 +05:30
seq_printf ( s , " %s_%d(%s)%*s %08x \n " , # name , i , p_names [ plane ] , \
2012-09-28 13:58:14 +03:00
( int ) ( 46 - strlen ( # name ) - strlen ( p_names [ plane ] ) ) , " " , \
2011-08-05 19:06:00 +05:30
dispc_read_reg ( DISPC_REG ( plane , name , i ) ) )
2011-08-05 19:06:01 +05:30
/* Video pipeline coefficient registers */
2011-05-27 14:22:16 +03:00
2011-08-05 19:06:01 +05:30
/* start from OMAP_DSS_VIDEO1 */
for ( i = 1 ; i < dss_feat_get_num_ovls ( ) ; i + + ) {
for ( j = 0 ; j < 8 ; j + + )
DUMPREG ( i , DISPC_OVL_FIR_COEF_H , j ) ;
2011-05-06 11:45:49 +05:30
2011-08-05 19:06:01 +05:30
for ( j = 0 ; j < 8 ; j + + )
DUMPREG ( i , DISPC_OVL_FIR_COEF_HV , j ) ;
2011-08-05 19:06:00 +05:30
2011-08-05 19:06:01 +05:30
for ( j = 0 ; j < 5 ; j + + )
DUMPREG ( i , DISPC_OVL_CONV_COEF , j ) ;
2011-05-19 19:47:53 +05:30
2011-08-05 19:06:01 +05:30
if ( dss_has_feature ( FEAT_FIR_COEF_V ) ) {
for ( j = 0 ; j < 8 ; j + + )
DUMPREG ( i , DISPC_OVL_FIR_COEF_V , j ) ;
}
if ( dss_has_feature ( FEAT_HANDLE_UV_SEPARATE ) ) {
for ( j = 0 ; j < 8 ; j + + )
DUMPREG ( i , DISPC_OVL_FIR_COEF_H2 , j ) ;
for ( j = 0 ; j < 8 ; j + + )
DUMPREG ( i , DISPC_OVL_FIR_COEF_HV2 , j ) ;
for ( j = 0 ; j < 8 ; j + + )
DUMPREG ( i , DISPC_OVL_FIR_COEF_V2 , j ) ;
}
2011-05-27 14:22:16 +03:00
}
2009-11-12 11:41:42 +02:00
2011-05-27 10:52:19 +03:00
dispc_runtime_put ( ) ;
2011-08-05 19:06:00 +05:30
# undef DISPC_REG
2009-11-12 11:41:42 +02:00
# undef DUMPREG
}
/* with fck as input clock rate, find dispc dividers that produce req_pck */
2012-06-21 09:33:55 +05:30
void dispc_find_clk_divs ( unsigned long req_pck , unsigned long fck ,
2009-11-12 11:41:42 +02:00
struct dispc_clock_info * cinfo )
{
2011-08-29 15:56:04 +03:00
u16 pcd_min , pcd_max ;
2009-11-12 11:41:42 +02:00
unsigned long best_pck ;
u16 best_ld , cur_ld ;
u16 best_pd , cur_pd ;
2011-08-29 15:56:04 +03:00
pcd_min = dss_feat_get_param_min ( FEAT_PARAM_DSS_PCD ) ;
pcd_max = dss_feat_get_param_max ( FEAT_PARAM_DSS_PCD ) ;
2009-11-12 11:41:42 +02:00
best_pck = 0 ;
best_ld = 0 ;
best_pd = 0 ;
for ( cur_ld = 1 ; cur_ld < = 255 ; + + cur_ld ) {
unsigned long lck = fck / cur_ld ;
2011-08-29 15:56:04 +03:00
for ( cur_pd = pcd_min ; cur_pd < = pcd_max ; + + cur_pd ) {
2009-11-12 11:41:42 +02:00
unsigned long pck = lck / cur_pd ;
long old_delta = abs ( best_pck - req_pck ) ;
long new_delta = abs ( pck - req_pck ) ;
if ( best_pck = = 0 | | new_delta < old_delta ) {
best_pck = pck ;
best_ld = cur_ld ;
best_pd = cur_pd ;
if ( pck = = req_pck )
goto found ;
}
if ( pck < req_pck )
break ;
}
if ( lck / pcd_min < req_pck )
break ;
}
found :
cinfo - > lck_div = best_ld ;
cinfo - > pck_div = best_pd ;
cinfo - > lck = fck / cinfo - > lck_div ;
cinfo - > pck = cinfo - > lck / cinfo - > pck_div ;
}
/* calculate clock rates using dividers in cinfo */
int dispc_calc_clock_rates ( unsigned long dispc_fclk_rate ,
struct dispc_clock_info * cinfo )
{
if ( cinfo - > lck_div > 255 | | cinfo - > lck_div = = 0 )
return - EINVAL ;
2011-08-29 15:56:04 +03:00
if ( cinfo - > pck_div < 1 | | cinfo - > pck_div > 255 )
2009-11-12 11:41:42 +02:00
return - EINVAL ;
cinfo - > lck = dispc_fclk_rate / cinfo - > lck_div ;
cinfo - > pck = cinfo - > lck / cinfo - > pck_div ;
return 0 ;
}
2012-06-29 14:00:54 +05:30
void dispc_mgr_set_clock_div ( enum omap_channel channel ,
2012-10-03 09:09:11 +02:00
const struct dispc_clock_info * cinfo )
2009-11-12 11:41:42 +02:00
{
DSSDBG ( " lck = %lu (%u) \n " , cinfo - > lck , cinfo - > lck_div ) ;
DSSDBG ( " pck = %lu (%u) \n " , cinfo - > pck , cinfo - > pck_div ) ;
2011-08-16 13:45:15 +03:00
dispc_mgr_set_lcd_divisor ( channel , cinfo - > lck_div , cinfo - > pck_div ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:45:15 +03:00
int dispc_mgr_get_clock_div ( enum omap_channel channel ,
2010-12-02 11:27:11 +00:00
struct dispc_clock_info * cinfo )
2009-11-12 11:41:42 +02:00
{
unsigned long fck ;
fck = dispc_fclk_rate ( ) ;
2011-03-03 09:27:59 -06:00
cinfo - > lck_div = REG_GET ( DISPC_DIVISORo ( channel ) , 23 , 16 ) ;
cinfo - > pck_div = REG_GET ( DISPC_DIVISORo ( channel ) , 7 , 0 ) ;
2009-11-12 11:41:42 +02:00
cinfo - > lck = fck / cinfo - > lck_div ;
cinfo - > pck = cinfo - > lck / cinfo - > pck_div ;
return 0 ;
}
2012-10-10 15:13:14 +03:00
u32 dispc_read_irqstatus ( void )
{
return dispc_read_reg ( DISPC_IRQSTATUS ) ;
}
void dispc_clear_irqstatus ( u32 mask )
{
dispc_write_reg ( DISPC_IRQSTATUS , mask ) ;
}
u32 dispc_read_irqenable ( void )
{
return dispc_read_reg ( DISPC_IRQENABLE ) ;
}
void dispc_write_irqenable ( u32 mask )
{
u32 old_mask = dispc_read_reg ( DISPC_IRQENABLE ) ;
/* clear the irqstatus for newly enabled irqs */
dispc_clear_irqstatus ( ( mask ^ old_mask ) & mask ) ;
dispc_write_reg ( DISPC_IRQENABLE , mask ) ;
}
2009-11-12 11:41:42 +02:00
/* dispc.irq_lock has to be locked by the caller */
static void _omap_dispc_set_irqs ( void )
{
u32 mask ;
int i ;
struct omap_dispc_isr_data * isr_data ;
mask = dispc . irq_error_mask ;
for ( i = 0 ; i < DISPC_MAX_NR_ISRS ; i + + ) {
isr_data = & dispc . registered_isr [ i ] ;
if ( isr_data - > isr = = NULL )
continue ;
mask | = isr_data - > mask ;
}
2012-10-10 15:13:14 +03:00
dispc_write_irqenable ( mask ) ;
2009-11-12 11:41:42 +02:00
}
int omap_dispc_register_isr ( omap_dispc_isr_t isr , void * arg , u32 mask )
{
int i ;
int ret ;
unsigned long flags ;
struct omap_dispc_isr_data * isr_data ;
if ( isr = = NULL )
return - EINVAL ;
spin_lock_irqsave ( & dispc . irq_lock , flags ) ;
/* check for duplicate entry */
for ( i = 0 ; i < DISPC_MAX_NR_ISRS ; i + + ) {
isr_data = & dispc . registered_isr [ i ] ;
if ( isr_data - > isr = = isr & & isr_data - > arg = = arg & &
isr_data - > mask = = mask ) {
ret = - EINVAL ;
goto err ;
}
}
isr_data = NULL ;
ret = - EBUSY ;
for ( i = 0 ; i < DISPC_MAX_NR_ISRS ; i + + ) {
isr_data = & dispc . registered_isr [ i ] ;
if ( isr_data - > isr ! = NULL )
continue ;
isr_data - > isr = isr ;
isr_data - > arg = arg ;
isr_data - > mask = mask ;
ret = 0 ;
break ;
}
2011-03-04 18:19:54 +02:00
if ( ret )
goto err ;
2009-11-12 11:41:42 +02:00
_omap_dispc_set_irqs ( ) ;
spin_unlock_irqrestore ( & dispc . irq_lock , flags ) ;
return 0 ;
err :
spin_unlock_irqrestore ( & dispc . irq_lock , flags ) ;
return ret ;
}
EXPORT_SYMBOL ( omap_dispc_register_isr ) ;
int omap_dispc_unregister_isr ( omap_dispc_isr_t isr , void * arg , u32 mask )
{
int i ;
unsigned long flags ;
int ret = - EINVAL ;
struct omap_dispc_isr_data * isr_data ;
spin_lock_irqsave ( & dispc . irq_lock , flags ) ;
for ( i = 0 ; i < DISPC_MAX_NR_ISRS ; i + + ) {
isr_data = & dispc . registered_isr [ i ] ;
if ( isr_data - > isr ! = isr | | isr_data - > arg ! = arg | |
isr_data - > mask ! = mask )
continue ;
/* found the correct isr */
isr_data - > isr = NULL ;
isr_data - > arg = NULL ;
isr_data - > mask = 0 ;
ret = 0 ;
break ;
}
if ( ret = = 0 )
_omap_dispc_set_irqs ( ) ;
spin_unlock_irqrestore ( & dispc . irq_lock , flags ) ;
return ret ;
}
EXPORT_SYMBOL ( omap_dispc_unregister_isr ) ;
static void print_irq_status ( u32 status )
{
if ( ( status & dispc . irq_error_mask ) = = 0 )
return ;
2012-09-29 12:33:05 +05:30
# define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
pr_debug ( " DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s \n " ,
status ,
PIS ( OCP_ERR ) ,
PIS ( GFX_FIFO_UNDERFLOW ) ,
PIS ( VID1_FIFO_UNDERFLOW ) ,
PIS ( VID2_FIFO_UNDERFLOW ) ,
dss_feat_get_num_ovls ( ) > 3 ? PIS ( VID3_FIFO_UNDERFLOW ) : " " ,
PIS ( SYNC_LOST ) ,
PIS ( SYNC_LOST_DIGIT ) ,
dss_has_feature ( FEAT_MGR_LCD2 ) ? PIS ( SYNC_LOST2 ) : " " ,
dss_has_feature ( FEAT_MGR_LCD3 ) ? PIS ( SYNC_LOST3 ) : " " ) ;
2009-11-12 11:41:42 +02:00
# undef PIS
}
/* Called from dss.c. Note that we don't touch clocks here,
* but we presume they are on because we got an IRQ . However ,
* an irq handler may turn the clocks off , so we may not have
* clock later in the function . */
2011-02-23 08:41:03 +00:00
static irqreturn_t omap_dispc_irq_handler ( int irq , void * arg )
2009-11-12 11:41:42 +02:00
{
int i ;
2011-02-23 08:41:03 +00:00
u32 irqstatus , irqenable ;
2009-11-12 11:41:42 +02:00
u32 handledirqs = 0 ;
u32 unhandled_errors ;
struct omap_dispc_isr_data * isr_data ;
struct omap_dispc_isr_data registered_isr [ DISPC_MAX_NR_ISRS ] ;
spin_lock ( & dispc . irq_lock ) ;
2012-10-10 15:13:14 +03:00
irqstatus = dispc_read_irqstatus ( ) ;
irqenable = dispc_read_irqenable ( ) ;
2011-02-23 08:41:03 +00:00
/* IRQ is not for us */
if ( ! ( irqstatus & irqenable ) ) {
spin_unlock ( & dispc . irq_lock ) ;
return IRQ_NONE ;
}
2009-11-12 11:41:42 +02:00
2009-12-17 14:35:21 +02:00
# ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
spin_lock ( & dispc . irq_stats_lock ) ;
dispc . irq_stats . irq_count + + ;
dss_collect_irq_stats ( irqstatus , dispc . irq_stats . irqs ) ;
spin_unlock ( & dispc . irq_stats_lock ) ;
# endif
2012-09-29 13:57:31 +05:30
print_irq_status ( irqstatus ) ;
2009-11-12 11:41:42 +02:00
/* Ack the interrupt. Do it here before clocks are possibly turned
* off */
2012-10-10 15:13:14 +03:00
dispc_clear_irqstatus ( irqstatus ) ;
2009-11-12 11:41:42 +02:00
/* flush posted write */
2012-10-10 15:13:14 +03:00
dispc_read_irqstatus ( ) ;
2009-11-12 11:41:42 +02:00
/* make a copy and unlock, so that isrs can unregister
* themselves */
memcpy ( registered_isr , dispc . registered_isr ,
sizeof ( registered_isr ) ) ;
spin_unlock ( & dispc . irq_lock ) ;
for ( i = 0 ; i < DISPC_MAX_NR_ISRS ; i + + ) {
isr_data = & registered_isr [ i ] ;
if ( ! isr_data - > isr )
continue ;
if ( isr_data - > mask & irqstatus ) {
isr_data - > isr ( isr_data - > arg , irqstatus ) ;
handledirqs | = isr_data - > mask ;
}
}
spin_lock ( & dispc . irq_lock ) ;
unhandled_errors = irqstatus & ~ handledirqs & dispc . irq_error_mask ;
if ( unhandled_errors ) {
dispc . error_irqs | = unhandled_errors ;
dispc . irq_error_mask & = ~ unhandled_errors ;
_omap_dispc_set_irqs ( ) ;
schedule_work ( & dispc . error_work ) ;
}
spin_unlock ( & dispc . irq_lock ) ;
2011-02-23 08:41:03 +00:00
return IRQ_HANDLED ;
2009-11-12 11:41:42 +02:00
}
static void dispc_error_worker ( struct work_struct * work )
{
int i ;
u32 errors ;
unsigned long flags ;
2011-08-15 11:51:50 +03:00
static const unsigned fifo_underflow_bits [ ] = {
DISPC_IRQ_GFX_FIFO_UNDERFLOW ,
DISPC_IRQ_VID1_FIFO_UNDERFLOW ,
DISPC_IRQ_VID2_FIFO_UNDERFLOW ,
2011-09-13 18:20:33 +05:30
DISPC_IRQ_VID3_FIFO_UNDERFLOW ,
2011-08-15 11:51:50 +03:00
} ;
2009-11-12 11:41:42 +02:00
spin_lock_irqsave ( & dispc . irq_lock , flags ) ;
errors = dispc . error_irqs ;
dispc . error_irqs = 0 ;
spin_unlock_irqrestore ( & dispc . irq_lock , flags ) ;
2011-06-27 10:31:05 -07:00
dispc_runtime_get ( ) ;
2011-08-15 11:51:50 +03:00
for ( i = 0 ; i < omap_dss_get_num_overlays ( ) ; + + i ) {
struct omap_overlay * ovl ;
unsigned bit ;
2009-11-12 11:41:42 +02:00
2011-08-15 11:51:50 +03:00
ovl = omap_dss_get_overlay ( i ) ;
bit = fifo_underflow_bits [ i ] ;
2009-11-12 11:41:42 +02:00
2011-08-15 11:51:50 +03:00
if ( bit & errors ) {
DSSERR ( " FIFO UNDERFLOW on %s, disabling the overlay \n " ,
ovl - > name ) ;
2011-08-16 13:25:00 +03:00
dispc_ovl_enable ( ovl - > id , false ) ;
2011-08-16 13:45:15 +03:00
dispc_mgr_go ( ovl - > manager - > id ) ;
2012-07-24 19:33:55 +05:30
msleep ( 50 ) ;
2009-11-12 11:41:42 +02:00
}
}
2011-08-15 11:51:50 +03:00
for ( i = 0 ; i < omap_dss_get_num_overlay_managers ( ) ; + + i ) {
struct omap_overlay_manager * mgr ;
unsigned bit ;
2009-11-12 11:41:42 +02:00
2011-08-15 11:51:50 +03:00
mgr = omap_dss_get_overlay_manager ( i ) ;
2012-06-21 11:07:44 +05:30
bit = mgr_desc [ i ] . sync_lost_irq ;
2009-11-12 11:41:42 +02:00
2011-08-15 11:51:50 +03:00
if ( bit & errors ) {
2012-10-24 09:20:40 +03:00
int j ;
2009-11-12 11:41:42 +02:00
2011-08-15 11:51:50 +03:00
DSSERR ( " SYNC_LOST on channel %s, restarting the output "
" with video overlays disabled \n " ,
mgr - > name ) ;
2010-12-02 11:27:12 +00:00
2012-06-15 15:34:24 +03:00
dss_mgr_disable ( mgr ) ;
2010-12-02 11:27:12 +00:00
2012-10-24 09:20:40 +03:00
for ( j = 0 ; j < omap_dss_get_num_overlays ( ) ; + + j ) {
2010-12-02 11:27:12 +00:00
struct omap_overlay * ovl ;
2012-10-24 09:20:40 +03:00
ovl = omap_dss_get_overlay ( j ) ;
2010-12-02 11:27:12 +00:00
2011-08-15 11:51:50 +03:00
if ( ovl - > id ! = OMAP_DSS_GFX & &
ovl - > manager = = mgr )
2012-06-15 15:34:24 +03:00
ovl - > disable ( ovl ) ;
2010-12-02 11:27:12 +00:00
}
2012-06-15 15:34:24 +03:00
dss_mgr_enable ( mgr ) ;
2010-12-02 11:27:12 +00:00
}
}
2009-11-12 11:41:42 +02:00
if ( errors & DISPC_IRQ_OCP_ERR ) {
DSSERR ( " OCP_ERR \n " ) ;
for ( i = 0 ; i < omap_dss_get_num_overlay_managers ( ) ; + + i ) {
struct omap_overlay_manager * mgr ;
2012-09-07 17:44:51 +05:30
2009-11-12 11:41:42 +02:00
mgr = omap_dss_get_overlay_manager ( i ) ;
2012-06-15 15:34:24 +03:00
dss_mgr_disable ( mgr ) ;
2009-11-12 11:41:42 +02:00
}
}
spin_lock_irqsave ( & dispc . irq_lock , flags ) ;
dispc . irq_error_mask | = errors ;
_omap_dispc_set_irqs ( ) ;
spin_unlock_irqrestore ( & dispc . irq_lock , flags ) ;
2011-06-27 10:31:05 -07:00
dispc_runtime_put ( ) ;
2009-11-12 11:41:42 +02:00
}
int omap_dispc_wait_for_irq_timeout ( u32 irqmask , unsigned long timeout )
{
void dispc_irq_wait_handler ( void * data , u32 mask )
{
complete ( ( struct completion * ) data ) ;
}
int r ;
DECLARE_COMPLETION_ONSTACK ( completion ) ;
r = omap_dispc_register_isr ( dispc_irq_wait_handler , & completion ,
irqmask ) ;
if ( r )
return r ;
timeout = wait_for_completion_timeout ( & completion , timeout ) ;
omap_dispc_unregister_isr ( dispc_irq_wait_handler , & completion , irqmask ) ;
if ( timeout = = 0 )
return - ETIMEDOUT ;
return 0 ;
}
int omap_dispc_wait_for_irq_interruptible_timeout ( u32 irqmask ,
unsigned long timeout )
{
void dispc_irq_wait_handler ( void * data , u32 mask )
{
complete ( ( struct completion * ) data ) ;
}
int r ;
DECLARE_COMPLETION_ONSTACK ( completion ) ;
r = omap_dispc_register_isr ( dispc_irq_wait_handler , & completion ,
irqmask ) ;
if ( r )
return r ;
timeout = wait_for_completion_interruptible_timeout ( & completion ,
timeout ) ;
omap_dispc_unregister_isr ( dispc_irq_wait_handler , & completion , irqmask ) ;
if ( timeout = = 0 )
return - ETIMEDOUT ;
if ( timeout = = - ERESTARTSYS )
return - ERESTARTSYS ;
return 0 ;
}
static void _omap_dispc_initialize_irq ( void )
{
unsigned long flags ;
spin_lock_irqsave ( & dispc . irq_lock , flags ) ;
memset ( dispc . registered_isr , 0 , sizeof ( dispc . registered_isr ) ) ;
dispc . irq_error_mask = DISPC_IRQ_MASK_ERROR ;
2010-12-02 11:27:12 +00:00
if ( dss_has_feature ( FEAT_MGR_LCD2 ) )
dispc . irq_error_mask | = DISPC_IRQ_SYNC_LOST2 ;
2012-06-29 10:43:13 +05:30
if ( dss_has_feature ( FEAT_MGR_LCD3 ) )
dispc . irq_error_mask | = DISPC_IRQ_SYNC_LOST3 ;
2011-09-13 18:20:33 +05:30
if ( dss_feat_get_num_ovls ( ) > 3 )
dispc . irq_error_mask | = DISPC_IRQ_VID3_FIFO_UNDERFLOW ;
2009-11-12 11:41:42 +02:00
/* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
* so clear it */
2012-10-10 15:13:14 +03:00
dispc_clear_irqstatus ( dispc_read_irqstatus ( ) ) ;
2009-11-12 11:41:42 +02:00
_omap_dispc_set_irqs ( ) ;
spin_unlock_irqrestore ( & dispc . irq_lock , flags ) ;
}
void dispc_enable_sidle ( void )
{
REG_FLD_MOD ( DISPC_SYSCONFIG , 2 , 4 , 3 ) ; /* SIDLEMODE: smart idle */
}
void dispc_disable_sidle ( void )
{
REG_FLD_MOD ( DISPC_SYSCONFIG , 1 , 4 , 3 ) ; /* SIDLEMODE: no idle */
}
static void _omap_dispc_initial_config ( void )
{
u32 l ;
2011-03-03 09:28:00 -06:00
/* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
if ( dss_has_feature ( FEAT_CORE_CLK_DIV ) ) {
l = dispc_read_reg ( DISPC_DIVISOR ) ;
/* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
l = FLD_MOD ( l , 1 , 0 , 0 ) ;
l = FLD_MOD ( l , 1 , 23 , 16 ) ;
dispc_write_reg ( DISPC_DIVISOR , l ) ;
}
2009-11-12 11:41:42 +02:00
/* FUNCGATED */
2010-12-02 11:27:13 +00:00
if ( dss_has_feature ( FEAT_FUNCGATED ) )
REG_FLD_MOD ( DISPC_CONFIG , 1 , 9 , 9 ) ;
2009-11-12 11:41:42 +02:00
2012-09-11 12:04:47 +05:30
dispc_setup_color_conv_coef ( ) ;
2009-11-12 11:41:42 +02:00
dispc_set_loadmode ( OMAP_DSS_LOAD_FRAME_ONLY ) ;
2012-08-22 16:56:57 +03:00
dispc_init_fifos ( ) ;
2011-06-21 09:35:36 +03:00
dispc_configure_burst_sizes ( ) ;
2011-09-08 11:29:17 +05:30
dispc_ovl_enable_zorder_planes ( ) ;
2009-11-12 11:41:42 +02:00
}
2012-07-03 12:26:51 +05:30
static const struct dispc_features omap24xx_dispc_feats __initconst = {
. sw_start = 5 ,
. fp_start = 15 ,
. bp_start = 27 ,
. sw_max = 64 ,
. vp_max = 255 ,
. hp_max = 256 ,
2012-11-14 13:50:15 +05:30
. mgr_width_start = 10 ,
. mgr_height_start = 26 ,
. mgr_width_max = 2048 ,
. mgr_height_max = 2048 ,
2012-07-03 12:26:51 +05:30
. calc_scaling = dispc_ovl_calc_scaling_24xx ,
. calc_core_clk = calc_core_clk_24xx ,
2012-08-22 16:56:57 +03:00
. num_fifos = 3 ,
2012-11-08 10:01:33 +02:00
. no_framedone_tv = true ,
2012-07-03 12:26:51 +05:30
} ;
static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = {
. sw_start = 5 ,
. fp_start = 15 ,
. bp_start = 27 ,
. sw_max = 64 ,
. vp_max = 255 ,
. hp_max = 256 ,
2012-11-14 13:50:15 +05:30
. mgr_width_start = 10 ,
. mgr_height_start = 26 ,
. mgr_width_max = 2048 ,
. mgr_height_max = 2048 ,
2012-07-03 12:26:51 +05:30
. calc_scaling = dispc_ovl_calc_scaling_34xx ,
. calc_core_clk = calc_core_clk_34xx ,
2012-08-22 16:56:57 +03:00
. num_fifos = 3 ,
2012-11-08 10:01:33 +02:00
. no_framedone_tv = true ,
2012-07-03 12:26:51 +05:30
} ;
static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = {
. sw_start = 7 ,
. fp_start = 19 ,
. bp_start = 31 ,
. sw_max = 256 ,
. vp_max = 4095 ,
. hp_max = 4096 ,
2012-11-14 13:50:15 +05:30
. mgr_width_start = 10 ,
. mgr_height_start = 26 ,
. mgr_width_max = 2048 ,
. mgr_height_max = 2048 ,
2012-07-03 12:26:51 +05:30
. calc_scaling = dispc_ovl_calc_scaling_34xx ,
. calc_core_clk = calc_core_clk_34xx ,
2012-08-22 16:56:57 +03:00
. num_fifos = 3 ,
2012-11-08 10:01:33 +02:00
. no_framedone_tv = true ,
2012-07-03 12:26:51 +05:30
} ;
static const struct dispc_features omap44xx_dispc_feats __initconst = {
. sw_start = 7 ,
. fp_start = 19 ,
. bp_start = 31 ,
. sw_max = 256 ,
. vp_max = 4095 ,
. hp_max = 4096 ,
2012-11-14 13:50:15 +05:30
. mgr_width_start = 10 ,
. mgr_height_start = 26 ,
. mgr_width_max = 2048 ,
. mgr_height_max = 2048 ,
2012-07-03 12:26:51 +05:30
. calc_scaling = dispc_ovl_calc_scaling_44xx ,
. calc_core_clk = calc_core_clk_44xx ,
2012-08-22 16:56:57 +03:00
. num_fifos = 5 ,
2012-08-22 16:57:02 +03:00
. gfx_fifo_workaround = true ,
2012-07-03 12:26:51 +05:30
} ;
2012-11-14 13:50:16 +05:30
static const struct dispc_features omap54xx_dispc_feats __initconst = {
. sw_start = 7 ,
. fp_start = 19 ,
. bp_start = 31 ,
. sw_max = 256 ,
. vp_max = 4095 ,
. hp_max = 4096 ,
. mgr_width_start = 11 ,
. mgr_height_start = 27 ,
. mgr_width_max = 4096 ,
. mgr_height_max = 4096 ,
. calc_scaling = dispc_ovl_calc_scaling_44xx ,
. calc_core_clk = calc_core_clk_44xx ,
. num_fifos = 5 ,
. gfx_fifo_workaround = true ,
} ;
2012-09-28 12:54:03 +03:00
static int __init dispc_init_features ( struct platform_device * pdev )
2012-07-03 12:26:51 +05:30
{
const struct dispc_features * src ;
struct dispc_features * dst ;
2012-09-28 12:54:03 +03:00
dst = devm_kzalloc ( & pdev - > dev , sizeof ( * dst ) , GFP_KERNEL ) ;
2012-07-03 12:26:51 +05:30
if ( ! dst ) {
2012-09-28 12:54:03 +03:00
dev_err ( & pdev - > dev , " Failed to allocate DISPC Features \n " ) ;
2012-07-03 12:26:51 +05:30
return - ENOMEM ;
}
2012-10-18 13:46:29 +03:00
switch ( omapdss_get_version ( ) ) {
2012-09-28 12:54:03 +03:00
case OMAPDSS_VER_OMAP24xx :
2012-07-03 12:26:51 +05:30
src = & omap24xx_dispc_feats ;
2012-09-28 12:54:03 +03:00
break ;
case OMAPDSS_VER_OMAP34xx_ES1 :
src = & omap34xx_rev1_0_dispc_feats ;
break ;
case OMAPDSS_VER_OMAP34xx_ES3 :
case OMAPDSS_VER_OMAP3630 :
case OMAPDSS_VER_AM35xx :
src = & omap34xx_rev3_0_dispc_feats ;
break ;
case OMAPDSS_VER_OMAP4430_ES1 :
case OMAPDSS_VER_OMAP4430_ES2 :
case OMAPDSS_VER_OMAP4 :
2012-07-03 12:26:51 +05:30
src = & omap44xx_dispc_feats ;
2012-09-28 12:54:03 +03:00
break ;
case OMAPDSS_VER_OMAP5 :
2012-11-14 13:50:16 +05:30
src = & omap54xx_dispc_feats ;
2012-09-28 12:54:03 +03:00
break ;
default :
2012-07-03 12:26:51 +05:30
return - ENODEV ;
}
memcpy ( dst , src , sizeof ( * dst ) ) ;
dispc . feat = dst ;
return 0 ;
}
2011-01-24 06:22:00 +00:00
/* DISPC HW IP initialisation */
2012-02-17 17:41:13 +02:00
static int __init omap_dispchw_probe ( struct platform_device * pdev )
2011-01-24 06:22:00 +00:00
{
u32 rev ;
2011-02-23 08:41:03 +00:00
int r = 0 ;
2011-01-24 06:22:04 +00:00
struct resource * dispc_mem ;
2011-05-27 10:52:19 +03:00
struct clk * clk ;
2011-01-24 06:22:04 +00:00
2011-01-24 06:22:00 +00:00
dispc . pdev = pdev ;
2012-09-28 12:54:03 +03:00
r = dispc_init_features ( dispc . pdev ) ;
2012-07-03 12:26:51 +05:30
if ( r )
return r ;
2011-01-24 06:22:00 +00:00
spin_lock_init ( & dispc . irq_lock ) ;
# ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
spin_lock_init ( & dispc . irq_stats_lock ) ;
dispc . irq_stats . last_reset = jiffies ;
# endif
INIT_WORK ( & dispc . error_work , dispc_error_worker ) ;
2011-01-24 06:22:04 +00:00
dispc_mem = platform_get_resource ( dispc . pdev , IORESOURCE_MEM , 0 ) ;
if ( ! dispc_mem ) {
DSSERR ( " can't get IORESOURCE_MEM DISPC \n " ) ;
2012-01-25 13:31:04 +02:00
return - EINVAL ;
2011-01-24 06:22:04 +00:00
}
2012-01-25 13:31:04 +02:00
2012-01-24 14:00:45 +01:00
dispc . base = devm_ioremap ( & pdev - > dev , dispc_mem - > start ,
resource_size ( dispc_mem ) ) ;
2011-01-24 06:22:00 +00:00
if ( ! dispc . base ) {
DSSERR ( " can't ioremap DISPC \n " ) ;
2012-01-25 13:31:04 +02:00
return - ENOMEM ;
2011-02-23 08:41:03 +00:00
}
2012-01-25 13:31:04 +02:00
2011-02-23 08:41:03 +00:00
dispc . irq = platform_get_irq ( dispc . pdev , 0 ) ;
if ( dispc . irq < 0 ) {
DSSERR ( " platform_get_irq failed \n " ) ;
2012-01-25 13:31:04 +02:00
return - ENODEV ;
2011-02-23 08:41:03 +00:00
}
2012-01-24 14:00:45 +01:00
r = devm_request_irq ( & pdev - > dev , dispc . irq , omap_dispc_irq_handler ,
IRQF_SHARED , " OMAP DISPC " , dispc . pdev ) ;
2011-02-23 08:41:03 +00:00
if ( r < 0 ) {
DSSERR ( " request_irq failed \n " ) ;
2012-01-25 13:31:04 +02:00
return r ;
}
clk = clk_get ( & pdev - > dev , " fck " ) ;
if ( IS_ERR ( clk ) ) {
DSSERR ( " can't get fck \n " ) ;
r = PTR_ERR ( clk ) ;
return r ;
2011-01-24 06:22:00 +00:00
}
2012-01-25 13:31:04 +02:00
dispc . dss_clk = clk ;
2011-05-27 10:52:19 +03:00
pm_runtime_enable ( & pdev - > dev ) ;
r = dispc_runtime_get ( ) ;
if ( r )
goto err_runtime_get ;
2011-01-24 06:22:00 +00:00
_omap_dispc_initial_config ( ) ;
_omap_dispc_initialize_irq ( ) ;
rev = dispc_read_reg ( DISPC_REVISION ) ;
2011-01-24 06:22:03 +00:00
dev_dbg ( & pdev - > dev , " OMAP DISPC rev %d.%d \n " ,
2011-01-24 06:22:00 +00:00
FLD_GET ( rev , 7 , 4 ) , FLD_GET ( rev , 3 , 0 ) ) ;
2011-05-27 10:52:19 +03:00
dispc_runtime_put ( ) ;
2011-01-24 06:22:00 +00:00
2012-03-02 18:01:07 +02:00
dss_debugfs_create_file ( " dispc " , dispc_dump_regs ) ;
# ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
dss_debugfs_create_file ( " dispc_irq " , dispc_dump_irqs ) ;
# endif
2011-01-24 06:22:00 +00:00
return 0 ;
2011-05-27 10:52:19 +03:00
err_runtime_get :
pm_runtime_disable ( & pdev - > dev ) ;
clk_put ( dispc . dss_clk ) ;
2011-02-23 08:41:03 +00:00
return r ;
2011-01-24 06:22:00 +00:00
}
2012-02-17 17:41:13 +02:00
static int __exit omap_dispchw_remove ( struct platform_device * pdev )
2011-01-24 06:22:00 +00:00
{
2011-05-27 10:52:19 +03:00
pm_runtime_disable ( & pdev - > dev ) ;
clk_put ( dispc . dss_clk ) ;
2011-01-24 06:22:00 +00:00
return 0 ;
}
2011-05-27 10:52:19 +03:00
static int dispc_runtime_suspend ( struct device * dev )
{
dispc_save_context ( ) ;
return 0 ;
}
static int dispc_runtime_resume ( struct device * dev )
{
2011-06-01 15:54:06 +03:00
dispc_restore_context ( ) ;
2011-05-27 10:52:19 +03:00
return 0 ;
}
static const struct dev_pm_ops dispc_pm_ops = {
. runtime_suspend = dispc_runtime_suspend ,
. runtime_resume = dispc_runtime_resume ,
} ;
2011-01-24 06:22:00 +00:00
static struct platform_driver omap_dispchw_driver = {
2012-02-17 17:41:13 +02:00
. remove = __exit_p ( omap_dispchw_remove ) ,
2011-01-24 06:22:00 +00:00
. driver = {
. name = " omapdss_dispc " ,
. owner = THIS_MODULE ,
2011-05-27 10:52:19 +03:00
. pm = & dispc_pm_ops ,
2011-01-24 06:22:00 +00:00
} ,
} ;
2012-02-17 17:41:13 +02:00
int __init dispc_init_platform_driver ( void )
2011-01-24 06:22:00 +00:00
{
2012-03-07 12:53:18 +02:00
return platform_driver_probe ( & omap_dispchw_driver , omap_dispchw_probe ) ;
2011-01-24 06:22:00 +00:00
}
2012-02-17 17:41:13 +02:00
void __exit dispc_uninit_platform_driver ( void )
2011-01-24 06:22:00 +00:00
{
2012-02-23 15:32:37 +02:00
platform_driver_unregister ( & omap_dispchw_driver ) ;
2011-01-24 06:22:00 +00:00
}