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>
2009-11-12 11:41:42 +02:00
# include <plat/clock.h>
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 ] ;
} ;
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
2011-08-05 19:06:04 +05:30
u32 fifo_size [ MAX_DSS_OVERLAYS ] ;
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
# 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 ,
} ;
2009-11-12 11:41:42 +02:00
static void _omap_dispc_set_irqs ( void ) ;
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
}
2011-06-01 15:54:06 +03:00
static int dispc_get_ctx_loss_count ( void )
{
struct device * dev = & dispc . pdev - > dev ;
struct omap_display_platform_data * pdata = dev - > platform_data ;
struct omap_dss_board_info * board_data = pdata - > board_data ;
int cnt ;
if ( ! board_data - > get_context_loss_count )
return - ENOENT ;
cnt = board_data - > get_context_loss_count ( dev ) ;
WARN_ONCE ( cnt < 0 , " get_context_loss_count failed: %d \n " , cnt ) ;
return cnt ;
}
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 ) ;
}
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
dispc . ctx_loss_cnt = dispc_get_ctx_loss_count ( ) ;
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 ;
ctx = dispc_get_ctx_loss_count ( ) ;
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 ) ;
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 ) ;
2010-03-05 01:13:11 +02:00
/* clear spurious SYNC_LOST_DIGIT interrupts */
dispc_write_reg ( DISPC_IRQSTATUS , DISPC_IRQ_SYNC_LOST_DIGIT ) ;
/*
* 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 ) ;
2011-05-27 10:52:19 +03:00
WARN_ON ( r < 0 ) ;
2009-11-12 11:41:42 +02:00
}
2011-09-08 12:30:19 +05:30
static inline bool dispc_mgr_is_lcd ( enum omap_channel channel )
{
if ( channel = = OMAP_DSS_CHANNEL_LCD | |
channel = = OMAP_DSS_CHANNEL_LCD2 )
return true ;
else
return false ;
}
2011-05-27 10:52:19 +03:00
2011-09-13 18:28:41 +05:30
static struct omap_dss_device * dispc_mgr_get_device ( enum omap_channel channel )
{
struct omap_overlay_manager * mgr =
omap_dss_get_overlay_manager ( channel ) ;
return mgr ? mgr - > device : NULL ;
}
2011-11-07 15:50:09 +02:00
u32 dispc_mgr_get_vsync_irq ( enum omap_channel channel )
{
switch ( channel ) {
case OMAP_DSS_CHANNEL_LCD :
return DISPC_IRQ_VSYNC ;
case OMAP_DSS_CHANNEL_LCD2 :
return DISPC_IRQ_VSYNC2 ;
case OMAP_DSS_CHANNEL_DIGIT :
return DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN ;
default :
BUG ( ) ;
}
}
2011-11-18 15:39:52 +02:00
u32 dispc_mgr_get_framedone_irq ( enum omap_channel channel )
{
switch ( channel ) {
case OMAP_DSS_CHANNEL_LCD :
return DISPC_IRQ_FRAMEDONE ;
case OMAP_DSS_CHANNEL_LCD2 :
return DISPC_IRQ_FRAMEDONE2 ;
case OMAP_DSS_CHANNEL_DIGIT :
return 0 ;
default :
BUG ( ) ;
}
}
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
{
int bit ;
2011-09-08 12:30:19 +05:30
if ( dispc_mgr_is_lcd ( channel ) )
2009-11-12 11:41:42 +02:00
bit = 5 ; /* GOLCD */
else
bit = 6 ; /* GODIGIT */
2010-12-02 11:27:12 +00:00
if ( channel = = OMAP_DSS_CHANNEL_LCD2 )
return REG_GET ( DISPC_CONTROL2 , bit , bit ) = = 1 ;
else
return REG_GET ( DISPC_CONTROL , bit , bit ) = = 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
{
int bit ;
2010-12-02 11:27:12 +00:00
bool enable_bit , go_bit ;
2009-11-12 11:41:42 +02:00
2011-09-08 12:30:19 +05:30
if ( dispc_mgr_is_lcd ( channel ) )
2009-11-12 11:41:42 +02:00
bit = 0 ; /* LCDENABLE */
else
bit = 1 ; /* DIGITALENABLE */
/* if the channel is not enabled, we don't need GO */
2010-12-02 11:27:12 +00:00
if ( channel = = OMAP_DSS_CHANNEL_LCD2 )
enable_bit = REG_GET ( DISPC_CONTROL2 , bit , bit ) = = 1 ;
else
enable_bit = REG_GET ( DISPC_CONTROL , bit , bit ) = = 1 ;
if ( ! enable_bit )
2011-05-19 14:12:26 +03:00
return ;
2009-11-12 11:41:42 +02:00
2011-09-08 12:30:19 +05:30
if ( dispc_mgr_is_lcd ( channel ) )
2009-11-12 11:41:42 +02:00
bit = 5 ; /* GOLCD */
else
bit = 6 ; /* GODIGIT */
2010-12-02 11:27:12 +00:00
if ( channel = = OMAP_DSS_CHANNEL_LCD2 )
go_bit = REG_GET ( DISPC_CONTROL2 , bit , bit ) = = 1 ;
else
go_bit = REG_GET ( DISPC_CONTROL , bit , bit ) = = 1 ;
if ( go_bit ) {
2009-11-12 11:41:42 +02:00
DSSERR ( " GO bit not down for channel %d \n " , channel ) ;
2011-05-19 14:12:26 +03:00
return ;
2009-11-12 11:41:42 +02:00
}
2010-12-02 11:27:12 +00:00
DSSDBG ( " GO %s \n " , channel = = OMAP_DSS_CHANNEL_LCD ? " LCD " :
( channel = = OMAP_DSS_CHANNEL_LCD2 ? " LCD2 " : " DIGIT " ) ) ;
2009-11-12 11:41:42 +02:00
2010-12-02 11:27:12 +00:00
if ( channel = = OMAP_DSS_CHANNEL_LCD2 )
REG_FLD_MOD ( DISPC_CONTROL2 , 1 , bit , bit ) ;
else
REG_FLD_MOD ( DISPC_CONTROL , 1 , bit , bit ) ;
2009-11-12 11:41:42 +02:00
}
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
}
}
static void _dispc_setup_color_conv_coef ( void )
{
2011-08-05 19:06:03 +05:30
int i ;
2009-11-12 11:41:42 +02:00
const struct color_conv_coef {
int ry , rcr , rcb , gy , gcr , gcb , by , bcr , bcb ;
int full_range ;
} ctbl_bt601_5 = {
298 , 409 , 0 , 298 , - 208 , - 100 , 298 , 0 , 517 , 0 ,
} ;
const struct color_conv_coef * ct ;
# define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
ct = & ctbl_bt601_5 ;
2011-08-05 19:06:03 +05:30
for ( i = 1 ; i < dss_feat_get_num_ovls ( ) ; i + + ) {
dispc_write_reg ( DISPC_OVL_CONV_COEF ( i , 0 ) ,
CVAL ( ct - > rcr , ct - > ry ) ) ;
dispc_write_reg ( DISPC_OVL_CONV_COEF ( i , 1 ) ,
CVAL ( ct - > gy , ct - > rcb ) ) ;
dispc_write_reg ( DISPC_OVL_CONV_COEF ( i , 2 ) ,
CVAL ( ct - > gcb , ct - > gcr ) ) ;
dispc_write_reg ( DISPC_OVL_CONV_COEF ( i , 3 ) ,
CVAL ( ct - > bcr , ct - > by ) ) ;
dispc_write_reg ( DISPC_OVL_CONV_COEF ( i , 4 ) ,
CVAL ( 0 , ct - > bcb ) ) ;
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES ( i ) , ct - > full_range ,
11 , 11 ) ;
}
2009-11-12 11:41:42 +02:00
# undef CVAL
}
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 ) ;
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_pos ( enum omap_plane plane , int x , int y )
2009-11-12 11:41:42 +02:00
{
u32 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
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_pic_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
if ( plane = = OMAP_DSS_GFX )
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
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_vid_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
dispc_write_reg ( DISPC_OVL_SIZE ( plane ) , val ) ;
2009-11-12 11:41:42 +02:00
}
2011-09-08 11:29:17 +05:30
static void dispc_ovl_set_zorder ( enum omap_plane plane , u8 zorder )
{
struct omap_overlay * ovl = omap_dss_get_overlay ( plane ) ;
if ( ( ovl - > caps & OMAP_DSS_OVL_CAP_ZORDER ) = = 0 )
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 ) ;
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_set_pre_mult_alpha ( enum omap_plane plane , bool enable )
2010-11-04 12:28:42 +01:00
{
2011-08-15 15:18:20 +03:00
struct omap_overlay * ovl = omap_dss_get_overlay ( plane ) ;
2010-11-04 12:28:42 +01:00
2011-08-15 15:18:20 +03:00
if ( ( ovl - > 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
}
2011-08-16 13:25:00 +03:00
static void dispc_ovl_setup_global_alpha ( enum omap_plane plane , 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 ;
2011-08-15 15:18:20 +03:00
struct omap_overlay * ovl = omap_dss_get_overlay ( plane ) ;
2011-08-15 11:51:50 +03:00
2011-08-15 15:18:20 +03:00
if ( ( ovl - > 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 :
BUG ( ) ; break ;
}
} 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 :
BUG ( ) ; break ;
}
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
}
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 ;
default :
BUG ( ) ;
}
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 ( ) ;
}
val = dispc_read_reg ( DISPC_OVL_ATTRIBUTES ( plane ) ) ;
if ( dss_has_feature ( FEAT_MGR_LCD2 ) ) {
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 ;
}
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 )
{
2011-09-13 18:20:33 +05:30
static const unsigned shifts [ ] = { 6 , 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 */
for ( i = 0 ; i < omap_dss_get_num_overlays ( ) ; + + 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
{
u16 reg ;
if ( channel = = OMAP_DSS_CHANNEL_LCD )
reg = DISPC_CONFIG ;
else if ( channel = = OMAP_DSS_CHANNEL_LCD2 )
reg = DISPC_CONFIG2 ;
else
return ;
REG_FLD_MOD ( reg , enable , 15 , 15 ) ;
}
2011-11-04 18:14:20 +02:00
static void dispc_mgr_set_cpr_coef ( enum omap_channel channel ,
2011-06-21 09:34:30 +03:00
struct omap_dss_cpr_coefs * coefs )
{
u32 coef_r , coef_g , coef_b ;
2011-09-08 12:30:19 +05:30
if ( ! dispc_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
}
2011-09-14 11:52:54 +05:30
static void dispc_ovl_enable_replication ( enum omap_plane plane , 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
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 ;
val = FLD_VAL ( height - 1 , 26 , 16 ) | FLD_VAL ( width - 1 , 10 , 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
}
static void dispc_read_plane_fifo_sizes ( void )
{
u32 size ;
int plane ;
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
2011-08-05 19:06:04 +05:30
for ( plane = 0 ; plane < dss_feat_get_num_ovls ( ) ; + + plane ) {
2011-06-21 09:35:36 +03:00
size = REG_GET ( DISPC_OVL_FIFO_SIZE_STATUS ( plane ) , start , end ) ;
size * = unit ;
2009-11-12 11:41:42 +02:00
dispc . fifo_size [ plane ] = size ;
}
}
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
{
return dispc . fifo_size [ plane ] ;
}
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 ,
u32 * fifo_low , u32 * fifo_high , bool use_fifomerge )
{
/*
* 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 ;
for ( i = 0 ; i < omap_dss_get_num_overlays ( ) ; + + i )
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
*/
if ( dss_has_feature ( FEAT_OMAP3_DSI_FIFO_BUG ) ) {
* fifo_low = ovl_fifo_size - burst_size * 2 ;
* fifo_high = total_fifo_size - burst_size ;
} 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
}
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 ;
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 */
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES2 ( plane ) , 0 , 8 , 8 ) ;
return ;
}
switch ( color_mode ) {
case OMAP_DSS_COLOR_NV12 :
/* UV is subsampled by 2 vertically*/
orig_height > > = 1 ;
/* UV is subsampled by 2 horz.*/
orig_width > > = 1 ;
break ;
case OMAP_DSS_COLOR_YUV2 :
case OMAP_DSS_COLOR_UYVY :
/*For YUV422 with 90/270 rotation,
* we don ' t upsample chroma
*/
if ( rotation = = OMAP_DSS_ROT_0 | |
rotation = = OMAP_DSS_ROT_180 )
/* UV is subsampled by 2 hrz*/
orig_width > > = 1 ;
/* must use FIR for YUV422 if rotated */
if ( rotation ! = OMAP_DSS_ROT_0 )
scale_x = scale_y = true ;
break ;
default :
BUG ( ) ;
}
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 ) ;
REG_FLD_MOD ( DISPC_OVL_ATTRIBUTES2 ( plane ) ,
( scale_x | | scale_y ) ? 1 : 0 , 8 , 8 ) ;
/* 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
dispc_ovl_set_vid_accu2_0 ( plane , 0x80 , 0 ) ;
dispc_ovl_set_vid_accu2_1 ( plane , 0x80 , 0 ) ;
2011-05-19 19:47:54 +05:30
}
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 ( ) ;
}
}
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 ( ) ;
}
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 ( ) ;
}
}
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-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 .
*/
static int check_horiz_timing_omap3 ( enum omap_channel channel , u16 pos_x ,
u16 width , u16 height , u16 out_width , u16 out_height )
{
int DS = DIV_ROUND_UP ( height , out_height ) ;
struct omap_dss_device * dssdev = dispc_mgr_get_device ( channel ) ;
struct omap_video_timings t = dssdev - > panel . timings ;
unsigned long nonactive , lclk , pclk ;
static const u8 limits [ 3 ] = { 8 , 10 , 20 } ;
u64 val , blank ;
int i ;
nonactive = t . x_res + t . hfp + t . hsw + t . hbp - out_width ;
pclk = dispc_mgr_pclk_rate ( channel ) ;
if ( dispc_mgr_is_lcd ( channel ) )
lclk = dispc_mgr_lclk_rate ( channel ) ;
else
lclk = dispc_fclk_rate ( ) ;
i = 0 ;
if ( out_height < height )
i + + ;
if ( out_width < width )
i + + ;
blank = div_u64 ( ( u64 ) ( t . hbp + t . hsw + t . hfp ) * lclk , pclk ) ;
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 " ,
val , max ( 0 , DS - 2 ) * width ) ;
if ( val < max ( 0 , DS - 2 ) * width )
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 " ,
val , max ( 0 , DS - 1 ) * width ) ;
if ( val < max ( 0 , DS - 1 ) * width )
return - EINVAL ;
return 0 ;
}
2012-04-23 12:16:50 +05:30
static unsigned long calc_core_clk_five_taps ( enum omap_channel channel ,
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 ;
2011-08-16 13:45:15 +03:00
u64 tmp , pclk = dispc_mgr_pclk_rate ( channel ) ;
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 ) {
2011-09-08 12:51:10 +05:30
struct omap_dss_device * dssdev = dispc_mgr_get_device ( channel ) ;
unsigned int ppl = dssdev - > panel . 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-04-23 12:16:50 +05:30
static unsigned long calc_core_clk ( enum omap_channel channel , u16 width ,
2010-12-02 11:27:11 +00:00
u16 height , u16 out_width , u16 out_height )
2009-11-12 11:41:42 +02:00
{
unsigned int hf , vf ;
2012-01-30 10:54:17 +05:30
unsigned long pclk = dispc_mgr_pclk_rate ( channel ) ;
2009-11-12 11:41:42 +02:00
/*
* 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 ;
2011-12-19 14:03:56 +05:30
if ( cpu_is_omap24xx ( ) ) {
if ( vf > 1 & & hf > 1 )
2012-01-30 10:54:17 +05:30
return pclk * 4 ;
2011-12-19 14:03:56 +05:30
else
2012-01-30 10:54:17 +05:30
return pclk * 2 ;
2011-12-19 14:03:56 +05:30
} else if ( cpu_is_omap34xx ( ) ) {
2012-01-30 10:54:17 +05:30
return pclk * vf * hf ;
2011-12-19 14:03:56 +05:30
} else {
2012-01-30 10:54:17 +05:30
if ( hf > 1 )
return DIV_ROUND_UP ( pclk , out_width ) * width ;
else
return pclk ;
2011-12-19 14:03:56 +05:30
}
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 ,
enum omap_channel channel , 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-04-02 20:43:17 +05:30
int * x_predecim , int * y_predecim , u16 pos_x )
2011-09-08 13:15:11 +05:30
{
struct omap_overlay * ovl = omap_dss_get_overlay ( plane ) ;
2011-09-08 13:25:17 +05:30
const int maxdownscale = dss_feat_get_param_max ( FEAT_PARAM_DOWNSCALE ) ;
2011-12-19 14:03:56 +05:30
const int maxsinglelinewidth =
dss_feat_get_param_max ( FEAT_PARAM_LINEWIDTH ) ;
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-04-02 20:43:16 +05:30
int decim_x , decim_y , error , min_factor ;
u16 in_width , in_height , in_width_max = 0 ;
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 ;
if ( ( ovl - > caps & OMAP_DSS_OVL_CAP_SCALE ) = = 0 )
return - EINVAL ;
2011-09-08 13:15:11 +05:30
2012-04-02 20:43:16 +05:30
* x_predecim = max_decim_limit ;
* y_predecim = max_decim_limit ;
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 ) ;
min_factor = min ( decim_x , decim_y ) ;
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 ;
2011-12-19 14:03:56 +05:30
if ( cpu_is_omap24xx ( ) ) {
* five_taps = false ;
2012-04-02 20:43:16 +05:30
do {
in_height = DIV_ROUND_UP ( height , decim_y ) ;
in_width = DIV_ROUND_UP ( width , decim_x ) ;
2012-04-23 12:16:50 +05:30
core_clk = calc_core_clk ( channel , in_width , in_height ,
2012-04-02 20:43:16 +05:30
out_width , out_height ) ;
2012-04-23 12:16:50 +05:30
error = ( in_width > maxsinglelinewidth | | ! core_clk | |
core_clk > dispc_core_clk_rate ( ) ) ;
2012-04-02 20:43:16 +05:30
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 ;
}
2011-12-19 14:03:56 +05:30
} else if ( cpu_is_omap34xx ( ) ) {
2012-04-02 20:43:16 +05:30
do {
in_height = DIV_ROUND_UP ( height , decim_y ) ;
in_width = DIV_ROUND_UP ( width , decim_x ) ;
2012-04-23 12:16:50 +05:30
core_clk = calc_core_clk_five_taps ( channel , in_width ,
in_height , out_width , out_height , color_mode ) ;
2012-04-02 20:43:16 +05:30
2012-04-02 20:43:17 +05:30
error = check_horiz_timing_omap3 ( channel , pos_x ,
in_width , in_height , out_width , out_height ) ;
2012-04-02 20:43:16 +05:30
if ( in_width > maxsinglelinewidth )
if ( in_height > out_height & &
in_height < out_height * 2 )
* five_taps = false ;
if ( ! * five_taps )
2012-04-23 12:16:50 +05:30
core_clk = calc_core_clk ( channel , in_width ,
in_height , out_width , out_height ) ;
2012-04-02 20:43:17 +05:30
error = ( error | | in_width > maxsinglelinewidth * 2 | |
2012-04-02 20:43:16 +05:30
( in_width > maxsinglelinewidth & & * five_taps ) | |
2012-04-23 12:16:50 +05:30
! core_clk | | core_clk > dispc_core_clk_rate ( ) ) ;
2012-04-02 20:43:16 +05:30
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-04-02 20:43:17 +05:30
if ( check_horiz_timing_omap3 ( channel , pos_x , width , height ,
out_width , out_height ) ) {
DSSERR ( " horizontal timing too tight \n " ) ;
return - EINVAL ;
}
2012-04-02 20:43:16 +05:30
if ( in_width > ( maxsinglelinewidth * 2 ) ) {
2011-12-19 14:03:56 +05:30
DSSERR ( " Cannot setup scaling " ) ;
DSSERR ( " width exceeds maximum width possible " ) ;
return - EINVAL ;
}
2012-04-02 20:43:16 +05:30
if ( in_width > maxsinglelinewidth & & * five_taps ) {
DSSERR ( " cannot setup scaling with five taps " ) ;
return - EINVAL ;
2011-12-19 14:03:56 +05:30
}
} else {
2012-04-02 20:43:16 +05:30
int decim_x_min = decim_x ;
in_height = DIV_ROUND_UP ( height , decim_y ) ;
2012-04-23 12:16:50 +05:30
in_width_max = dispc_core_clk_rate ( ) /
2012-04-02 20:43:16 +05:30
DIV_ROUND_UP ( dispc_mgr_pclk_rate ( channel ) ,
out_width ) ;
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 ) {
2011-12-19 14:03:56 +05:30
DSSERR ( " Cannot scale width exceeds max line width " ) ;
return - EINVAL ;
}
2012-04-02 20:43:16 +05:30
2012-04-23 12:16:50 +05:30
core_clk = calc_core_clk ( channel , in_width , in_height ,
out_width , out_height ) ;
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 ;
}
2011-09-14 11:10:10 +05:30
int dispc_ovl_setup ( enum omap_plane plane , struct omap_overlay_info * oi ,
2011-11-03 17:03:44 +02:00
bool ilace , bool replication )
2009-11-12 11:41:42 +02:00
{
2011-09-08 13:15:11 +05:30
struct omap_overlay * ovl = omap_dss_get_overlay ( plane ) ;
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 ;
2011-09-14 11:10:10 +05:30
u16 frame_height = oi - > height ;
2009-11-12 11:41:42 +02:00
unsigned int field_offset = 0 ;
2012-04-02 20:43:16 +05:30
u16 in_height = oi - > height ;
u16 in_width = oi - > width ;
u16 out_width , out_height ;
2011-11-03 17:03:44 +02:00
enum omap_channel channel ;
2012-04-02 20:43:16 +05:30
int x_predecim = 1 , y_predecim = 1 ;
2011-11-03 17:03:44 +02:00
channel = dispc_ovl_get_channel_out ( plane ) ;
2009-11-12 11:41:42 +02:00
2011-09-14 11:10:10 +05:30
DSSDBG ( " dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
2011-11-03 17:00:07 +02:00
" %dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d \n " ,
plane , oi - > paddr , oi - > p_uv_addr ,
2011-09-14 11:52:54 +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 ,
2011-11-03 17:00:07 +02:00
oi - > mirror , ilace , channel , replication ) ;
2011-05-19 14:12:26 +03:00
2011-09-14 11:10:10 +05:30
if ( oi - > paddr = = 0 )
2009-11-12 11:41:42 +02:00
return - EINVAL ;
2012-04-02 20:43:16 +05:30
out_width = oi - > out_width = = 0 ? oi - > width : oi - > out_width ;
out_height = oi - > out_height = = 0 ? oi - > height : oi - > out_height ;
2011-11-03 16:08:27 +02:00
2012-04-02 20:43:16 +05:30
if ( ilace & & oi - > 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 ;
2011-09-14 11:10:10 +05:30
oi - > 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, "
" out_height %d \n " ,
2012-04-02 20:43:16 +05:30
in_height , oi - > pos_y , out_height ) ;
2009-11-12 11:41:42 +02:00
}
2011-09-14 11:10:10 +05:30
if ( ! dss_feat_color_mode_supported ( plane , oi - > color_mode ) )
2010-11-25 17:58:10 +05:30
return - EINVAL ;
2012-04-02 20:43:16 +05:30
r = dispc_ovl_calc_scaling ( plane , channel , in_width , in_height ,
out_width , out_height , oi - > color_mode , & five_taps ,
2012-04-02 20:43:17 +05:30
& x_predecim , & y_predecim , oi - > pos_x ) ;
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 ) ;
2011-09-08 13:15:11 +05:30
if ( oi - > color_mode = = OMAP_DSS_COLOR_YUV2 | |
oi - > color_mode = = OMAP_DSS_COLOR_UYVY | |
oi - > color_mode = = OMAP_DSS_COLOR_NV12 )
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 ;
2011-09-14 11:10:10 +05:30
if ( oi - > rotation_type = = OMAP_DSS_ROT_DMA )
calc_dma_rotation_offset ( oi - > rotation , oi - > mirror ,
2012-04-02 20:43:16 +05:30
oi - > screen_width , in_width , frame_height ,
2011-09-14 11:10:10 +05:30
oi - > 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
2011-09-14 11:10:10 +05:30
calc_vrfb_rotation_offset ( oi - > rotation , oi - > mirror ,
2012-04-02 20:43:16 +05:30
oi - > screen_width , in_width , frame_height ,
2011-09-14 11:10:10 +05:30
oi - > 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 ) ;
2011-09-14 11:10:10 +05:30
dispc_ovl_set_color_mode ( plane , oi - > color_mode ) ;
2009-11-12 11:41:42 +02:00
2011-09-14 11:10:10 +05:30
dispc_ovl_set_ba0 ( plane , oi - > paddr + offset0 ) ;
dispc_ovl_set_ba1 ( plane , oi - > paddr + offset1 ) ;
2009-11-12 11:41:42 +02:00
2011-09-14 11:10:10 +05:30
if ( OMAP_DSS_COLOR_NV12 = = oi - > color_mode ) {
dispc_ovl_set_ba0_uv ( plane , oi - > p_uv_addr + offset0 ) ;
dispc_ovl_set_ba1_uv ( plane , oi - > 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-04-02 20:43:16 +05:30
DSSDBG ( " %d,%d %dx%d -> %dx%d \n " , oi - > pos_x , oi - > pos_y , in_width ,
in_height , out_width , out_height ) ;
2009-11-12 11:41:42 +02:00
2011-09-14 11:10:10 +05:30
dispc_ovl_set_pos ( plane , oi - > pos_x , oi - > pos_y ) ;
2009-11-12 11:41:42 +02:00
2012-04-02 20:43:16 +05:30
dispc_ovl_set_pic_size ( plane , in_width , in_height ) ;
2009-11-12 11:41:42 +02:00
2011-09-08 13:15:11 +05:30
if ( ovl - > 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 ,
2011-09-14 11:10:10 +05:30
oi - > color_mode , oi - > rotation ) ;
2012-04-02 20:43:16 +05:30
dispc_ovl_set_vid_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
}
2011-09-14 11:10:10 +05:30
dispc_ovl_set_rotation_attrs ( plane , oi - > rotation , oi - > mirror ,
oi - > color_mode ) ;
2009-11-12 11:41:42 +02:00
2011-09-08 11:29:17 +05:30
dispc_ovl_set_zorder ( plane , oi - > zorder ) ;
2011-09-14 11:10:10 +05:30
dispc_ovl_set_pre_mult_alpha ( plane , oi - > pre_mult_alpha ) ;
dispc_ovl_setup_global_alpha ( plane , oi - > global_alpha ) ;
2009-11-12 11:41:42 +02:00
2011-09-14 11:52:54 +05:30
dispc_ovl_enable_replication ( plane , replication ) ;
2009-11-12 11:41:42 +02:00
return 0 ;
}
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
}
static void dispc_disable_isr ( void * data , u32 mask )
{
struct completion * compl = data ;
complete ( compl ) ;
}
2010-12-02 11:27:12 +00:00
static void _enable_lcd_out ( enum omap_channel channel , bool enable )
2009-11-12 11:41:42 +02:00
{
2011-10-12 10:17:02 +03:00
if ( channel = = OMAP_DSS_CHANNEL_LCD2 ) {
2010-12-02 11:27:12 +00:00
REG_FLD_MOD ( DISPC_CONTROL2 , enable ? 1 : 0 , 0 , 0 ) ;
2011-10-12 10:17:02 +03:00
/* flush posted write */
dispc_read_reg ( DISPC_CONTROL2 ) ;
} else {
2010-12-02 11:27:12 +00:00
REG_FLD_MOD ( DISPC_CONTROL , enable ? 1 : 0 , 0 , 0 ) ;
2011-10-12 10:17:02 +03:00
dispc_read_reg ( DISPC_CONTROL ) ;
}
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:45:15 +03:00
static void dispc_mgr_enable_lcd_out ( enum omap_channel channel , bool enable )
2009-11-12 11:41:42 +02:00
{
struct completion frame_done_completion ;
bool is_on ;
int r ;
2010-12-02 11:27:12 +00:00
u32 irq ;
2009-11-12 11:41:42 +02:00
/* When we disable LCD output, we need to wait until frame is done.
* Otherwise the DSS is still working , and turning off the clocks
* prevents DSS from going to OFF mode */
2010-12-02 11:27:12 +00:00
is_on = channel = = OMAP_DSS_CHANNEL_LCD2 ?
REG_GET ( DISPC_CONTROL2 , 0 , 0 ) :
REG_GET ( DISPC_CONTROL , 0 , 0 ) ;
irq = channel = = OMAP_DSS_CHANNEL_LCD2 ? DISPC_IRQ_FRAMEDONE2 :
DISPC_IRQ_FRAMEDONE ;
2009-11-12 11:41:42 +02:00
if ( ! enable & & is_on ) {
init_completion ( & frame_done_completion ) ;
r = omap_dispc_register_isr ( dispc_disable_isr ,
2010-12-02 11:27:12 +00:00
& frame_done_completion , irq ) ;
2009-11-12 11:41:42 +02:00
if ( r )
DSSERR ( " failed to register FRAMEDONE isr \n " ) ;
}
2010-12-02 11:27:12 +00:00
_enable_lcd_out ( channel , enable ) ;
2009-11-12 11:41:42 +02:00
if ( ! enable & & is_on ) {
if ( ! wait_for_completion_timeout ( & frame_done_completion ,
msecs_to_jiffies ( 100 ) ) )
DSSERR ( " timeout waiting for FRAME DONE \n " ) ;
r = omap_dispc_unregister_isr ( dispc_disable_isr ,
2010-12-02 11:27:12 +00:00
& frame_done_completion , irq ) ;
2009-11-12 11:41:42 +02:00
if ( r )
DSSERR ( " failed to unregister FRAMEDONE isr \n " ) ;
}
}
static void _enable_digit_out ( bool enable )
{
REG_FLD_MOD ( DISPC_CONTROL , enable ? 1 : 0 , 1 , 1 ) ;
2011-10-12 10:17:02 +03:00
/* flush posted write */
dispc_read_reg ( DISPC_CONTROL ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:45:15 +03:00
static void dispc_mgr_enable_digit_out ( bool enable )
2009-11-12 11:41:42 +02:00
{
struct completion frame_done_completion ;
2011-08-31 14:42:49 +03:00
enum dss_hdmi_venc_clk_source_select src ;
int r , i ;
u32 irq_mask ;
int num_irqs ;
2009-11-12 11:41:42 +02:00
2011-05-19 14:12:26 +03:00
if ( REG_GET ( DISPC_CONTROL , 1 , 1 ) = = enable )
2009-11-12 11:41:42 +02:00
return ;
2011-08-31 14:42:49 +03:00
src = dss_get_hdmi_venc_clk_source ( ) ;
2009-11-12 11:41:42 +02:00
if ( enable ) {
unsigned long flags ;
/* When we enable digit output, we'll get an extra digit
* sync lost interrupt , that we need to ignore */
spin_lock_irqsave ( & dispc . irq_lock , flags ) ;
dispc . irq_error_mask & = ~ DISPC_IRQ_SYNC_LOST_DIGIT ;
_omap_dispc_set_irqs ( ) ;
spin_unlock_irqrestore ( & dispc . irq_lock , flags ) ;
}
/* When we disable digit output, we need to wait until fields are done.
* Otherwise the DSS is still working , and turning off the clocks
* prevents DSS from going to OFF mode . And when enabling , we need to
* wait for the extra sync losts */
init_completion ( & frame_done_completion ) ;
2011-08-31 14:42:49 +03:00
if ( src = = DSS_HDMI_M_PCLK & & enable = = false ) {
irq_mask = DISPC_IRQ_FRAMEDONETV ;
num_irqs = 1 ;
} else {
irq_mask = DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD ;
/* XXX I understand from TRM that we should only wait for the
* current field to complete . But it seems we have to wait for
* both fields */
num_irqs = 2 ;
}
2009-11-12 11:41:42 +02:00
r = omap_dispc_register_isr ( dispc_disable_isr , & frame_done_completion ,
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
_enable_digit_out ( enable ) ;
2011-08-31 14:42:49 +03:00
for ( i = 0 ; i < num_irqs ; + + i ) {
if ( ! wait_for_completion_timeout ( & frame_done_completion ,
msecs_to_jiffies ( 100 ) ) )
DSSERR ( " timeout waiting for digit out to %s \n " ,
enable ? " start " : " stop " ) ;
}
2009-11-12 11:41:42 +02:00
2011-08-31 14:42:49 +03:00
r = omap_dispc_unregister_isr ( dispc_disable_isr , & frame_done_completion ,
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 ) ;
2009-11-12 11:41:42 +02:00
if ( enable ) {
unsigned long flags ;
spin_lock_irqsave ( & dispc . irq_lock , flags ) ;
2011-08-31 14:42:49 +03:00
dispc . irq_error_mask | = DISPC_IRQ_SYNC_LOST_DIGIT ;
2009-11-12 11:41:42 +02:00
dispc_write_reg ( DISPC_IRQSTATUS , DISPC_IRQ_SYNC_LOST_DIGIT ) ;
_omap_dispc_set_irqs ( ) ;
spin_unlock_irqrestore ( & dispc . irq_lock , flags ) ;
}
}
2011-08-16 13:45:15 +03:00
bool dispc_mgr_is_enabled ( enum omap_channel channel )
2010-01-08 17:14:53 +02:00
{
if ( channel = = OMAP_DSS_CHANNEL_LCD )
return ! ! REG_GET ( DISPC_CONTROL , 0 , 0 ) ;
else if ( channel = = OMAP_DSS_CHANNEL_DIGIT )
return ! ! REG_GET ( DISPC_CONTROL , 1 , 1 ) ;
2010-12-02 11:27:12 +00:00
else if ( channel = = OMAP_DSS_CHANNEL_LCD2 )
return ! ! REG_GET ( DISPC_CONTROL2 , 0 , 0 ) ;
2010-01-08 17:14:53 +02:00
else
BUG ( ) ;
}
2011-08-16 13:45:15 +03:00
void dispc_mgr_enable ( enum omap_channel channel , bool enable )
2010-01-08 17:14:53 +02:00
{
2011-09-08 12:30:19 +05:30
if ( dispc_mgr_is_lcd ( channel ) )
2011-08-16 13:45:15 +03:00
dispc_mgr_enable_lcd_out ( channel , enable ) ;
2010-01-08 17:14:53 +02:00
else if ( channel = = OMAP_DSS_CHANNEL_DIGIT )
2011-08-16 13:45:15 +03:00
dispc_mgr_enable_digit_out ( enable ) ;
2010-01-08 17:14:53 +02:00
else
BUG ( ) ;
}
2009-11-12 11:41:42 +02:00
void dispc_lcd_enable_signal_polarity ( bool act_high )
{
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 ) ;
}
2011-08-16 13:45:15 +03:00
void dispc_mgr_enable_fifohandcheck ( enum omap_channel channel , bool enable )
2009-11-12 11:41:42 +02:00
{
2010-12-02 11:27:12 +00:00
if ( channel = = OMAP_DSS_CHANNEL_LCD2 )
REG_FLD_MOD ( DISPC_CONFIG2 , enable ? 1 : 0 , 16 , 16 ) ;
else
REG_FLD_MOD ( DISPC_CONFIG , enable ? 1 : 0 , 16 , 16 ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:45:15 +03:00
void dispc_mgr_set_lcd_display_type ( enum omap_channel channel ,
2010-12-02 11:27:10 +00:00
enum omap_lcd_display_type type )
2009-11-12 11:41:42 +02:00
{
int mode ;
switch ( type ) {
case OMAP_DSS_LCD_DISPLAY_STN :
mode = 0 ;
break ;
case OMAP_DSS_LCD_DISPLAY_TFT :
mode = 1 ;
break ;
default :
BUG ( ) ;
return ;
}
2010-12-02 11:27:12 +00:00
if ( channel = = OMAP_DSS_CHANNEL_LCD2 )
REG_FLD_MOD ( DISPC_CONTROL2 , mode , 3 , 3 ) ;
else
REG_FLD_MOD ( DISPC_CONTROL , mode , 3 , 3 ) ;
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 )
{
if ( ch = = OMAP_DSS_CHANNEL_LCD )
REG_FLD_MOD ( DISPC_CONFIG , type , 11 , 11 ) ;
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 , type , 13 , 13 ) ;
2010-12-02 11:27:12 +00:00
else /* OMAP_DSS_CHANNEL_LCD2 */
REG_FLD_MOD ( DISPC_CONFIG2 , type , 11 , 11 ) ;
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
{
if ( ch = = OMAP_DSS_CHANNEL_LCD )
REG_FLD_MOD ( DISPC_CONFIG , enable , 10 , 10 ) ;
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 , 12 , 12 ) ;
2010-12-02 11:27:12 +00:00
else /* OMAP_DSS_CHANNEL_LCD2 */
REG_FLD_MOD ( DISPC_CONFIG2 , enable , 10 , 10 ) ;
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 ,
struct omap_overlay_manager_info * info )
{
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
2011-08-16 13:45:15 +03:00
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 ;
}
2010-12-02 11:27:12 +00:00
if ( channel = = OMAP_DSS_CHANNEL_LCD2 )
REG_FLD_MOD ( DISPC_CONTROL2 , code , 9 , 8 ) ;
else
REG_FLD_MOD ( DISPC_CONTROL , code , 9 , 8 ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-22 17:41:57 +05:30
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 ) ;
}
void dispc_mgr_enable_stallmode ( enum omap_channel channel , bool enable )
{
if ( channel = = OMAP_DSS_CHANNEL_LCD2 )
REG_FLD_MOD ( DISPC_CONTROL2 , enable , 11 , 11 ) ;
else
REG_FLD_MOD ( DISPC_CONTROL , enable , 11 , 11 ) ;
2009-11-12 11:41:42 +02:00
}
2012-04-16 12:53:44 +05:30
static bool _dispc_mgr_size_ok ( u16 width , u16 height )
{
return width < = dss_feat_get_param_max ( FEAT_PARAM_MGR_WIDTH ) & &
height < = dss_feat_get_param_max ( FEAT_PARAM_MGR_HEIGHT ) ;
}
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 )
{
if ( cpu_is_omap24xx ( ) | | omap_rev ( ) < OMAP3430_REV_ES3_0 ) {
if ( hsw < 1 | | hsw > 64 | |
hfp < 1 | | hfp > 256 | |
hbp < 1 | | hbp > 256 | |
vsw < 1 | | vsw > 64 | |
vfp < 0 | | vfp > 255 | |
vbp < 0 | | vbp > 255 )
return false ;
} else {
if ( hsw < 1 | | hsw > 256 | |
hfp < 1 | | hfp > 4096 | |
hbp < 1 | | hbp > 4096 | |
vsw < 1 | | vsw > 256 | |
vfp < 0 | | vfp > 4095 | |
vbp < 0 | | vbp > 4095 )
return false ;
}
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 ) ;
if ( dispc_mgr_is_lcd ( channel ) )
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 ,
2010-12-02 11:27:10 +00:00
int hfp , int hbp , int vsw , int vfp , int vbp )
2009-11-12 11:41:42 +02:00
{
u32 timing_h , timing_v ;
if ( cpu_is_omap24xx ( ) | | omap_rev ( ) < OMAP3430_REV_ES3_0 ) {
timing_h = FLD_VAL ( hsw - 1 , 5 , 0 ) | FLD_VAL ( hfp - 1 , 15 , 8 ) |
FLD_VAL ( hbp - 1 , 27 , 20 ) ;
timing_v = FLD_VAL ( vsw - 1 , 5 , 0 ) | FLD_VAL ( vfp , 15 , 8 ) |
FLD_VAL ( vbp , 27 , 20 ) ;
} else {
timing_h = FLD_VAL ( hsw - 1 , 7 , 0 ) | FLD_VAL ( hfp - 1 , 19 , 8 ) |
FLD_VAL ( hbp - 1 , 31 , 20 ) ;
timing_v = FLD_VAL ( vsw - 1 , 7 , 0 ) | FLD_VAL ( vfp , 19 , 8 ) |
FLD_VAL ( vbp , 31 , 20 ) ;
}
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 ) ;
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 ,
2010-12-02 11:27:10 +00:00
struct omap_video_timings * timings )
2009-11-12 11:41:42 +02:00
{
unsigned xtot , ytot ;
unsigned long ht , vt ;
2012-04-16 12:53:43 +05:30
DSSDBG ( " channel %d xres %u yres %u \n " , channel , timings - > x_res ,
timings - > y_res ) ;
2009-11-12 11:41:42 +02:00
2012-04-16 12:53:44 +05:30
if ( ! dispc_mgr_timings_ok ( channel , timings ) )
BUG ( ) ;
2009-11-12 11:41:42 +02:00
2012-04-16 12:53:44 +05:30
if ( dispc_mgr_is_lcd ( channel ) ) {
2012-04-16 12:53:43 +05:30
_dispc_mgr_set_lcd_timings ( channel , timings - > hsw , timings - > hfp ,
timings - > hbp , timings - > vsw , timings - > vfp ,
timings - > vbp ) ;
2009-11-12 11:41:42 +02:00
2012-04-16 12:53:43 +05:30
xtot = timings - > x_res + timings - > hfp + timings - > hsw +
timings - > hbp ;
ytot = timings - > y_res + timings - > vfp + timings - > vsw +
timings - > 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 " ,
2009-11-12 11:41:42 +02:00
timings - > hsw , timings - > hfp , timings - > hbp ,
timings - > vsw , timings - > vfp , timings - > vbp ) ;
2012-04-16 12:53:43 +05:30
DSSDBG ( " hsync %luHz, vsync %luHz \n " , ht , vt ) ;
}
2012-04-16 12:53:44 +05:30
dispc_mgr_set_size ( channel , timings - > x_res , timings - > 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 ( ) ;
}
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 ;
2011-03-03 09:27:59 -06:00
l = dispc_read_reg ( DISPC_DIVISORo ( channel ) ) ;
2009-11-12 11:41:42 +02:00
lcd = FLD_GET ( l , 23 , 16 ) ;
2011-03-08 05:50:35 -06:00
switch ( dss_get_lcd_clk_source ( channel ) ) {
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:35 -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:35 -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:35 -06:00
default :
BUG ( ) ;
}
2009-11-12 11:41:42 +02:00
return r / lcd ;
}
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 ;
2011-09-13 18:28:41 +05:30
if ( dispc_mgr_is_lcd ( channel ) ) {
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 {
struct omap_dss_device * dssdev =
dispc_mgr_get_device ( channel ) ;
switch ( dssdev - > type ) {
case OMAP_DISPLAY_TYPE_VENC :
return venc_get_pixel_clock ( ) ;
case OMAP_DISPLAY_TYPE_HDMI :
return hdmi_get_pixel_clock ( ) ;
default :
BUG ( ) ;
}
}
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 ;
}
2009-11-12 11:41:42 +02:00
void dispc_dump_clocks ( struct seq_file * s )
{
int lcd , pcd ;
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 ( ) ;
enum omap_dss_clk_source lcd_clk_src ;
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
seq_printf ( s , " - LCD1 - \n " ) ;
2011-03-08 05:50:35 -06:00
lcd_clk_src = dss_get_lcd_clk_source ( OMAP_DSS_CHANNEL_LCD ) ;
seq_printf ( s , " lcd1_clk source = %s (%s) \n " ,
dss_get_generic_clk_source_name ( lcd_clk_src ) ,
dss_feat_get_clk_source_name ( lcd_clk_src ) ) ;
2011-08-16 13:45:15 +03:00
dispc_mgr_get_lcd_divisor ( OMAP_DSS_CHANNEL_LCD , & lcd , & pcd ) ;
2010-12-02 11:27:12 +00:00
2010-12-02 11:27:11 +00:00
seq_printf ( s , " lck \t \t %-16lulck div \t %u \n " ,
2011-08-16 13:45:15 +03:00
dispc_mgr_lclk_rate ( OMAP_DSS_CHANNEL_LCD ) , lcd ) ;
2010-12-02 11:27:11 +00:00
seq_printf ( s , " pck \t \t %-16lupck div \t %u \n " ,
2011-08-16 13:45:15 +03:00
dispc_mgr_pclk_rate ( OMAP_DSS_CHANNEL_LCD ) , pcd ) ;
2010-12-02 11:27:12 +00:00
if ( dss_has_feature ( FEAT_MGR_LCD2 ) ) {
seq_printf ( s , " - LCD2 - \n " ) ;
2011-03-08 05:50:35 -06:00
lcd_clk_src = dss_get_lcd_clk_source ( OMAP_DSS_CHANNEL_LCD2 ) ;
seq_printf ( s , " lcd2_clk source = %s (%s) \n " ,
dss_get_generic_clk_source_name ( lcd_clk_src ) ,
dss_feat_get_clk_source_name ( lcd_clk_src ) ) ;
2011-08-16 13:45:15 +03:00
dispc_mgr_get_lcd_divisor ( OMAP_DSS_CHANNEL_LCD2 , & lcd , & pcd ) ;
2009-11-12 11:41:42 +02:00
2010-12-02 11:27:12 +00:00
seq_printf ( s , " lck \t \t %-16lulck div \t %u \n " ,
2011-08-16 13:45:15 +03:00
dispc_mgr_lclk_rate ( OMAP_DSS_CHANNEL_LCD2 ) , lcd ) ;
2010-12-02 11:27:12 +00:00
seq_printf ( s , " pck \t \t %-16lupck div \t %u \n " ,
2011-08-16 13:45:15 +03:00
dispc_mgr_pclk_rate ( OMAP_DSS_CHANNEL_LCD2 ) , pcd ) ;
2010-12-02 11:27:12 +00:00
}
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
void dispc_dump_irqs ( struct seq_file * s )
{
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 ) ;
}
2009-12-17 14:35:21 +02:00
# undef PIS
}
# endif
2009-11-12 11:41:42 +02:00
void dispc_dump_regs ( struct seq_file * s )
{
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 " ,
} ;
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
}
# 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], \
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 ] , \
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
}
2011-08-16 13:45:15 +03:00
static void _dispc_mgr_set_pol_freq ( enum omap_channel channel , bool onoff ,
bool rf , bool ieo , bool ipc , bool ihs , bool ivs , u8 acbi ,
u8 acb )
2009-11-12 11:41:42 +02:00
{
u32 l = 0 ;
DSSDBG ( " onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d \n " ,
onoff , rf , ieo , ipc , ihs , ivs , acbi , acb ) ;
l | = FLD_VAL ( onoff , 17 , 17 ) ;
l | = FLD_VAL ( rf , 16 , 16 ) ;
l | = FLD_VAL ( ieo , 15 , 15 ) ;
l | = FLD_VAL ( ipc , 14 , 14 ) ;
l | = FLD_VAL ( ihs , 13 , 13 ) ;
l | = FLD_VAL ( ivs , 12 , 12 ) ;
l | = FLD_VAL ( acbi , 11 , 8 ) ;
l | = FLD_VAL ( acb , 7 , 0 ) ;
2010-12-02 11:27:11 +00:00
dispc_write_reg ( DISPC_POL_FREQ ( channel ) , l ) ;
2009-11-12 11:41:42 +02:00
}
2011-08-16 13:45:15 +03:00
void dispc_mgr_set_pol_freq ( enum omap_channel channel ,
2010-12-02 11:27:11 +00:00
enum omap_panel_config config , u8 acbi , u8 acb )
2009-11-12 11:41:42 +02:00
{
2011-08-16 13:45:15 +03:00
_dispc_mgr_set_pol_freq ( channel , ( config & OMAP_DSS_LCD_ONOFF ) ! = 0 ,
2009-11-12 11:41:42 +02:00
( config & OMAP_DSS_LCD_RF ) ! = 0 ,
( config & OMAP_DSS_LCD_IEO ) ! = 0 ,
( config & OMAP_DSS_LCD_IPC ) ! = 0 ,
( config & OMAP_DSS_LCD_IHS ) ! = 0 ,
( config & OMAP_DSS_LCD_IVS ) ! = 0 ,
acbi , acb ) ;
}
/* with fck as input clock rate, find dispc dividers that produce req_pck */
void dispc_find_clk_divs ( bool is_tft , unsigned long req_pck , unsigned long fck ,
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 ) ;
if ( ! is_tft )
pcd_min = 3 ;
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 ;
}
2011-08-16 13:45:15 +03:00
int dispc_mgr_set_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
{
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
return 0 ;
}
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 ;
}
/* dispc.irq_lock has to be locked by the caller */
static void _omap_dispc_set_irqs ( void )
{
u32 mask ;
u32 old_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 ;
}
old_mask = dispc_read_reg ( DISPC_IRQENABLE ) ;
/* clear the irqstatus for newly enabled irqs */
dispc_write_reg ( DISPC_IRQSTATUS , ( mask ^ old_mask ) & mask ) ;
dispc_write_reg ( DISPC_IRQENABLE , mask ) ;
}
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 ) ;
# ifdef DEBUG
static void print_irq_status ( u32 status )
{
if ( ( status & dispc . irq_error_mask ) = = 0 )
return ;
printk ( KERN_DEBUG " DISPC IRQ: 0x%x: " , status ) ;
# define PIS(x) \
if ( status & DISPC_IRQ_ # # x ) \
printk ( # x " " ) ;
PIS ( GFX_FIFO_UNDERFLOW ) ;
PIS ( OCP_ERR ) ;
PIS ( VID1_FIFO_UNDERFLOW ) ;
PIS ( VID2_FIFO_UNDERFLOW ) ;
2011-09-13 18:20:33 +05:30
if ( dss_feat_get_num_ovls ( ) > 3 )
PIS ( VID3_FIFO_UNDERFLOW ) ;
2009-11-12 11:41:42 +02:00
PIS ( SYNC_LOST ) ;
PIS ( SYNC_LOST_DIGIT ) ;
2010-12-02 11:27:12 +00:00
if ( dss_has_feature ( FEAT_MGR_LCD2 ) )
PIS ( SYNC_LOST2 ) ;
2009-11-12 11:41:42 +02:00
# undef PIS
printk ( " \n " ) ;
}
# endif
/* 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 ) ;
irqstatus = dispc_read_reg ( DISPC_IRQSTATUS ) ;
2011-02-23 08:41:03 +00:00
irqenable = dispc_read_reg ( DISPC_IRQENABLE ) ;
/* 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
2009-11-12 11:41:42 +02:00
# ifdef DEBUG
if ( dss_debug )
print_irq_status ( irqstatus ) ;
# endif
/* Ack the interrupt. Do it here before clocks are possibly turned
* off */
dispc_write_reg ( DISPC_IRQSTATUS , irqstatus ) ;
/* flush posted write */
dispc_read_reg ( DISPC_IRQSTATUS ) ;
/* 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
} ;
static const unsigned sync_lost_bits [ ] = {
DISPC_IRQ_SYNC_LOST ,
DISPC_IRQ_SYNC_LOST_DIGIT ,
DISPC_IRQ_SYNC_LOST2 ,
} ;
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 ) ;
2009-11-12 11:41:42 +02:00
mdelay ( 50 ) ;
}
}
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 ) ;
bit = sync_lost_bits [ i ] ;
2009-11-12 11:41:42 +02:00
2011-08-15 11:51:50 +03:00
if ( bit & errors ) {
struct omap_dss_device * dssdev = mgr - > device ;
bool enable ;
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
2011-08-15 11:51:50 +03:00
enable = dssdev - > state = = OMAP_DSS_DISPLAY_ACTIVE ;
dssdev - > driver - > disable ( dssdev ) ;
2010-12-02 11:27:12 +00:00
for ( i = 0 ; i < omap_dss_get_num_overlays ( ) ; + + i ) {
struct omap_overlay * ovl ;
ovl = omap_dss_get_overlay ( i ) ;
2011-08-15 11:51:50 +03:00
if ( ovl - > id ! = OMAP_DSS_GFX & &
ovl - > manager = = mgr )
2011-08-16 13:25:00 +03:00
dispc_ovl_enable ( ovl - > id , false ) ;
2010-12-02 11:27:12 +00:00
}
2011-08-16 13:45:15 +03:00
dispc_mgr_go ( mgr - > id ) ;
2010-12-02 11:27:12 +00:00
mdelay ( 50 ) ;
2011-08-15 11:51:50 +03:00
2010-12-02 11:27:12 +00:00
if ( enable )
dssdev - > driver - > enable ( dssdev ) ;
}
}
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 ;
mgr = omap_dss_get_overlay_manager ( i ) ;
2011-12-11 14:02:27 -06:00
if ( mgr - > device & & mgr - > device - > driver )
mgr - > device - > driver - > disable ( mgr - > device ) ;
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 ;
if ( timeout = = - ERESTARTSYS )
return - ERESTARTSYS ;
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 ;
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 */
dispc_write_reg ( DISPC_IRQSTATUS , dispc_read_reg ( DISPC_IRQSTATUS ) ) ;
_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
_dispc_setup_color_conv_coef ( ) ;
dispc_set_loadmode ( OMAP_DSS_LOAD_FRAME_ONLY ) ;
dispc_read_plane_fifo_sizes ( ) ;
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
}
2011-01-24 06:22:00 +00:00
/* DISPC HW IP initialisation */
static int omap_dispchw_probe ( struct platform_device * pdev )
{
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 ;
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
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
}
static int omap_dispchw_remove ( struct platform_device * pdev )
{
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 ( ) ;
dss_runtime_put ( ) ;
return 0 ;
}
static int dispc_runtime_resume ( struct device * dev )
{
int r ;
r = dss_runtime_get ( ) ;
if ( r < 0 )
return r ;
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 = {
. probe = omap_dispchw_probe ,
. remove = omap_dispchw_remove ,
. 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
} ,
} ;
int dispc_init_platform_driver ( void )
{
return platform_driver_register ( & omap_dispchw_driver ) ;
}
void dispc_uninit_platform_driver ( void )
{
return platform_driver_unregister ( & omap_dispchw_driver ) ;
}