2016-10-14 19:56:49 +05:30
/*
* Copyright © 2016 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 .
*
*
*/
2019-04-05 14:00:11 +03:00
2016-10-14 19:56:49 +05:30
# include <drm/drm_atomic_helper.h>
# include <drm/drm_dp_dual_mode_helper.h>
2019-04-05 14:00:11 +03:00
# include <drm/drm_edid.h>
2019-08-06 14:39:33 +03:00
# include "intel_display_types.h"
2019-04-05 14:00:17 +03:00
# include "intel_dp.h"
2019-04-05 14:00:11 +03:00
# include "intel_lspcon.h"
2016-10-14 19:56:49 +05:30
2018-10-12 11:53:10 +05:30
/* LSPCON OUI Vendor ID(signatures) */
# define LSPCON_VENDOR_PARADE_OUI 0x001CF8
# define LSPCON_VENDOR_MCA_OUI 0x0060AD
2018-10-12 11:53:12 +05:30
/* AUX addresses to write MCA AVI IF */
# define LSPCON_MCA_AVI_IF_WRITE_OFFSET 0x5C0
# define LSPCON_MCA_AVI_IF_CTRL 0x5DF
# define LSPCON_MCA_AVI_IF_KICKOFF (1 << 0)
# define LSPCON_MCA_AVI_IF_HANDLED (1 << 1)
2018-10-12 11:53:13 +05:30
/* AUX addresses to write Parade AVI IF */
# define LSPCON_PARADE_AVI_IF_WRITE_OFFSET 0x516
# define LSPCON_PARADE_AVI_IF_CTRL 0x51E
# define LSPCON_PARADE_AVI_IF_KICKOFF (1 << 7)
# define LSPCON_PARADE_AVI_IF_DATA_SIZE 32
2016-10-24 19:33:30 +03:00
static struct intel_dp * lspcon_to_intel_dp ( struct intel_lspcon * lspcon )
{
struct intel_digital_port * dig_port =
container_of ( lspcon , struct intel_digital_port , lspcon ) ;
return & dig_port - > dp ;
}
2016-11-21 21:15:06 +02:00
static const char * lspcon_mode_name ( enum drm_lspcon_mode mode )
{
switch ( mode ) {
case DRM_LSPCON_MODE_PCON :
return " PCON " ;
case DRM_LSPCON_MODE_LS :
return " LS " ;
case DRM_LSPCON_MODE_INVALID :
return " INVALID " ;
default :
MISSING_CASE ( mode ) ;
return " INVALID " ;
}
}
2018-10-12 11:53:10 +05:30
static bool lspcon_detect_vendor ( struct intel_lspcon * lspcon )
{
struct intel_dp * dp = lspcon_to_intel_dp ( lspcon ) ;
struct drm_dp_dpcd_ident * ident ;
u32 vendor_oui ;
if ( drm_dp_read_desc ( & dp - > aux , & dp - > desc , drm_dp_is_branch ( dp - > dpcd ) ) ) {
DRM_ERROR ( " Can't read description \n " ) ;
return false ;
}
ident = & dp - > desc . ident ;
vendor_oui = ( ident - > oui [ 0 ] < < 16 ) | ( ident - > oui [ 1 ] < < 8 ) |
ident - > oui [ 2 ] ;
switch ( vendor_oui ) {
case LSPCON_VENDOR_MCA_OUI :
lspcon - > vendor = LSPCON_VENDOR_MCA ;
DRM_DEBUG_KMS ( " Vendor: Mega Chips \n " ) ;
break ;
case LSPCON_VENDOR_PARADE_OUI :
lspcon - > vendor = LSPCON_VENDOR_PARADE ;
DRM_DEBUG_KMS ( " Vendor: Parade Tech \n " ) ;
break ;
default :
DRM_ERROR ( " Invalid/Unknown vendor OUI \n " ) ;
return false ;
}
return true ;
}
2016-10-18 14:21:51 +03:00
static enum drm_lspcon_mode lspcon_get_current_mode ( struct intel_lspcon * lspcon )
2016-10-14 19:56:49 +05:30
{
2016-11-21 21:15:06 +02:00
enum drm_lspcon_mode current_mode ;
2016-10-24 19:33:30 +03:00
struct i2c_adapter * adapter = & lspcon_to_intel_dp ( lspcon ) - > aux . ddc ;
2016-10-14 19:56:49 +05:30
2016-11-21 21:15:06 +02:00
if ( drm_lspcon_get_mode ( adapter , & current_mode ) ) {
2017-10-10 15:37:43 +05:30
DRM_DEBUG_KMS ( " Error reading LSPCON mode \n " ) ;
2016-11-21 21:15:06 +02:00
return DRM_LSPCON_MODE_INVALID ;
}
return current_mode ;
}
static enum drm_lspcon_mode lspcon_wait_mode ( struct intel_lspcon * lspcon ,
enum drm_lspcon_mode mode )
{
enum drm_lspcon_mode current_mode ;
current_mode = lspcon_get_current_mode ( lspcon ) ;
2017-10-10 15:37:43 +05:30
if ( current_mode = = mode )
2016-11-21 21:15:06 +02:00
goto out ;
DRM_DEBUG_KMS ( " Waiting for LSPCON mode %s to settle \n " ,
lspcon_mode_name ( mode ) ) ;
2018-08-17 22:07:28 +02:00
wait_for ( ( current_mode = lspcon_get_current_mode ( lspcon ) ) = = mode , 400 ) ;
2016-11-21 21:15:06 +02:00
if ( current_mode ! = mode )
2017-10-10 15:37:43 +05:30
DRM_ERROR ( " LSPCON mode hasn't settled \n " ) ;
2016-11-21 21:15:06 +02:00
out :
DRM_DEBUG_KMS ( " Current LSPCON mode %s \n " ,
lspcon_mode_name ( current_mode ) ) ;
2016-10-14 19:56:49 +05:30
return current_mode ;
}
static int lspcon_change_mode ( struct intel_lspcon * lspcon ,
2016-11-21 21:15:07 +02:00
enum drm_lspcon_mode mode )
2016-10-14 19:56:49 +05:30
{
int err ;
enum drm_lspcon_mode current_mode ;
2016-10-24 19:33:30 +03:00
struct i2c_adapter * adapter = & lspcon_to_intel_dp ( lspcon ) - > aux . ddc ;
2016-10-14 19:56:49 +05:30
err = drm_lspcon_get_mode ( adapter , & current_mode ) ;
if ( err ) {
DRM_ERROR ( " Error reading LSPCON mode \n " ) ;
return err ;
}
if ( current_mode = = mode ) {
DRM_DEBUG_KMS ( " Current mode = desired LSPCON mode \n " ) ;
return 0 ;
}
err = drm_lspcon_set_mode ( adapter , mode ) ;
if ( err < 0 ) {
DRM_ERROR ( " LSPCON mode change failed \n " ) ;
return err ;
}
lspcon - > mode = mode ;
DRM_DEBUG_KMS ( " LSPCON mode changed done \n " ) ;
return 0 ;
}
2016-11-21 21:15:04 +02:00
static bool lspcon_wake_native_aux_ch ( struct intel_lspcon * lspcon )
{
2018-06-12 12:19:35 +03:00
u8 rev ;
2016-11-21 21:15:04 +02:00
if ( drm_dp_dpcd_readb ( & lspcon_to_intel_dp ( lspcon ) - > aux , DP_DPCD_REV ,
& rev ) ! = 1 ) {
DRM_DEBUG_KMS ( " Native AUX CH down \n " ) ;
return false ;
}
DRM_DEBUG_KMS ( " Native AUX CH up, DPCD version: %d.%d \n " ,
rev > > 4 , rev & 0xf ) ;
return true ;
}
2018-10-12 11:53:14 +05:30
void lspcon_ycbcr420_config ( struct drm_connector * connector ,
struct intel_crtc_state * crtc_state )
{
const struct drm_display_info * info = & connector - > display_info ;
const struct drm_display_mode * adjusted_mode =
2019-10-31 12:26:02 +01:00
& crtc_state - > hw . adjusted_mode ;
2018-10-12 11:53:14 +05:30
if ( drm_mode_is_420_only ( info , adjusted_mode ) & &
connector - > ycbcr_420_allowed ) {
crtc_state - > port_clock / = 2 ;
crtc_state - > output_format = INTEL_OUTPUT_FORMAT_YCBCR444 ;
crtc_state - > lspcon_downsampling = true ;
}
}
2016-10-14 19:56:49 +05:30
static bool lspcon_probe ( struct intel_lspcon * lspcon )
{
2017-10-10 15:37:44 +05:30
int retry ;
2016-10-14 19:56:49 +05:30
enum drm_dp_dual_mode_type adaptor_type ;
2016-10-24 19:33:30 +03:00
struct i2c_adapter * adapter = & lspcon_to_intel_dp ( lspcon ) - > aux . ddc ;
2016-11-21 21:15:06 +02:00
enum drm_lspcon_mode expected_mode ;
2016-10-14 19:56:49 +05:30
2016-11-21 21:15:06 +02:00
expected_mode = lspcon_wake_native_aux_ch ( lspcon ) ?
DRM_LSPCON_MODE_PCON : DRM_LSPCON_MODE_LS ;
2016-11-21 21:15:04 +02:00
2016-10-14 19:56:49 +05:30
/* Lets probe the adaptor and check its type */
2017-10-10 15:37:44 +05:30
for ( retry = 0 ; retry < 6 ; retry + + ) {
if ( retry )
usleep_range ( 500 , 1000 ) ;
adaptor_type = drm_dp_dual_mode_detect ( adapter ) ;
if ( adaptor_type = = DRM_DP_DUAL_MODE_LSPCON )
break ;
}
2016-10-14 19:56:49 +05:30
if ( adaptor_type ! = DRM_DP_DUAL_MODE_LSPCON ) {
DRM_DEBUG_KMS ( " No LSPCON detected, found %s \n " ,
2017-10-10 15:37:44 +05:30
drm_dp_get_dual_mode_type_name ( adaptor_type ) ) ;
2016-10-14 19:56:49 +05:30
return false ;
}
/* Yay ... got a LSPCON device */
DRM_DEBUG_KMS ( " LSPCON detected \n " ) ;
2016-11-21 21:15:06 +02:00
lspcon - > mode = lspcon_wait_mode ( lspcon , expected_mode ) ;
2018-10-12 11:53:10 +05:30
/*
* In the SW state machine , lets Put LSPCON in PCON mode only .
* In this way , it will work with both HDMI 1.4 sinks as well as HDMI
* 2.0 sinks .
*/
2018-11-07 19:18:21 +02:00
if ( lspcon - > mode ! = DRM_LSPCON_MODE_PCON ) {
2018-10-12 11:53:10 +05:30
if ( lspcon_change_mode ( lspcon , DRM_LSPCON_MODE_PCON ) < 0 ) {
DRM_ERROR ( " LSPCON mode change to PCON failed \n " ) ;
return false ;
}
}
2016-10-14 19:56:49 +05:30
return true ;
}
2016-10-24 19:33:31 +03:00
static void lspcon_resume_in_pcon_wa ( struct intel_lspcon * lspcon )
{
struct intel_dp * intel_dp = lspcon_to_intel_dp ( lspcon ) ;
2017-01-27 11:39:19 +02:00
struct intel_digital_port * dig_port = dp_to_dig_port ( intel_dp ) ;
2016-10-24 19:33:31 +03:00
unsigned long start = jiffies ;
while ( 1 ) {
2018-01-29 15:22:20 -08:00
if ( intel_digital_port_connected ( & dig_port - > base ) ) {
2016-10-24 19:33:31 +03:00
DRM_DEBUG_KMS ( " LSPCON recovering in PCON mode after %u ms \n " ,
jiffies_to_msecs ( jiffies - start ) ) ;
return ;
}
if ( time_after ( jiffies , start + msecs_to_jiffies ( 1000 ) ) )
break ;
usleep_range ( 10000 , 15000 ) ;
}
DRM_DEBUG_KMS ( " LSPCON DP descriptor mismatch after resume \n " ) ;
}
2018-10-12 11:53:13 +05:30
static bool lspcon_parade_fw_ready ( struct drm_dp_aux * aux )
{
u8 avi_if_ctrl ;
u8 retry ;
ssize_t ret ;
/* Check if LSPCON FW is ready for data */
for ( retry = 0 ; retry < 5 ; retry + + ) {
if ( retry )
usleep_range ( 200 , 300 ) ;
ret = drm_dp_dpcd_read ( aux , LSPCON_PARADE_AVI_IF_CTRL ,
& avi_if_ctrl , 1 ) ;
if ( ret < 0 ) {
DRM_ERROR ( " Failed to read AVI IF control \n " ) ;
return false ;
}
if ( ( avi_if_ctrl & LSPCON_PARADE_AVI_IF_KICKOFF ) = = 0 )
return true ;
}
DRM_ERROR ( " Parade FW not ready to accept AVI IF \n " ) ;
return false ;
}
static bool _lspcon_parade_write_infoframe_blocks ( struct drm_dp_aux * aux ,
2019-01-16 11:15:22 +02:00
u8 * avi_buf )
2018-10-12 11:53:13 +05:30
{
u8 avi_if_ctrl ;
u8 block_count = 0 ;
u8 * data ;
2019-01-16 11:15:22 +02:00
u16 reg ;
2018-10-12 11:53:13 +05:30
ssize_t ret ;
while ( block_count < 4 ) {
if ( ! lspcon_parade_fw_ready ( aux ) ) {
DRM_DEBUG_KMS ( " LSPCON FW not ready, block %d \n " ,
block_count ) ;
return false ;
}
reg = LSPCON_PARADE_AVI_IF_WRITE_OFFSET ;
data = avi_buf + block_count * 8 ;
ret = drm_dp_dpcd_write ( aux , reg , data , 8 ) ;
if ( ret < 0 ) {
DRM_ERROR ( " Failed to write AVI IF block %d \n " ,
block_count ) ;
return false ;
}
/*
* Once a block of data is written , we have to inform the FW
* about this by writing into avi infoframe control register :
* - set the kickoff bit [ 7 ] to 1
* - write the block no . to bits [ 1 : 0 ]
*/
reg = LSPCON_PARADE_AVI_IF_CTRL ;
avi_if_ctrl = LSPCON_PARADE_AVI_IF_KICKOFF | block_count ;
ret = drm_dp_dpcd_write ( aux , reg , & avi_if_ctrl , 1 ) ;
if ( ret < 0 ) {
DRM_ERROR ( " Failed to update (0x%x), block %d \n " ,
reg , block_count ) ;
return false ;
}
block_count + + ;
}
DRM_DEBUG_KMS ( " Wrote AVI IF blocks successfully \n " ) ;
return true ;
}
static bool _lspcon_write_avi_infoframe_parade ( struct drm_dp_aux * aux ,
2019-01-16 11:15:22 +02:00
const u8 * frame ,
2018-10-12 11:53:13 +05:30
ssize_t len )
{
2019-01-16 11:15:22 +02:00
u8 avi_if [ LSPCON_PARADE_AVI_IF_DATA_SIZE ] = { 1 , } ;
2018-10-12 11:53:13 +05:30
/*
* Parade ' s frames contains 32 bytes of data , divided
* into 4 frames :
* Token byte ( first byte of first frame , must be non - zero )
* HB0 to HB2 from AVI IF ( 3 bytes header )
* PB0 to PB27 from AVI IF ( 28 bytes data )
* So it should look like this
* first block : | < token > < HB0 - HB2 > < DB0 - DB3 > |
* next 3 blocks : | < DB4 - DB11 > | < DB12 - DB19 > | < DB20 - DB28 > |
*/
if ( len > LSPCON_PARADE_AVI_IF_DATA_SIZE - 1 ) {
DRM_ERROR ( " Invalid length of infoframes \n " ) ;
return false ;
}
memcpy ( & avi_if [ 1 ] , frame , len ) ;
if ( ! _lspcon_parade_write_infoframe_blocks ( aux , avi_if ) ) {
DRM_DEBUG_KMS ( " Failed to write infoframe blocks \n " ) ;
return false ;
}
return true ;
}
2018-10-12 11:53:12 +05:30
static bool _lspcon_write_avi_infoframe_mca ( struct drm_dp_aux * aux ,
2019-01-16 11:15:22 +02:00
const u8 * buffer , ssize_t len )
2018-10-12 11:53:12 +05:30
{
int ret ;
2019-01-16 11:15:22 +02:00
u32 val = 0 ;
u32 retry ;
u16 reg ;
const u8 * data = buffer ;
2018-10-12 11:53:12 +05:30
reg = LSPCON_MCA_AVI_IF_WRITE_OFFSET ;
while ( val < len ) {
/* DPCD write for AVI IF can fail on a slow FW day, so retry */
for ( retry = 0 ; retry < 5 ; retry + + ) {
ret = drm_dp_dpcd_write ( aux , reg , ( void * ) data , 1 ) ;
if ( ret = = 1 ) {
break ;
} else if ( retry < 4 ) {
mdelay ( 50 ) ;
continue ;
} else {
DRM_ERROR ( " DPCD write failed at:0x%x \n " , reg ) ;
return false ;
}
}
val + + ; reg + + ; data + + ;
}
val = 0 ;
reg = LSPCON_MCA_AVI_IF_CTRL ;
ret = drm_dp_dpcd_read ( aux , reg , & val , 1 ) ;
if ( ret < 0 ) {
DRM_ERROR ( " DPCD read failed, address 0x%x \n " , reg ) ;
return false ;
}
/* Indicate LSPCON chip about infoframe, clear bit 1 and set bit 0 */
val & = ~ LSPCON_MCA_AVI_IF_HANDLED ;
val | = LSPCON_MCA_AVI_IF_KICKOFF ;
ret = drm_dp_dpcd_write ( aux , reg , & val , 1 ) ;
if ( ret < 0 ) {
DRM_ERROR ( " DPCD read failed, address 0x%x \n " , reg ) ;
return false ;
}
val = 0 ;
ret = drm_dp_dpcd_read ( aux , reg , & val , 1 ) ;
if ( ret < 0 ) {
DRM_ERROR ( " DPCD read failed, address 0x%x \n " , reg ) ;
return false ;
}
if ( val = = LSPCON_MCA_AVI_IF_HANDLED )
DRM_DEBUG_KMS ( " AVI IF handled by FW \n " ) ;
return true ;
}
void lspcon_write_infoframe ( struct intel_encoder * encoder ,
const struct intel_crtc_state * crtc_state ,
unsigned int type ,
const void * frame , ssize_t len )
{
2018-10-12 11:53:13 +05:30
bool ret ;
2019-12-04 20:05:43 +02:00
struct intel_dp * intel_dp = enc_to_intel_dp ( encoder ) ;
struct intel_lspcon * lspcon = enc_to_intel_lspcon ( encoder ) ;
2018-10-12 11:53:12 +05:30
/* LSPCON only needs AVI IF */
if ( type ! = HDMI_INFOFRAME_TYPE_AVI )
return ;
if ( lspcon - > vendor = = LSPCON_VENDOR_MCA )
ret = _lspcon_write_avi_infoframe_mca ( & intel_dp - > aux ,
frame , len ) ;
2018-10-12 11:53:13 +05:30
else
ret = _lspcon_write_avi_infoframe_parade ( & intel_dp - > aux ,
frame , len ) ;
2018-10-12 11:53:12 +05:30
if ( ! ret ) {
DRM_ERROR ( " Failed to write AVI infoframes \n " ) ;
return ;
}
DRM_DEBUG_DRIVER ( " AVI infoframes updated successfully \n " ) ;
}
2019-02-25 19:41:02 +02:00
void lspcon_read_infoframe ( struct intel_encoder * encoder ,
const struct intel_crtc_state * crtc_state ,
unsigned int type ,
void * frame , ssize_t len )
{
/* FIXME implement this */
}
2018-10-12 11:53:11 +05:30
void lspcon_set_infoframes ( struct intel_encoder * encoder ,
bool enable ,
const struct intel_crtc_state * crtc_state ,
const struct drm_connector_state * conn_state )
{
ssize_t ret ;
union hdmi_infoframe frame ;
2019-01-16 11:15:22 +02:00
u8 buf [ VIDEO_DIP_DATA_SIZE ] ;
2019-12-04 20:05:43 +02:00
struct intel_digital_port * dig_port = enc_to_dig_port ( encoder ) ;
2018-10-12 11:53:11 +05:30
struct intel_lspcon * lspcon = & dig_port - > lspcon ;
2019-01-08 19:28:25 +02:00
const struct drm_display_mode * adjusted_mode =
2019-10-31 12:26:02 +01:00
& crtc_state - > hw . adjusted_mode ;
2018-10-12 11:53:11 +05:30
if ( ! lspcon - > active ) {
DRM_ERROR ( " Writing infoframes while LSPCON disabled ? \n " ) ;
return ;
}
2019-02-25 19:41:01 +02:00
/* FIXME precompute infoframes */
2018-10-12 11:53:11 +05:30
ret = drm_hdmi_avi_infoframe_from_display_mode ( & frame . avi ,
2019-01-08 19:28:25 +02:00
conn_state - > connector ,
adjusted_mode ) ;
2018-10-12 11:53:11 +05:30
if ( ret < 0 ) {
DRM_ERROR ( " couldn't fill AVI infoframe \n " ) ;
return ;
}
2018-10-12 11:53:14 +05:30
if ( crtc_state - > output_format = = INTEL_OUTPUT_FORMAT_YCBCR444 ) {
if ( crtc_state - > lspcon_downsampling )
frame . avi . colorspace = HDMI_COLORSPACE_YUV420 ;
else
frame . avi . colorspace = HDMI_COLORSPACE_YUV444 ;
} else {
frame . avi . colorspace = HDMI_COLORSPACE_RGB ;
}
2019-01-08 19:28:25 +02:00
drm_hdmi_avi_infoframe_quant_range ( & frame . avi ,
conn_state - > connector ,
adjusted_mode ,
2018-10-12 11:53:11 +05:30
crtc_state - > limited_color_range ?
HDMI_QUANTIZATION_RANGE_LIMITED :
2019-01-08 19:28:28 +02:00
HDMI_QUANTIZATION_RANGE_FULL ) ;
2018-10-12 11:53:11 +05:30
ret = hdmi_infoframe_pack ( & frame , buf , sizeof ( buf ) ) ;
if ( ret < 0 ) {
DRM_ERROR ( " Failed to pack AVI IF \n " ) ;
return ;
}
dig_port - > write_infoframe ( encoder , crtc_state , HDMI_INFOFRAME_TYPE_AVI ,
buf , ret ) ;
}
2019-02-25 19:40:59 +02:00
u32 lspcon_infoframes_enabled ( struct intel_encoder * encoder ,
2018-10-12 11:53:11 +05:30
const struct intel_crtc_state * pipe_config )
{
2019-02-25 19:40:59 +02:00
/* FIXME actually read this from the hw */
2020-05-14 09:07:28 +03:00
return 0 ;
2018-10-12 11:53:11 +05:30
}
2016-10-14 19:56:52 +05:30
void lspcon_resume ( struct intel_lspcon * lspcon )
{
2016-11-21 21:15:06 +02:00
enum drm_lspcon_mode expected_mode ;
if ( lspcon_wake_native_aux_ch ( lspcon ) ) {
expected_mode = DRM_LSPCON_MODE_PCON ;
2016-11-21 21:15:04 +02:00
lspcon_resume_in_pcon_wa ( lspcon ) ;
2016-11-21 21:15:06 +02:00
} else {
expected_mode = DRM_LSPCON_MODE_LS ;
}
if ( lspcon_wait_mode ( lspcon , expected_mode ) = = DRM_LSPCON_MODE_PCON )
return ;
2016-10-24 19:33:31 +03:00
2016-11-21 21:15:07 +02:00
if ( lspcon_change_mode ( lspcon , DRM_LSPCON_MODE_PCON ) )
2016-10-14 19:56:52 +05:30
DRM_ERROR ( " LSPCON resume failed \n " ) ;
else
DRM_DEBUG_KMS ( " LSPCON resume success \n " ) ;
}
2016-11-21 21:15:06 +02:00
void lspcon_wait_pcon_mode ( struct intel_lspcon * lspcon )
{
lspcon_wait_mode ( lspcon , DRM_LSPCON_MODE_PCON ) ;
}
2020-06-30 21:50:54 -07:00
bool lspcon_init ( struct intel_digital_port * dig_port )
2016-10-14 19:56:49 +05:30
{
2020-06-30 21:50:54 -07:00
struct intel_dp * dp = & dig_port - > dp ;
struct intel_lspcon * lspcon = & dig_port - > lspcon ;
struct drm_device * dev = dig_port - > base . base . dev ;
2016-10-14 19:56:49 +05:30
struct drm_i915_private * dev_priv = to_i915 ( dev ) ;
2018-10-12 11:53:14 +05:30
struct drm_connector * connector = & dp - > attached_connector - > base ;
2016-10-14 19:56:49 +05:30
2017-08-15 20:04:03 -07:00
if ( ! HAS_LSPCON ( dev_priv ) ) {
DRM_ERROR ( " LSPCON is not supported on this platform \n " ) ;
2016-10-14 19:56:49 +05:30
return false ;
}
lspcon - > active = false ;
lspcon - > mode = DRM_LSPCON_MODE_INVALID ;
if ( ! lspcon_probe ( lspcon ) ) {
DRM_ERROR ( " Failed to probe lspcon \n " ) ;
return false ;
}
2020-08-26 14:24:55 -04:00
if ( drm_dp_read_dpcd_caps ( & dp - > aux , dp - > dpcd ) ! = 0 ) {
2016-10-24 19:33:28 +03:00
DRM_ERROR ( " LSPCON DPCD read failed \n " ) ;
return false ;
}
2018-10-12 11:53:10 +05:30
if ( ! lspcon_detect_vendor ( lspcon ) ) {
DRM_ERROR ( " LSPCON vendor detection failed \n " ) ;
return false ;
}
2016-10-24 19:33:29 +03:00
2018-10-12 11:53:14 +05:30
connector - > ycbcr_420_allowed = true ;
2018-10-12 11:53:10 +05:30
lspcon - > active = true ;
2016-10-14 19:56:49 +05:30
DRM_DEBUG_KMS ( " Success: LSPCON init \n " ) ;
return true ;
}