2009-08-07 13:15:50 +03:00
/*
* linux / drivers / video / omap2 / dss / dpi . 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 "DPI"
# include <linux/kernel.h>
# include <linux/delay.h>
2011-07-10 13:20:26 -04:00
# include <linux/export.h>
2010-02-04 17:03:41 +02:00
# include <linux/err.h>
2009-08-07 13:15:50 +03:00
# include <linux/errno.h>
2010-02-04 17:03:41 +02:00
# include <linux/platform_device.h>
# include <linux/regulator/consumer.h>
2009-08-07 13:15:50 +03:00
2011-05-11 14:05:07 +03:00
# include <video/omapdss.h>
2009-08-07 13:15:50 +03:00
# include <plat/cpu.h>
# include "dss.h"
static struct {
2010-02-04 17:03:41 +02:00
struct regulator * vdds_dsi_reg ;
2011-05-12 17:26:26 +05:30
struct platform_device * dsidev ;
2009-08-07 13:15:50 +03:00
} dpi ;
2011-05-12 17:26:26 +05:30
static struct platform_device * dpi_get_dsidev ( enum omap_dss_clk_source clk )
{
int dsi_module ;
dsi_module = clk = = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1 ;
return dsi_get_dsidev_from_id ( dsi_module ) ;
}
2011-04-12 13:52:26 +05:30
static bool dpi_use_dsi_pll ( struct omap_dss_device * dssdev )
{
if ( dssdev - > clocks . dispc . dispc_fclk_src = =
OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC | |
2011-05-12 17:26:29 +05:30
dssdev - > clocks . dispc . dispc_fclk_src = =
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC | |
2011-04-12 13:52:26 +05:30
dssdev - > clocks . dispc . channel . lcd_clk_src = =
2011-05-12 17:26:29 +05:30
OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC | |
dssdev - > clocks . dispc . channel . lcd_clk_src = =
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC )
2011-04-12 13:52:26 +05:30
return true ;
else
return false ;
}
2010-12-02 11:27:11 +00:00
static int dpi_set_dsi_clk ( struct omap_dss_device * dssdev , bool is_tft ,
unsigned long pck_req , unsigned long * fck , int * lck_div ,
int * pck_div )
2009-08-07 13:15:50 +03:00
{
struct dsi_clock_info dsi_cinfo ;
struct dispc_clock_info dispc_cinfo ;
int r ;
2011-05-12 17:26:26 +05:30
r = dsi_pll_calc_clock_div_pck ( dpi . dsidev , is_tft , pck_req ,
& dsi_cinfo , & dispc_cinfo ) ;
2009-08-07 13:15:50 +03:00
if ( r )
return r ;
2011-05-12 17:26:26 +05:30
r = dsi_pll_set_clock_div ( dpi . dsidev , & dsi_cinfo ) ;
2009-08-07 13:15:50 +03:00
if ( r )
return r ;
2011-04-12 13:52:24 +05:30
dss_select_dispc_clk_source ( dssdev - > clocks . dispc . dispc_fclk_src ) ;
2009-08-07 13:15:50 +03:00
2011-08-16 13:45:15 +03:00
r = dispc_mgr_set_clock_div ( dssdev - > manager - > id , & dispc_cinfo ) ;
2011-08-10 11:25:36 +03:00
if ( r ) {
dss_select_dispc_clk_source ( OMAP_DSS_CLK_SRC_FCK ) ;
2009-08-07 13:15:50 +03:00
return r ;
2011-08-10 11:25:36 +03:00
}
2009-08-07 13:15:50 +03:00
2011-02-24 14:17:30 +05:30
* fck = dsi_cinfo . dsi_pll_hsdiv_dispc_clk ;
2009-08-07 13:15:50 +03:00
* lck_div = dispc_cinfo . lck_div ;
* pck_div = dispc_cinfo . pck_div ;
return 0 ;
}
2011-04-12 13:52:26 +05:30
2010-12-02 11:27:11 +00:00
static int dpi_set_dispc_clk ( struct omap_dss_device * dssdev , bool is_tft ,
unsigned long pck_req , unsigned long * fck , int * lck_div ,
int * pck_div )
2009-08-07 13:15:50 +03:00
{
struct dss_clock_info dss_cinfo ;
struct dispc_clock_info dispc_cinfo ;
int r ;
r = dss_calc_clock_div ( is_tft , pck_req , & dss_cinfo , & dispc_cinfo ) ;
if ( r )
return r ;
r = dss_set_clock_div ( & dss_cinfo ) ;
if ( r )
return r ;
2011-08-16 13:45:15 +03:00
r = dispc_mgr_set_clock_div ( dssdev - > manager - > id , & dispc_cinfo ) ;
2009-08-07 13:15:50 +03:00
if ( r )
return r ;
* fck = dss_cinfo . fck ;
* lck_div = dispc_cinfo . lck_div ;
* pck_div = dispc_cinfo . pck_div ;
return 0 ;
}
static int dpi_set_mode ( struct omap_dss_device * dssdev )
{
struct omap_video_timings * t = & dssdev - > panel . timings ;
2011-04-12 13:52:26 +05:30
int lck_div = 0 , pck_div = 0 ;
unsigned long fck = 0 ;
2009-08-07 13:15:50 +03:00
unsigned long pck ;
bool is_tft ;
int r = 0 ;
2011-08-16 13:45:15 +03:00
dispc_mgr_set_pol_freq ( dssdev - > manager - > id , dssdev - > panel . config ,
2010-12-02 11:27:11 +00:00
dssdev - > panel . acbi , dssdev - > panel . acb ) ;
2009-08-07 13:15:50 +03:00
is_tft = ( dssdev - > panel . config & OMAP_DSS_LCD_TFT ) ! = 0 ;
2011-04-12 13:52:26 +05:30
if ( dpi_use_dsi_pll ( dssdev ) )
r = dpi_set_dsi_clk ( dssdev , is_tft , t - > pixel_clock * 1000 ,
& fck , & lck_div , & pck_div ) ;
else
r = dpi_set_dispc_clk ( dssdev , is_tft , t - > pixel_clock * 1000 ,
& fck , & lck_div , & pck_div ) ;
2009-08-07 13:15:50 +03:00
if ( r )
2011-05-27 10:52:19 +03:00
return r ;
2009-08-07 13:15:50 +03:00
pck = fck / lck_div / pck_div / 1000 ;
if ( pck ! = t - > pixel_clock ) {
DSSWARN ( " Could not find exact pixel clock. "
" Requested %d kHz, got %lu kHz \n " ,
t - > pixel_clock , pck ) ;
t - > pixel_clock = pck ;
}
2012-04-26 20:10:46 +05:30
dss_mgr_set_timings ( dssdev - > manager , t ) ;
2009-08-07 13:15:50 +03:00
2011-05-27 10:52:19 +03:00
return 0 ;
2009-08-07 13:15:50 +03:00
}
2011-05-27 10:52:19 +03:00
static void dpi_basic_init ( struct omap_dss_device * dssdev )
2009-08-07 13:15:50 +03:00
{
bool is_tft ;
is_tft = ( dssdev - > panel . config & OMAP_DSS_LCD_TFT ) ! = 0 ;
2011-08-22 17:41:57 +05:30
dispc_mgr_set_io_pad_mode ( DSS_IO_PAD_MODE_BYPASS ) ;
dispc_mgr_enable_stallmode ( dssdev - > manager - > id , false ) ;
2011-08-16 13:45:15 +03:00
dispc_mgr_set_lcd_display_type ( dssdev - > manager - > id , is_tft ?
2010-12-02 11:27:10 +00:00
OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN ) ;
2011-08-16 13:45:15 +03:00
dispc_mgr_set_tft_data_lines ( dssdev - > manager - > id ,
2010-12-02 11:27:10 +00:00
dssdev - > phy . dpi . data_lines ) ;
2009-08-07 13:15:50 +03:00
}
2010-01-12 15:12:07 +02:00
int omapdss_dpi_display_enable ( struct omap_dss_device * dssdev )
2009-08-07 13:15:50 +03:00
{
int r ;
2012-02-07 09:44:55 +00:00
if ( cpu_is_omap34xx ( ) & & ! dpi . vdds_dsi_reg ) {
DSSERR ( " no VDSS_DSI regulator \n " ) ;
return - ENODEV ;
}
2011-06-23 16:38:21 +03:00
if ( dssdev - > manager = = NULL ) {
DSSERR ( " failed to enable display: no manager \n " ) ;
return - ENODEV ;
}
2009-08-07 13:15:50 +03:00
r = omap_dss_start_device ( dssdev ) ;
if ( r ) {
DSSERR ( " failed to start device \n " ) ;
2011-05-27 10:52:19 +03:00
goto err_start_dev ;
2009-08-07 13:15:50 +03:00
}
2010-02-04 17:03:41 +02:00
if ( cpu_is_omap34xx ( ) ) {
r = regulator_enable ( dpi . vdds_dsi_reg ) ;
if ( r )
2011-05-27 10:52:19 +03:00
goto err_reg_enable ;
2010-02-04 17:03:41 +02:00
}
2011-05-27 10:52:19 +03:00
r = dss_runtime_get ( ) ;
if ( r )
goto err_get_dss ;
2009-08-07 13:15:50 +03:00
2011-05-27 10:52:19 +03:00
r = dispc_runtime_get ( ) ;
2009-08-07 13:15:50 +03:00
if ( r )
2011-05-27 10:52:19 +03:00
goto err_get_dispc ;
dpi_basic_init ( dssdev ) ;
2009-08-07 13:15:50 +03:00
2011-04-12 13:52:26 +05:30
if ( dpi_use_dsi_pll ( dssdev ) ) {
2011-05-27 10:52:19 +03:00
r = dsi_runtime_get ( dpi . dsidev ) ;
if ( r )
goto err_get_dsi ;
2011-05-12 17:26:26 +05:30
r = dsi_pll_init ( dpi . dsidev , 0 , 1 ) ;
2011-04-12 13:52:26 +05:30
if ( r )
2011-05-27 10:52:19 +03:00
goto err_dsi_pll_init ;
2011-04-12 13:52:26 +05:30
}
2009-08-07 13:15:50 +03:00
r = dpi_set_mode ( dssdev ) ;
if ( r )
2011-05-27 10:52:19 +03:00
goto err_set_mode ;
2009-08-07 13:15:50 +03:00
mdelay ( 2 ) ;
2011-11-21 13:42:58 +02:00
r = dss_mgr_enable ( dssdev - > manager ) ;
if ( r )
goto err_mgr_enable ;
2009-08-07 13:15:50 +03:00
return 0 ;
2011-11-21 13:42:58 +02:00
err_mgr_enable :
2011-05-27 10:52:19 +03:00
err_set_mode :
2011-04-12 13:52:26 +05:30
if ( dpi_use_dsi_pll ( dssdev ) )
2011-05-18 11:33:44 +03:00
dsi_pll_uninit ( dpi . dsidev , true ) ;
2011-05-27 10:52:19 +03:00
err_dsi_pll_init :
if ( dpi_use_dsi_pll ( dssdev ) )
dsi_runtime_put ( dpi . dsidev ) ;
err_get_dsi :
dispc_runtime_put ( ) ;
err_get_dispc :
dss_runtime_put ( ) ;
err_get_dss :
2010-02-04 17:03:41 +02:00
if ( cpu_is_omap34xx ( ) )
regulator_disable ( dpi . vdds_dsi_reg ) ;
2011-05-27 10:52:19 +03:00
err_reg_enable :
2009-08-07 13:15:50 +03:00
omap_dss_stop_device ( dssdev ) ;
2011-05-27 10:52:19 +03:00
err_start_dev :
2009-08-07 13:15:50 +03:00
return r ;
}
2010-01-12 15:12:07 +02:00
EXPORT_SYMBOL ( omapdss_dpi_display_enable ) ;
2009-08-07 13:15:50 +03:00
2010-01-12 15:12:07 +02:00
void omapdss_dpi_display_disable ( struct omap_dss_device * dssdev )
2009-08-07 13:15:50 +03:00
{
2011-11-04 10:22:46 +02:00
dss_mgr_disable ( dssdev - > manager ) ;
2009-08-07 13:15:50 +03:00
2011-04-12 13:52:26 +05:30
if ( dpi_use_dsi_pll ( dssdev ) ) {
dss_select_dispc_clk_source ( OMAP_DSS_CLK_SRC_FCK ) ;
2011-05-12 17:26:26 +05:30
dsi_pll_uninit ( dpi . dsidev , true ) ;
2011-05-27 10:52:19 +03:00
dsi_runtime_put ( dpi . dsidev ) ;
2011-04-12 13:52:26 +05:30
}
2009-08-07 13:15:50 +03:00
2011-05-27 10:52:19 +03:00
dispc_runtime_put ( ) ;
dss_runtime_put ( ) ;
2009-08-07 13:15:50 +03:00
2010-02-04 17:03:41 +02:00
if ( cpu_is_omap34xx ( ) )
regulator_disable ( dpi . vdds_dsi_reg ) ;
2009-08-07 13:15:50 +03:00
omap_dss_stop_device ( dssdev ) ;
}
2010-01-12 15:12:07 +02:00
EXPORT_SYMBOL ( omapdss_dpi_display_disable ) ;
2009-08-07 13:15:50 +03:00
2010-01-20 12:11:25 +02:00
void dpi_set_timings ( struct omap_dss_device * dssdev ,
2009-08-07 13:15:50 +03:00
struct omap_video_timings * timings )
{
2011-05-27 10:52:19 +03:00
int r ;
2009-08-07 13:15:50 +03:00
DSSDBG ( " dpi_set_timings \n " ) ;
dssdev - > panel . timings = * timings ;
if ( dssdev - > state = = OMAP_DSS_DISPLAY_ACTIVE ) {
2011-05-27 10:52:19 +03:00
r = dss_runtime_get ( ) ;
if ( r )
return ;
r = dispc_runtime_get ( ) ;
if ( r ) {
dss_runtime_put ( ) ;
return ;
}
2009-08-07 13:15:50 +03:00
dpi_set_mode ( dssdev ) ;
2011-05-27 10:52:19 +03:00
dispc_runtime_put ( ) ;
dss_runtime_put ( ) ;
2009-08-07 13:15:50 +03:00
}
}
2010-01-20 12:11:25 +02:00
EXPORT_SYMBOL ( dpi_set_timings ) ;
2009-08-07 13:15:50 +03:00
2010-01-20 12:11:25 +02:00
int dpi_check_timings ( struct omap_dss_device * dssdev ,
2009-08-07 13:15:50 +03:00
struct omap_video_timings * timings )
{
bool is_tft ;
int r ;
int lck_div , pck_div ;
unsigned long fck ;
unsigned long pck ;
2011-04-12 13:52:26 +05:30
struct dispc_clock_info dispc_cinfo ;
2009-08-07 13:15:50 +03:00
2012-04-16 12:53:44 +05:30
if ( ! dispc_mgr_timings_ok ( dssdev - > manager - > id , timings ) )
2009-08-07 13:15:50 +03:00
return - EINVAL ;
if ( timings - > pixel_clock = = 0 )
return - EINVAL ;
is_tft = ( dssdev - > panel . config & OMAP_DSS_LCD_TFT ) ! = 0 ;
2011-04-12 13:52:26 +05:30
if ( dpi_use_dsi_pll ( dssdev ) ) {
2009-08-07 13:15:50 +03:00
struct dsi_clock_info dsi_cinfo ;
2011-05-12 17:26:26 +05:30
r = dsi_pll_calc_clock_div_pck ( dpi . dsidev , is_tft ,
2009-08-07 13:15:50 +03:00
timings - > pixel_clock * 1000 ,
& dsi_cinfo , & dispc_cinfo ) ;
if ( r )
return r ;
2011-02-24 14:17:30 +05:30
fck = dsi_cinfo . dsi_pll_hsdiv_dispc_clk ;
2011-04-12 13:52:26 +05:30
} else {
2009-08-07 13:15:50 +03:00
struct dss_clock_info dss_cinfo ;
r = dss_calc_clock_div ( is_tft , timings - > pixel_clock * 1000 ,
& dss_cinfo , & dispc_cinfo ) ;
if ( r )
return r ;
fck = dss_cinfo . fck ;
}
2011-04-12 13:52:26 +05:30
lck_div = dispc_cinfo . lck_div ;
pck_div = dispc_cinfo . pck_div ;
2009-08-07 13:15:50 +03:00
pck = fck / lck_div / pck_div / 1000 ;
timings - > pixel_clock = pck ;
return 0 ;
}
2010-01-20 12:11:25 +02:00
EXPORT_SYMBOL ( dpi_check_timings ) ;
2009-08-07 13:15:50 +03:00
int dpi_init_display ( struct omap_dss_device * dssdev )
{
DSSDBG ( " init_display \n " ) ;
2011-02-22 15:53:46 +02:00
if ( cpu_is_omap34xx ( ) & & dpi . vdds_dsi_reg = = NULL ) {
struct regulator * vdds_dsi ;
2009-08-07 13:15:50 +03:00
2011-02-22 15:53:46 +02:00
vdds_dsi = dss_get_vdds_dsi ( ) ;
if ( IS_ERR ( vdds_dsi ) ) {
2010-02-04 17:03:41 +02:00
DSSERR ( " can't get VDDS_DSI regulator \n " ) ;
2011-02-22 15:53:46 +02:00
return PTR_ERR ( vdds_dsi ) ;
2010-02-04 17:03:41 +02:00
}
2011-02-22 15:53:46 +02:00
dpi . vdds_dsi_reg = vdds_dsi ;
2010-02-04 17:03:41 +02:00
}
2011-05-12 17:26:26 +05:30
if ( dpi_use_dsi_pll ( dssdev ) ) {
enum omap_dss_clk_source dispc_fclk_src =
dssdev - > clocks . dispc . dispc_fclk_src ;
dpi . dsidev = dpi_get_dsidev ( dispc_fclk_src ) ;
}
2009-08-07 13:15:50 +03:00
return 0 ;
}
2011-03-02 12:32:48 +02:00
int dpi_init ( void )
2011-02-22 15:53:46 +02:00
{
return 0 ;
}
2009-08-07 13:15:50 +03:00
void dpi_exit ( void )
{
}