2014-05-23 21:35:27 +05:30
/*
* Copyright © 2014 Intel Corporation
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice ( including the next
* paragraph ) shall be included in all copies or substantial portions of the
* Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
* FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE .
*
* Author : Shobhit Kumar < shobhit . kumar @ intel . com >
*
*/
# include <drm/drmP.h>
# include <drm/drm_crtc.h>
# include <drm/drm_edid.h>
# include <drm/i915_drm.h>
2015-01-23 15:30:56 +02:00
# include <drm/drm_panel.h>
2014-05-23 21:35:27 +05:30
# include <linux/slab.h>
# include <video/mipi_display.h>
# include <asm/intel-mid.h>
# include <video/mipi_display.h>
# include "i915_drv.h"
# include "intel_drv.h"
# include "intel_dsi.h"
2015-01-23 15:30:56 +02:00
struct vbt_panel {
struct drm_panel panel ;
struct intel_dsi * intel_dsi ;
} ;
static inline struct vbt_panel * to_vbt_panel ( struct drm_panel * panel )
{
return container_of ( panel , struct vbt_panel , panel ) ;
}
2014-05-23 21:35:27 +05:30
# define MIPI_TRANSFER_MODE_SHIFT 0
# define MIPI_VIRTUAL_CHANNEL_SHIFT 1
# define MIPI_PORT_SHIFT 3
# define PREPARE_CNT_MAX 0x3F
# define EXIT_ZERO_CNT_MAX 0x3F
# define CLK_ZERO_CNT_MAX 0xFF
# define TRAIL_CNT_MAX 0x1F
# define NS_KHZ_RATIO 1000000
# define GPI0_NC_0_HV_DDI0_HPD 0x4130
# define GPIO_NC_0_HV_DDI0_PAD 0x4138
# define GPIO_NC_1_HV_DDI0_DDC_SDA 0x4120
# define GPIO_NC_1_HV_DDI0_DDC_SDA_PAD 0x4128
# define GPIO_NC_2_HV_DDI0_DDC_SCL 0x4110
# define GPIO_NC_2_HV_DDI0_DDC_SCL_PAD 0x4118
# define GPIO_NC_3_PANEL0_VDDEN 0x4140
# define GPIO_NC_3_PANEL0_VDDEN_PAD 0x4148
# define GPIO_NC_4_PANEL0_BLKEN 0x4150
# define GPIO_NC_4_PANEL0_BLKEN_PAD 0x4158
# define GPIO_NC_5_PANEL0_BLKCTL 0x4160
# define GPIO_NC_5_PANEL0_BLKCTL_PAD 0x4168
# define GPIO_NC_6_PCONF0 0x4180
# define GPIO_NC_6_PAD 0x4188
# define GPIO_NC_7_PCONF0 0x4190
# define GPIO_NC_7_PAD 0x4198
# define GPIO_NC_8_PCONF0 0x4170
# define GPIO_NC_8_PAD 0x4178
# define GPIO_NC_9_PCONF0 0x4100
# define GPIO_NC_9_PAD 0x4108
# define GPIO_NC_10_PCONF0 0x40E0
# define GPIO_NC_10_PAD 0x40E8
# define GPIO_NC_11_PCONF0 0x40F0
# define GPIO_NC_11_PAD 0x40F8
struct gpio_table {
u16 function_reg ;
u16 pad_reg ;
u8 init ;
} ;
static struct gpio_table gtable [ ] = {
{ GPI0_NC_0_HV_DDI0_HPD , GPIO_NC_0_HV_DDI0_PAD , 0 } ,
{ GPIO_NC_1_HV_DDI0_DDC_SDA , GPIO_NC_1_HV_DDI0_DDC_SDA_PAD , 0 } ,
{ GPIO_NC_2_HV_DDI0_DDC_SCL , GPIO_NC_2_HV_DDI0_DDC_SCL_PAD , 0 } ,
{ GPIO_NC_3_PANEL0_VDDEN , GPIO_NC_3_PANEL0_VDDEN_PAD , 0 } ,
{ GPIO_NC_4_PANEL0_BLKEN , GPIO_NC_4_PANEL0_BLKEN_PAD , 0 } ,
{ GPIO_NC_5_PANEL0_BLKCTL , GPIO_NC_5_PANEL0_BLKCTL_PAD , 0 } ,
{ GPIO_NC_6_PCONF0 , GPIO_NC_6_PAD , 0 } ,
{ GPIO_NC_7_PCONF0 , GPIO_NC_7_PAD , 0 } ,
{ GPIO_NC_8_PCONF0 , GPIO_NC_8_PAD , 0 } ,
{ GPIO_NC_9_PCONF0 , GPIO_NC_9_PAD , 0 } ,
{ GPIO_NC_10_PCONF0 , GPIO_NC_10_PAD , 0 } ,
{ GPIO_NC_11_PCONF0 , GPIO_NC_11_PAD , 0 }
} ;
2014-12-04 10:58:48 +05:30
static inline enum port intel_dsi_seq_port_to_port ( u8 port )
{
return port ? PORT_C : PORT_A ;
}
2015-01-16 14:27:21 +02:00
static const u8 * mipi_exec_send_packet ( struct intel_dsi * intel_dsi ,
const u8 * data )
2014-05-23 21:35:27 +05:30
{
2015-01-16 14:27:24 +02:00
struct mipi_dsi_device * dsi_device ;
u8 type , flags , seq_port ;
2014-05-23 21:35:27 +05:30
u16 len ;
2014-12-04 10:58:48 +05:30
enum port port ;
2014-05-23 21:35:27 +05:30
2015-01-16 14:27:24 +02:00
flags = * data + + ;
type = * data + + ;
len = * ( ( u16 * ) data ) ;
data + = 2 ;
seq_port = ( flags > > MIPI_PORT_SHIFT ) & 3 ;
2014-05-23 21:35:27 +05:30
2014-12-10 22:07:40 +05:30
/* For DSI single link on Port A & C, the seq_port value which is
* parsed from Sequence Block # 53 of VBT has been set to 0
* Now , read / write of packets for the DSI single link on Port A and
* Port C will based on the DVO port from VBT block 2.
*/
if ( intel_dsi - > ports = = ( 1 < < PORT_C ) )
port = PORT_C ;
else
port = intel_dsi_seq_port_to_port ( seq_port ) ;
2014-05-23 21:35:27 +05:30
2015-01-16 14:27:24 +02:00
dsi_device = intel_dsi - > dsi_hosts [ port ] - > device ;
if ( ! dsi_device ) {
DRM_DEBUG_KMS ( " no dsi device for port %c \n " , port_name ( port ) ) ;
goto out ;
}
2014-05-23 21:35:27 +05:30
2015-01-16 14:27:24 +02:00
if ( ( flags > > MIPI_TRANSFER_MODE_SHIFT ) & 1 )
dsi_device - > mode_flags & = ~ MIPI_DSI_MODE_LPM ;
else
dsi_device - > mode_flags | = MIPI_DSI_MODE_LPM ;
dsi_device - > channel = ( flags > > MIPI_VIRTUAL_CHANNEL_SHIFT ) & 3 ;
2014-05-23 21:35:27 +05:30
switch ( type ) {
case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM :
2015-01-16 14:27:24 +02:00
mipi_dsi_generic_write ( dsi_device , NULL , 0 ) ;
2014-05-23 21:35:27 +05:30
break ;
case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM :
2015-01-16 14:27:24 +02:00
mipi_dsi_generic_write ( dsi_device , data , 1 ) ;
2014-05-23 21:35:27 +05:30
break ;
case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM :
2015-01-16 14:27:24 +02:00
mipi_dsi_generic_write ( dsi_device , data , 2 ) ;
2014-05-23 21:35:27 +05:30
break ;
case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM :
case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM :
case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM :
DRM_DEBUG_DRIVER ( " Generic Read not yet implemented or used \n " ) ;
break ;
case MIPI_DSI_GENERIC_LONG_WRITE :
2015-01-16 14:27:24 +02:00
mipi_dsi_generic_write ( dsi_device , data , len ) ;
2014-05-23 21:35:27 +05:30
break ;
case MIPI_DSI_DCS_SHORT_WRITE :
2015-01-16 14:27:24 +02:00
mipi_dsi_dcs_write_buffer ( dsi_device , data , 1 ) ;
2014-05-23 21:35:27 +05:30
break ;
case MIPI_DSI_DCS_SHORT_WRITE_PARAM :
2015-01-16 14:27:24 +02:00
mipi_dsi_dcs_write_buffer ( dsi_device , data , 2 ) ;
2014-05-23 21:35:27 +05:30
break ;
case MIPI_DSI_DCS_READ :
DRM_DEBUG_DRIVER ( " DCS Read not yet implemented or used \n " ) ;
break ;
case MIPI_DSI_DCS_LONG_WRITE :
2015-01-16 14:27:24 +02:00
mipi_dsi_dcs_write_buffer ( dsi_device , data , len ) ;
2014-05-23 21:35:27 +05:30
break ;
2014-05-27 19:23:46 +05:30
}
2014-05-23 21:35:27 +05:30
2015-01-16 14:27:24 +02:00
out :
2014-05-23 21:35:27 +05:30
data + = len ;
return data ;
}
2015-01-16 14:27:21 +02:00
static const u8 * mipi_exec_delay ( struct intel_dsi * intel_dsi , const u8 * data )
2014-05-23 21:35:27 +05:30
{
2015-01-16 14:27:21 +02:00
u32 delay = * ( ( const u32 * ) data ) ;
2014-05-23 21:35:27 +05:30
usleep_range ( delay , delay + 10 ) ;
data + = 4 ;
return data ;
}
2015-01-16 14:27:21 +02:00
static const u8 * mipi_exec_gpio ( struct intel_dsi * intel_dsi , const u8 * data )
2014-05-23 21:35:27 +05:30
{
u8 gpio , action ;
u16 function , pad ;
u32 val ;
struct drm_device * dev = intel_dsi - > base . base . dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
gpio = * data + + ;
/* pull up/down */
action = * data + + ;
function = gtable [ gpio ] . function_reg ;
pad = gtable [ gpio ] . pad_reg ;
2015-05-26 20:42:30 +03:00
mutex_lock ( & dev_priv - > sb_lock ) ;
2014-05-23 21:35:27 +05:30
if ( ! gtable [ gpio ] . init ) {
/* program the function */
/* FIXME: remove constant below */
vlv_gpio_nc_write ( dev_priv , function , 0x2000CC00 ) ;
gtable [ gpio ] . init = 1 ;
}
val = 0x4 | action ;
/* pull up/down */
vlv_gpio_nc_write ( dev_priv , pad , val ) ;
2015-05-26 20:42:30 +03:00
mutex_unlock ( & dev_priv - > sb_lock ) ;
2014-05-23 21:35:27 +05:30
return data ;
}
2015-01-16 14:27:21 +02:00
typedef const u8 * ( * fn_mipi_elem_exec ) ( struct intel_dsi * intel_dsi ,
const u8 * data ) ;
2014-05-23 21:35:27 +05:30
static const fn_mipi_elem_exec exec_elem [ ] = {
NULL , /* reserved */
mipi_exec_send_packet ,
mipi_exec_delay ,
mipi_exec_gpio ,
NULL , /* status read; later */
} ;
/*
* MIPI Sequence from VBT # 53 parsing logic
* We have already separated each seqence during bios parsing
* Following is generic execution function for any sequence
*/
static const char * const seq_name [ ] = {
" UNDEFINED " ,
" MIPI_SEQ_ASSERT_RESET " ,
" MIPI_SEQ_INIT_OTP " ,
" MIPI_SEQ_DISPLAY_ON " ,
" MIPI_SEQ_DISPLAY_OFF " ,
" MIPI_SEQ_DEASSERT_RESET "
} ;
2015-01-16 14:27:21 +02:00
static void generic_exec_sequence ( struct intel_dsi * intel_dsi , const u8 * data )
2014-05-23 21:35:27 +05:30
{
fn_mipi_elem_exec mipi_elem_exec ;
int index ;
2015-01-16 14:27:21 +02:00
if ( ! data )
2014-05-23 21:35:27 +05:30
return ;
DRM_DEBUG_DRIVER ( " Starting MIPI sequence - %s \n " , seq_name [ * data ] ) ;
/* go to the first element of the sequence */
data + + ;
/* parse each byte till we reach end of sequence byte - 0x00 */
while ( 1 ) {
index = * data ;
mipi_elem_exec = exec_elem [ index ] ;
if ( ! mipi_elem_exec ) {
DRM_ERROR ( " Unsupported MIPI element, skipping sequence execution \n " ) ;
return ;
}
/* goto element payload */
data + + ;
/* execute the element specific rotines */
data = mipi_elem_exec ( intel_dsi , data ) ;
/*
* After processing the element , data should point to
* next element or end of sequence
* check if have we reached end of sequence
*/
if ( * data = = 0x00 )
break ;
}
}
2015-01-23 15:30:56 +02:00
static int vbt_panel_prepare ( struct drm_panel * panel )
{
struct vbt_panel * vbt_panel = to_vbt_panel ( panel ) ;
struct intel_dsi * intel_dsi = vbt_panel - > intel_dsi ;
struct drm_device * dev = intel_dsi - > base . base . dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
const u8 * sequence ;
sequence = dev_priv - > vbt . dsi . sequence [ MIPI_SEQ_ASSERT_RESET ] ;
generic_exec_sequence ( intel_dsi , sequence ) ;
sequence = dev_priv - > vbt . dsi . sequence [ MIPI_SEQ_INIT_OTP ] ;
generic_exec_sequence ( intel_dsi , sequence ) ;
return 0 ;
}
static int vbt_panel_unprepare ( struct drm_panel * panel )
{
struct vbt_panel * vbt_panel = to_vbt_panel ( panel ) ;
struct intel_dsi * intel_dsi = vbt_panel - > intel_dsi ;
struct drm_device * dev = intel_dsi - > base . base . dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
const u8 * sequence ;
sequence = dev_priv - > vbt . dsi . sequence [ MIPI_SEQ_DEASSERT_RESET ] ;
generic_exec_sequence ( intel_dsi , sequence ) ;
return 0 ;
}
static int vbt_panel_enable ( struct drm_panel * panel )
{
struct vbt_panel * vbt_panel = to_vbt_panel ( panel ) ;
struct intel_dsi * intel_dsi = vbt_panel - > intel_dsi ;
struct drm_device * dev = intel_dsi - > base . base . dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
const u8 * sequence ;
sequence = dev_priv - > vbt . dsi . sequence [ MIPI_SEQ_DISPLAY_ON ] ;
generic_exec_sequence ( intel_dsi , sequence ) ;
return 0 ;
}
static int vbt_panel_disable ( struct drm_panel * panel )
{
struct vbt_panel * vbt_panel = to_vbt_panel ( panel ) ;
struct intel_dsi * intel_dsi = vbt_panel - > intel_dsi ;
struct drm_device * dev = intel_dsi - > base . base . dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
const u8 * sequence ;
sequence = dev_priv - > vbt . dsi . sequence [ MIPI_SEQ_DISPLAY_OFF ] ;
generic_exec_sequence ( intel_dsi , sequence ) ;
return 0 ;
}
static int vbt_panel_get_modes ( struct drm_panel * panel )
{
struct vbt_panel * vbt_panel = to_vbt_panel ( panel ) ;
struct intel_dsi * intel_dsi = vbt_panel - > intel_dsi ;
struct drm_device * dev = intel_dsi - > base . base . dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct drm_display_mode * mode ;
if ( ! panel - > connector )
return 0 ;
mode = drm_mode_duplicate ( dev , dev_priv - > vbt . lfp_lvds_vbt_mode ) ;
if ( ! mode )
return 0 ;
mode - > type | = DRM_MODE_TYPE_PREFERRED ;
drm_mode_probed_add ( panel - > connector , mode ) ;
return 1 ;
}
static const struct drm_panel_funcs vbt_panel_funcs = {
. disable = vbt_panel_disable ,
. unprepare = vbt_panel_unprepare ,
. prepare = vbt_panel_prepare ,
. enable = vbt_panel_enable ,
. get_modes = vbt_panel_get_modes ,
} ;
struct drm_panel * vbt_panel_init ( struct intel_dsi * intel_dsi , u16 panel_id )
2014-05-23 21:35:27 +05:30
{
struct drm_device * dev = intel_dsi - > base . base . dev ;
struct drm_i915_private * dev_priv = dev - > dev_private ;
struct mipi_config * mipi_config = dev_priv - > vbt . dsi . config ;
struct mipi_pps_data * pps = dev_priv - > vbt . dsi . pps ;
struct drm_display_mode * mode = dev_priv - > vbt . lfp_lvds_vbt_mode ;
2015-01-23 15:30:56 +02:00
struct vbt_panel * vbt_panel ;
2014-05-23 21:35:27 +05:30
u32 bits_per_pixel = 24 ;
u32 tlpx_ns , extra_byte_count , bitrate , tlpx_ui ;
u32 ui_num , ui_den ;
u32 prepare_cnt , exit_zero_cnt , clk_zero_cnt , trail_cnt ;
u32 ths_prepare_ns , tclk_trail_ns ;
u32 tclk_prepare_clkzero , ths_prepare_hszero ;
u32 lp_to_hs_switch , hs_to_lp_switch ;
2014-07-30 20:34:57 +05:30
u32 pclk , computed_ddr ;
u16 burst_mode_ratio ;
2015-01-16 14:27:24 +02:00
enum port port ;
2014-05-23 21:35:27 +05:30
DRM_DEBUG_KMS ( " \n " ) ;
intel_dsi - > eotp_pkt = mipi_config - > eot_pkt_disabled ? 0 : 1 ;
intel_dsi - > clock_stop = mipi_config - > enable_clk_stop ? 1 : 0 ;
intel_dsi - > lane_count = mipi_config - > lane_cnt + 1 ;
intel_dsi - > pixel_format = mipi_config - > videomode_color_format < < 7 ;
2014-12-05 14:09:28 +05:30
intel_dsi - > dual_link = mipi_config - > dual_link ;
2014-12-05 14:13:41 +05:30
intel_dsi - > pixel_overlap = mipi_config - > pixel_overlap ;
2014-12-05 14:09:28 +05:30
2014-05-23 21:35:27 +05:30
if ( intel_dsi - > pixel_format = = VID_MODE_FORMAT_RGB666 )
bits_per_pixel = 18 ;
else if ( intel_dsi - > pixel_format = = VID_MODE_FORMAT_RGB565 )
bits_per_pixel = 16 ;
intel_dsi - > operation_mode = mipi_config - > is_cmd_mode ;
intel_dsi - > video_mode_format = mipi_config - > video_transfer_mode ;
intel_dsi - > escape_clk_div = mipi_config - > byte_clk_sel ;
intel_dsi - > lp_rx_timeout = mipi_config - > lp_rx_timeout ;
intel_dsi - > turn_arnd_val = mipi_config - > turn_around_timeout ;
intel_dsi - > rst_timer_val = mipi_config - > device_reset_timer ;
intel_dsi - > init_count = mipi_config - > master_init_timer ;
intel_dsi - > bw_timer = mipi_config - > dbi_bw_timer ;
2014-05-27 19:23:46 +05:30
intel_dsi - > video_frmt_cfg_bits =
mipi_config - > bta_enabled ? DISABLE_VIDEO_BTA : 0 ;
2014-05-23 21:35:27 +05:30
2014-07-30 20:34:57 +05:30
pclk = mode - > clock ;
2014-12-05 14:13:41 +05:30
/* In dual link mode each port needs half of pixel clock */
if ( intel_dsi - > dual_link ) {
pclk = pclk / 2 ;
/* we can enable pixel_overlap if needed by panel. In this
* case we need to increase the pixelclock for extra pixels
*/
if ( intel_dsi - > dual_link = = DSI_DUAL_LINK_FRONT_BACK ) {
pclk + = DIV_ROUND_UP ( mode - > vtotal *
intel_dsi - > pixel_overlap *
60 , 1000 ) ;
}
}
2014-07-30 20:34:57 +05:30
/* Burst Mode Ratio
* Target ddr frequency from VBT / non burst ddr freq
* multiply by 100 to preserve remainder
*/
if ( intel_dsi - > video_mode_format = = VIDEO_MODE_BURST ) {
if ( mipi_config - > target_burst_mode_freq ) {
computed_ddr =
( pclk * bits_per_pixel ) / intel_dsi - > lane_count ;
if ( mipi_config - > target_burst_mode_freq <
computed_ddr ) {
DRM_ERROR ( " Burst mode freq is less than computed \n " ) ;
2015-01-23 15:30:56 +02:00
return NULL ;
2014-07-30 20:34:57 +05:30
}
burst_mode_ratio = DIV_ROUND_UP (
mipi_config - > target_burst_mode_freq * 100 ,
computed_ddr ) ;
pclk = DIV_ROUND_UP ( pclk * burst_mode_ratio , 100 ) ;
} else {
DRM_ERROR ( " Burst mode target is not set \n " ) ;
2015-01-23 15:30:56 +02:00
return NULL ;
2014-07-30 20:34:57 +05:30
}
} else
burst_mode_ratio = 100 ;
intel_dsi - > burst_mode_ratio = burst_mode_ratio ;
intel_dsi - > pclk = pclk ;
bitrate = ( pclk * bits_per_pixel ) / intel_dsi - > lane_count ;
2014-05-23 21:35:27 +05:30
switch ( intel_dsi - > escape_clk_div ) {
case 0 :
tlpx_ns = 50 ;
break ;
case 1 :
tlpx_ns = 100 ;
break ;
case 2 :
tlpx_ns = 200 ;
break ;
default :
tlpx_ns = 50 ;
break ;
}
switch ( intel_dsi - > lane_count ) {
case 1 :
case 2 :
extra_byte_count = 2 ;
break ;
case 3 :
extra_byte_count = 4 ;
break ;
case 4 :
default :
extra_byte_count = 3 ;
break ;
}
/*
* ui ( s ) = 1 / f [ f in hz ]
* ui ( ns ) = 10 ^ 9 / ( f * 10 ^ 6 ) [ f in Mhz ] - > 10 ^ 3 / f ( Mhz )
*/
/* in Kbps */
ui_num = NS_KHZ_RATIO ;
ui_den = bitrate ;
tclk_prepare_clkzero = mipi_config - > tclk_prepare_clkzero ;
ths_prepare_hszero = mipi_config - > ths_prepare_hszero ;
/*
* B060
* LP byte clock = TLPX / ( 8U I )
*/
intel_dsi - > lp_byte_clk = DIV_ROUND_UP ( tlpx_ns * ui_den , 8 * ui_num ) ;
/* count values in UI = (ns value) * (bitrate / (2 * 10^6))
*
* Since txddrclkhs_i is 2 xUI , all the count values programmed in
* DPHY param register are divided by 2
*
* prepare count
*/
2014-05-27 19:23:46 +05:30
ths_prepare_ns = max ( mipi_config - > ths_prepare ,
mipi_config - > tclk_prepare ) ;
2014-05-23 21:35:27 +05:30
prepare_cnt = DIV_ROUND_UP ( ths_prepare_ns * ui_den , ui_num * 2 ) ;
/* exit zero count */
exit_zero_cnt = DIV_ROUND_UP (
( ths_prepare_hszero - ths_prepare_ns ) * ui_den ,
ui_num * 2
) ;
/*
* Exit zero is unified val ths_zero and ths_exit
* minimum value for ths_exit = 110 ns
* min ( exit_zero_cnt * 2 ) = 110 / UI
* exit_zero_cnt = 55 / UI
*/
if ( exit_zero_cnt < ( 55 * ui_den / ui_num ) )
if ( ( 55 * ui_den ) % ui_num )
exit_zero_cnt + = 1 ;
/* clk zero count */
clk_zero_cnt = DIV_ROUND_UP (
( tclk_prepare_clkzero - ths_prepare_ns )
* ui_den , 2 * ui_num ) ;
/* trail count */
tclk_trail_ns = max ( mipi_config - > tclk_trail , mipi_config - > ths_trail ) ;
trail_cnt = DIV_ROUND_UP ( tclk_trail_ns * ui_den , 2 * ui_num ) ;
if ( prepare_cnt > PREPARE_CNT_MAX | |
exit_zero_cnt > EXIT_ZERO_CNT_MAX | |
clk_zero_cnt > CLK_ZERO_CNT_MAX | |
trail_cnt > TRAIL_CNT_MAX )
DRM_DEBUG_DRIVER ( " Values crossing maximum limits, restricting to max values \n " ) ;
if ( prepare_cnt > PREPARE_CNT_MAX )
prepare_cnt = PREPARE_CNT_MAX ;
if ( exit_zero_cnt > EXIT_ZERO_CNT_MAX )
exit_zero_cnt = EXIT_ZERO_CNT_MAX ;
if ( clk_zero_cnt > CLK_ZERO_CNT_MAX )
clk_zero_cnt = CLK_ZERO_CNT_MAX ;
if ( trail_cnt > TRAIL_CNT_MAX )
trail_cnt = TRAIL_CNT_MAX ;
/* B080 */
intel_dsi - > dphy_reg = exit_zero_cnt < < 24 | trail_cnt < < 16 |
clk_zero_cnt < < 8 | prepare_cnt ;
/*
* LP to HS switch count = 4 TLPX + PREP_COUNT * 2 + EXIT_ZERO_COUNT * 2
* + 10U I + Extra Byte Count
*
* HS to LP switch count = THS - TRAIL + 2 TLPX + Extra Byte Count
* Extra Byte Count is calculated according to number of lanes .
* High Low Switch Count is the Max of LP to HS and
* HS to LP switch count
*
*/
tlpx_ui = DIV_ROUND_UP ( tlpx_ns * ui_den , ui_num ) ;
/* B044 */
/* FIXME:
* The comment above does not match with the code */
lp_to_hs_switch = DIV_ROUND_UP ( 4 * tlpx_ui + prepare_cnt * 2 +
exit_zero_cnt * 2 + 10 , 8 ) ;
hs_to_lp_switch = DIV_ROUND_UP ( mipi_config - > ths_trail + 2 * tlpx_ui , 8 ) ;
intel_dsi - > hs_to_lp_count = max ( lp_to_hs_switch , hs_to_lp_switch ) ;
intel_dsi - > hs_to_lp_count + = extra_byte_count ;
/* B088 */
/* LP -> HS for clock lanes
* LP clk sync + LP11 + LP01 + tclk_prepare + tclk_zero +
* extra byte count
* 2 TPLX + 1 TLPX + 1 TPLX ( in ns ) + prepare_cnt * 2 + clk_zero_cnt *
* 2 ( in UI ) + extra byte count
* In byteclks = ( 4 TLPX + prepare_cnt * 2 + clk_zero_cnt * 2 ( in UI ) ) /
* 8 + extra byte count
*/
intel_dsi - > clk_lp_to_hs_count =
DIV_ROUND_UP (
4 * tlpx_ui + prepare_cnt * 2 +
clk_zero_cnt * 2 ,
8 ) ;
intel_dsi - > clk_lp_to_hs_count + = extra_byte_count ;
/* HS->LP for Clock Lanes
* Low Power clock synchronisations + 1 Tx byteclk + tclk_trail +
* Extra byte count
* 2 TLPX + 8U I + ( trail_count * 2 ) ( in UI ) + Extra byte count
* In byteclks = ( 2 * TLpx ( in UI ) + trail_count * 2 + 8 ) ( in UI ) / 8 +
* Extra byte count
*/
intel_dsi - > clk_hs_to_lp_count =
DIV_ROUND_UP ( 2 * tlpx_ui + trail_cnt * 2 + 8 ,
8 ) ;
intel_dsi - > clk_hs_to_lp_count + = extra_byte_count ;
DRM_DEBUG_KMS ( " Eot %s \n " , intel_dsi - > eotp_pkt ? " enabled " : " disabled " ) ;
DRM_DEBUG_KMS ( " Clockstop %s \n " , intel_dsi - > clock_stop ?
" disabled " : " enabled " ) ;
DRM_DEBUG_KMS ( " Mode %s \n " , intel_dsi - > operation_mode ? " command " : " video " ) ;
2014-12-05 14:13:41 +05:30
if ( intel_dsi - > dual_link = = DSI_DUAL_LINK_FRONT_BACK )
DRM_DEBUG_KMS ( " Dual link: DSI_DUAL_LINK_FRONT_BACK \n " ) ;
else if ( intel_dsi - > dual_link = = DSI_DUAL_LINK_PIXEL_ALT )
DRM_DEBUG_KMS ( " Dual link: DSI_DUAL_LINK_PIXEL_ALT \n " ) ;
else
DRM_DEBUG_KMS ( " Dual link: NONE \n " ) ;
2014-05-23 21:35:27 +05:30
DRM_DEBUG_KMS ( " Pixel Format %d \n " , intel_dsi - > pixel_format ) ;
DRM_DEBUG_KMS ( " TLPX %d \n " , intel_dsi - > escape_clk_div ) ;
DRM_DEBUG_KMS ( " LP RX Timeout 0x%x \n " , intel_dsi - > lp_rx_timeout ) ;
DRM_DEBUG_KMS ( " Turnaround Timeout 0x%x \n " , intel_dsi - > turn_arnd_val ) ;
DRM_DEBUG_KMS ( " Init Count 0x%x \n " , intel_dsi - > init_count ) ;
DRM_DEBUG_KMS ( " HS to LP Count 0x%x \n " , intel_dsi - > hs_to_lp_count ) ;
DRM_DEBUG_KMS ( " LP Byte Clock %d \n " , intel_dsi - > lp_byte_clk ) ;
DRM_DEBUG_KMS ( " DBI BW Timer 0x%x \n " , intel_dsi - > bw_timer ) ;
DRM_DEBUG_KMS ( " LP to HS Clock Count 0x%x \n " , intel_dsi - > clk_lp_to_hs_count ) ;
DRM_DEBUG_KMS ( " HS to LP Clock Count 0x%x \n " , intel_dsi - > clk_hs_to_lp_count ) ;
DRM_DEBUG_KMS ( " BTA %s \n " ,
intel_dsi - > video_frmt_cfg_bits & DISABLE_VIDEO_BTA ?
" disabled " : " enabled " ) ;
/* delays in VBT are in unit of 100us, so need to convert
* here in ms
* Delay ( 100u s ) * 100 / 1000 = Delay / 10 ( ms ) */
intel_dsi - > backlight_off_delay = pps - > bl_disable_delay / 10 ;
intel_dsi - > backlight_on_delay = pps - > bl_enable_delay / 10 ;
intel_dsi - > panel_on_delay = pps - > panel_on_delay / 10 ;
intel_dsi - > panel_off_delay = pps - > panel_off_delay / 10 ;
intel_dsi - > panel_pwr_cycle_delay = pps - > panel_power_cycle_delay / 10 ;
2015-01-23 15:30:56 +02:00
/* This is cheating a bit with the cleanup. */
vbt_panel = devm_kzalloc ( dev - > dev , sizeof ( * vbt_panel ) , GFP_KERNEL ) ;
2014-05-23 21:35:27 +05:30
2015-01-23 15:30:56 +02:00
vbt_panel - > intel_dsi = intel_dsi ;
drm_panel_init ( & vbt_panel - > panel ) ;
vbt_panel - > panel . funcs = & vbt_panel_funcs ;
drm_panel_add ( & vbt_panel - > panel ) ;
2014-05-23 21:35:27 +05:30
2015-01-16 14:27:24 +02:00
/* a regular driver would get the device in probe */
for_each_dsi_port ( port , intel_dsi - > ports ) {
mipi_dsi_attach ( intel_dsi - > dsi_hosts [ port ] - > device ) ;
}
2015-01-23 15:30:56 +02:00
return & vbt_panel - > panel ;
2014-05-23 21:35:27 +05:30
}