2016-05-02 09:54:26 +02:00
/*
* Copyright ( c ) 2016 , Analogix Semiconductor .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 and
* only 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 .
*
* Based on anx7808 driver obtained from chromeos with copyright :
* Copyright ( c ) 2013 , Google Inc .
*
*/
# include <linux/delay.h>
# include <linux/err.h>
# include <linux/interrupt.h>
# include <linux/i2c.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of_gpio.h>
# include <linux/of_irq.h>
# include <linux/of_platform.h>
# include <linux/regmap.h>
# include <linux/types.h>
# include <linux/gpio/consumer.h>
# include <linux/regulator/consumer.h>
# include <drm/drmP.h>
# include <drm/drm_atomic_helper.h>
# include <drm/drm_crtc.h>
# include <drm/drm_crtc_helper.h>
# include <drm/drm_dp_helper.h>
# include <drm/drm_edid.h>
# include "analogix-anx78xx.h"
# define I2C_NUM_ADDRESSES 5
# define I2C_IDX_TX_P0 0
# define I2C_IDX_TX_P1 1
# define I2C_IDX_TX_P2 2
# define I2C_IDX_RX_P0 3
# define I2C_IDX_RX_P1 4
# define XTAL_CLK 270 /* 27M */
# define AUX_CH_BUFFER_SIZE 16
# define AUX_WAIT_TIMEOUT_MS 15
static const u8 anx78xx_i2c_addresses [ ] = {
[ I2C_IDX_TX_P0 ] = TX_P0 ,
[ I2C_IDX_TX_P1 ] = TX_P1 ,
[ I2C_IDX_TX_P2 ] = TX_P2 ,
[ I2C_IDX_RX_P0 ] = RX_P0 ,
[ I2C_IDX_RX_P1 ] = RX_P1 ,
} ;
struct anx78xx_platform_data {
struct regulator * dvdd10 ;
struct gpio_desc * gpiod_hpd ;
struct gpio_desc * gpiod_pd ;
struct gpio_desc * gpiod_reset ;
int hpd_irq ;
int intp_irq ;
} ;
struct anx78xx {
struct drm_dp_aux aux ;
struct drm_bridge bridge ;
struct i2c_client * client ;
struct edid * edid ;
struct drm_connector connector ;
struct drm_dp_link link ;
struct anx78xx_platform_data pdata ;
struct mutex lock ;
/*
* I2C Slave addresses of ANX7814 are mapped as TX_P0 , TX_P1 , TX_P2 ,
* RX_P0 and RX_P1 .
*/
struct i2c_client * i2c_dummy [ I2C_NUM_ADDRESSES ] ;
struct regmap * map [ I2C_NUM_ADDRESSES ] ;
u16 chipid ;
u8 dpcd [ DP_RECEIVER_CAP_SIZE ] ;
bool powered ;
} ;
static inline struct anx78xx * connector_to_anx78xx ( struct drm_connector * c )
{
return container_of ( c , struct anx78xx , connector ) ;
}
static inline struct anx78xx * bridge_to_anx78xx ( struct drm_bridge * bridge )
{
return container_of ( bridge , struct anx78xx , bridge ) ;
}
static int anx78xx_set_bits ( struct regmap * map , u8 reg , u8 mask )
{
return regmap_update_bits ( map , reg , mask , mask ) ;
}
static int anx78xx_clear_bits ( struct regmap * map , u8 reg , u8 mask )
{
return regmap_update_bits ( map , reg , mask , 0 ) ;
}
static bool anx78xx_aux_op_finished ( struct anx78xx * anx78xx )
{
unsigned int value ;
int err ;
err = regmap_read ( anx78xx - > map [ I2C_IDX_TX_P0 ] , SP_DP_AUX_CH_CTRL2_REG ,
& value ) ;
if ( err < 0 )
return false ;
return ( value & SP_AUX_EN ) = = 0 ;
}
static int anx78xx_aux_wait ( struct anx78xx * anx78xx )
{
unsigned long timeout ;
unsigned int status ;
int err ;
timeout = jiffies + msecs_to_jiffies ( AUX_WAIT_TIMEOUT_MS ) + 1 ;
while ( ! anx78xx_aux_op_finished ( anx78xx ) ) {
if ( time_after ( jiffies , timeout ) ) {
if ( ! anx78xx_aux_op_finished ( anx78xx ) ) {
DRM_ERROR ( " Timed out waiting AUX to finish \n " ) ;
return - ETIMEDOUT ;
}
break ;
}
usleep_range ( 1000 , 2000 ) ;
}
/* Read the AUX channel access status */
err = regmap_read ( anx78xx - > map [ I2C_IDX_TX_P0 ] , SP_AUX_CH_STATUS_REG ,
& status ) ;
if ( err < 0 ) {
DRM_ERROR ( " Failed to read from AUX channel: %d \n " , err ) ;
return err ;
}
if ( status & SP_AUX_STATUS ) {
DRM_ERROR ( " Failed to wait for AUX channel (status: %02x) \n " ,
status ) ;
return - ETIMEDOUT ;
}
return 0 ;
}
static int anx78xx_aux_address ( struct anx78xx * anx78xx , unsigned int addr )
{
int err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] , SP_AUX_ADDR_7_0_REG ,
addr & 0xff ) ;
if ( err )
return err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] , SP_AUX_ADDR_15_8_REG ,
( addr & 0xff00 ) > > 8 ) ;
if ( err )
return err ;
/*
* DP AUX CH Address Register # 2 , only update bits [ 3 : 0 ]
* [ 7 : 4 ] RESERVED
* [ 3 : 0 ] AUX_ADDR [ 19 : 16 ] , Register control AUX CH address .
*/
err = regmap_update_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_AUX_ADDR_19_16_REG ,
SP_AUX_ADDR_19_16_MASK ,
( addr & 0xf0000 ) > > 16 ) ;
if ( err )
return err ;
return 0 ;
}
static ssize_t anx78xx_aux_transfer ( struct drm_dp_aux * aux ,
struct drm_dp_aux_msg * msg )
{
struct anx78xx * anx78xx = container_of ( aux , struct anx78xx , aux ) ;
u8 ctrl1 = msg - > request ;
u8 ctrl2 = SP_AUX_EN ;
u8 * buffer = msg - > buffer ;
int err ;
/* The DP AUX transmit and receive buffer has 16 bytes. */
if ( WARN_ON ( msg - > size > AUX_CH_BUFFER_SIZE ) )
return - E2BIG ;
/* Zero-sized messages specify address-only transactions. */
if ( msg - > size < 1 )
ctrl2 | = SP_ADDR_ONLY ;
else /* For non-zero-sized set the length field. */
ctrl1 | = ( msg - > size - 1 ) < < SP_AUX_LENGTH_SHIFT ;
if ( ( msg - > request & DP_AUX_I2C_READ ) = = 0 ) {
/* When WRITE | MOT write values to data buffer */
err = regmap_bulk_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_BUF_DATA0_REG , buffer ,
msg - > size ) ;
if ( err )
return err ;
}
/* Write address and request */
err = anx78xx_aux_address ( anx78xx , msg - > address ) ;
if ( err )
return err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] , SP_DP_AUX_CH_CTRL1_REG ,
ctrl1 ) ;
if ( err )
return err ;
/* Start transaction */
err = regmap_update_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_AUX_CH_CTRL2_REG , SP_ADDR_ONLY |
SP_AUX_EN , ctrl2 ) ;
if ( err )
return err ;
err = anx78xx_aux_wait ( anx78xx ) ;
if ( err )
return err ;
msg - > reply = DP_AUX_I2C_REPLY_ACK ;
if ( ( msg - > size > 0 ) & & ( msg - > request & DP_AUX_I2C_READ ) ) {
/* Read values from data buffer */
err = regmap_bulk_read ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_BUF_DATA0_REG , buffer ,
msg - > size ) ;
if ( err )
return err ;
}
err = anx78xx_clear_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_AUX_CH_CTRL2_REG , SP_ADDR_ONLY ) ;
if ( err )
return err ;
return msg - > size ;
}
static int anx78xx_set_hpd ( struct anx78xx * anx78xx )
{
int err ;
err = anx78xx_clear_bits ( anx78xx - > map [ I2C_IDX_RX_P0 ] ,
SP_TMDS_CTRL_BASE + 7 , SP_PD_RT ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_VID_CTRL3_REG ,
SP_HPD_OUT ) ;
if ( err )
return err ;
return 0 ;
}
static int anx78xx_clear_hpd ( struct anx78xx * anx78xx )
{
int err ;
err = anx78xx_clear_bits ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_VID_CTRL3_REG ,
SP_HPD_OUT ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_RX_P0 ] ,
SP_TMDS_CTRL_BASE + 7 , SP_PD_RT ) ;
if ( err )
return err ;
return 0 ;
}
static const struct reg_sequence tmds_phy_initialization [ ] = {
{ SP_TMDS_CTRL_BASE + 1 , 0x90 } ,
{ SP_TMDS_CTRL_BASE + 2 , 0xa9 } ,
{ SP_TMDS_CTRL_BASE + 6 , 0x92 } ,
{ SP_TMDS_CTRL_BASE + 7 , 0x80 } ,
{ SP_TMDS_CTRL_BASE + 20 , 0xf2 } ,
{ SP_TMDS_CTRL_BASE + 22 , 0xc4 } ,
{ SP_TMDS_CTRL_BASE + 23 , 0x18 } ,
} ;
static int anx78xx_rx_initialization ( struct anx78xx * anx78xx )
{
int err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_RX_P0 ] , SP_HDMI_MUTE_CTRL_REG ,
SP_AUD_MUTE | SP_VID_MUTE ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_RX_P0 ] , SP_CHIP_CTRL_REG ,
SP_MAN_HDMI5V_DET | SP_PLLLOCK_CKDT_EN |
SP_DIGITAL_CKDT_EN ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_RX_P0 ] ,
SP_SOFTWARE_RESET1_REG , SP_HDCP_MAN_RST |
SP_SW_MAN_RST | SP_TMDS_RST | SP_VIDEO_RST ) ;
if ( err )
return err ;
err = anx78xx_clear_bits ( anx78xx - > map [ I2C_IDX_RX_P0 ] ,
SP_SOFTWARE_RESET1_REG , SP_HDCP_MAN_RST |
SP_SW_MAN_RST | SP_TMDS_RST | SP_VIDEO_RST ) ;
if ( err )
return err ;
/* Sync detect change, GP set mute */
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_RX_P0 ] ,
SP_AUD_EXCEPTION_ENABLE_BASE + 1 , BIT ( 5 ) |
BIT ( 6 ) ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_RX_P0 ] ,
SP_AUD_EXCEPTION_ENABLE_BASE + 3 ,
SP_AEC_EN21 ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_RX_P0 ] , SP_AUDVID_CTRL_REG ,
SP_AVC_EN | SP_AAC_OE | SP_AAC_EN ) ;
if ( err )
return err ;
err = anx78xx_clear_bits ( anx78xx - > map [ I2C_IDX_RX_P0 ] ,
SP_SYSTEM_POWER_DOWN1_REG , SP_PWDN_CTRL ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_RX_P0 ] ,
SP_VID_DATA_RANGE_CTRL_REG , SP_R2Y_INPUT_LIMIT ) ;
if ( err )
return err ;
/* Enable DDC stretch */
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_EXTRA_I2C_DEV_ADDR_REG , SP_I2C_EXTRA_ADDR ) ;
if ( err )
return err ;
/* TMDS phy initialization */
err = regmap_multi_reg_write ( anx78xx - > map [ I2C_IDX_RX_P0 ] ,
tmds_phy_initialization ,
ARRAY_SIZE ( tmds_phy_initialization ) ) ;
if ( err )
return err ;
err = anx78xx_clear_hpd ( anx78xx ) ;
if ( err )
return err ;
return 0 ;
}
static const u8 dp_tx_output_precise_tune_bits [ 20 ] = {
0x01 , 0x03 , 0x07 , 0x7f , 0x71 , 0x6b , 0x7f ,
0x73 , 0x7f , 0x7f , 0x00 , 0x00 , 0x00 , 0x00 ,
0x0c , 0x42 , 0x1e , 0x3e , 0x72 , 0x7e ,
} ;
static int anx78xx_link_phy_initialization ( struct anx78xx * anx78xx )
{
int err ;
/*
* REVISIT : It is writing to a RESERVED bits in Analog Control 0
* register .
*/
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_ANALOG_CTRL0_REG ,
0x02 ) ;
if ( err )
return err ;
/*
* Write DP TX output emphasis precise tune bits .
*/
err = regmap_bulk_write ( anx78xx - > map [ I2C_IDX_TX_P1 ] ,
SP_DP_TX_LT_CTRL0_REG ,
dp_tx_output_precise_tune_bits ,
ARRAY_SIZE ( dp_tx_output_precise_tune_bits ) ) ;
if ( err )
return err ;
return 0 ;
}
static int anx78xx_xtal_clk_sel ( struct anx78xx * anx78xx )
{
unsigned int value ;
int err ;
err = regmap_update_bits ( anx78xx - > map [ I2C_IDX_TX_P2 ] ,
SP_ANALOG_DEBUG2_REG ,
SP_XTAL_FRQ | SP_FORCE_SW_OFF_BYPASS ,
SP_XTAL_FRQ_27M ) ;
if ( err )
return err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] , SP_DP_AUX_CH_CTRL3_REG ,
XTAL_CLK & SP_WAIT_COUNTER_7_0_MASK ) ;
if ( err )
return err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] , SP_DP_AUX_CH_CTRL4_REG ,
( ( XTAL_CLK & 0xff00 ) > > 2 ) | ( XTAL_CLK / 10 ) ) ;
if ( err )
return err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_I2C_GEN_10US_TIMER0_REG , XTAL_CLK & 0xff ) ;
if ( err )
return err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_I2C_GEN_10US_TIMER1_REG ,
( XTAL_CLK & 0xff00 ) > > 8 ) ;
if ( err )
return err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] , SP_AUX_MISC_CTRL_REG ,
XTAL_CLK / 10 - 1 ) ;
if ( err )
return err ;
err = regmap_read ( anx78xx - > map [ I2C_IDX_RX_P0 ] ,
SP_HDMI_US_TIMER_CTRL_REG ,
& value ) ;
if ( err )
return err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_RX_P0 ] ,
SP_HDMI_US_TIMER_CTRL_REG ,
( value & SP_MS_TIMER_MARGIN_10_8_MASK ) |
( ( ( ( XTAL_CLK / 10 ) > > 1 ) - 2 ) < < 3 ) ) ;
if ( err )
return err ;
return 0 ;
}
static const struct reg_sequence otp_key_protect [ ] = {
{ SP_OTP_KEY_PROTECT1_REG , SP_OTP_PSW1 } ,
{ SP_OTP_KEY_PROTECT2_REG , SP_OTP_PSW2 } ,
{ SP_OTP_KEY_PROTECT3_REG , SP_OTP_PSW3 } ,
} ;
static int anx78xx_tx_initialization ( struct anx78xx * anx78xx )
{
int err ;
/* Set terminal resistor to 50 ohm */
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] , SP_DP_AUX_CH_CTRL2_REG ,
0x30 ) ;
if ( err )
return err ;
/* Enable aux double diff output */
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_AUX_CH_CTRL2_REG , 0x08 ) ;
if ( err )
return err ;
err = anx78xx_clear_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_HDCP_CTRL_REG , SP_AUTO_EN |
SP_AUTO_START ) ;
if ( err )
return err ;
err = regmap_multi_reg_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
otp_key_protect ,
ARRAY_SIZE ( otp_key_protect ) ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_HDCP_KEY_COMMAND_REG , SP_DISABLE_SYNC_HDCP ) ;
if ( err )
return err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_VID_CTRL8_REG ,
SP_VID_VRES_TH ) ;
if ( err )
return err ;
/*
* DP HDCP auto authentication wait timer ( when downstream starts to
* auth , DP side will wait for this period then do auth automatically )
*/
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] , SP_HDCP_AUTO_TIMER_REG ,
0x00 ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_HDCP_CTRL_REG , SP_LINK_POLLING ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_LINK_DEBUG_CTRL_REG , SP_M_VID_DEBUG ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P2 ] ,
SP_ANALOG_DEBUG2_REG , SP_POWERON_TIME_1P5MS ) ;
if ( err )
return err ;
err = anx78xx_xtal_clk_sel ( anx78xx ) ;
if ( err )
return err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] , SP_AUX_DEFER_CTRL_REG ,
SP_DEFER_CTRL_EN | 0x0c ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_POLLING_CTRL_REG ,
SP_AUTO_POLLING_DISABLE ) ;
if ( err )
return err ;
/*
* Short the link integrity check timer to speed up bstatus
* polling for HDCP CTS item 1 A - 07
*/
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_HDCP_LINK_CHECK_TIMER_REG , 0x1d ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_MISC_CTRL_REG , SP_EQ_TRAINING_LOOP ) ;
if ( err )
return err ;
/* Power down the main link by default */
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_ANALOG_POWER_DOWN_REG , SP_CH0_PD ) ;
if ( err )
return err ;
err = anx78xx_link_phy_initialization ( anx78xx ) ;
if ( err )
return err ;
/* Gen m_clk with downspreading */
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_M_CALCULATION_CTRL_REG , SP_M_GEN_CLK_SEL ) ;
if ( err )
return err ;
return 0 ;
}
static int anx78xx_enable_interrupts ( struct anx78xx * anx78xx )
{
int err ;
/*
* BIT0 : INT pin assertion polarity : 1 = assert high
* BIT1 : INT pin output type : 0 = push / pull
*/
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_INT_CTRL_REG , 0x01 ) ;
if ( err )
return err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P2 ] ,
SP_COMMON_INT_MASK4_REG , SP_HPD_LOST | SP_HPD_PLUG ) ;
if ( err )
return err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_DP_INT_MASK1_REG ,
SP_TRAINING_FINISH ) ;
if ( err )
return err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_RX_P0 ] , SP_INT_MASK1_REG ,
SP_CKDT_CHG | SP_SCDT_CHG ) ;
if ( err )
return err ;
return 0 ;
}
static void anx78xx_poweron ( struct anx78xx * anx78xx )
{
struct anx78xx_platform_data * pdata = & anx78xx - > pdata ;
int err ;
if ( WARN_ON ( anx78xx - > powered ) )
return ;
if ( pdata - > dvdd10 ) {
err = regulator_enable ( pdata - > dvdd10 ) ;
if ( err ) {
DRM_ERROR ( " Failed to enable DVDD10 regulator: %d \n " ,
err ) ;
return ;
}
usleep_range ( 1000 , 2000 ) ;
}
gpiod_set_value_cansleep ( pdata - > gpiod_reset , 1 ) ;
usleep_range ( 1000 , 2000 ) ;
gpiod_set_value_cansleep ( pdata - > gpiod_pd , 0 ) ;
usleep_range ( 1000 , 2000 ) ;
gpiod_set_value_cansleep ( pdata - > gpiod_reset , 0 ) ;
/* Power on registers module */
anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_POWERDOWN_CTRL_REG ,
SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD | SP_LINK_PD ) ;
anx78xx_clear_bits ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_POWERDOWN_CTRL_REG ,
SP_REGISTER_PD | SP_TOTAL_PD ) ;
anx78xx - > powered = true ;
}
static void anx78xx_poweroff ( struct anx78xx * anx78xx )
{
struct anx78xx_platform_data * pdata = & anx78xx - > pdata ;
int err ;
if ( WARN_ON ( ! anx78xx - > powered ) )
return ;
gpiod_set_value_cansleep ( pdata - > gpiod_reset , 1 ) ;
usleep_range ( 1000 , 2000 ) ;
gpiod_set_value_cansleep ( pdata - > gpiod_pd , 1 ) ;
usleep_range ( 1000 , 2000 ) ;
if ( pdata - > dvdd10 ) {
err = regulator_disable ( pdata - > dvdd10 ) ;
if ( err ) {
DRM_ERROR ( " Failed to disable DVDD10 regulator: %d \n " ,
err ) ;
return ;
}
usleep_range ( 1000 , 2000 ) ;
}
anx78xx - > powered = false ;
}
static int anx78xx_start ( struct anx78xx * anx78xx )
{
int err ;
/* Power on all modules */
err = anx78xx_clear_bits ( anx78xx - > map [ I2C_IDX_TX_P2 ] ,
SP_POWERDOWN_CTRL_REG ,
SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD |
SP_LINK_PD ) ;
err = anx78xx_enable_interrupts ( anx78xx ) ;
if ( err ) {
DRM_ERROR ( " Failed to enable interrupts: %d \n " , err ) ;
goto err_poweroff ;
}
err = anx78xx_rx_initialization ( anx78xx ) ;
if ( err ) {
DRM_ERROR ( " Failed receiver initialization: %d \n " , err ) ;
goto err_poweroff ;
}
err = anx78xx_tx_initialization ( anx78xx ) ;
if ( err ) {
DRM_ERROR ( " Failed transmitter initialization: %d \n " , err ) ;
goto err_poweroff ;
}
/*
* This delay seems to help keep the hardware in a good state . Without
* it , there are times where it fails silently .
*/
usleep_range ( 10000 , 15000 ) ;
return 0 ;
err_poweroff :
DRM_ERROR ( " Failed SlimPort transmitter initialization: %d \n " , err ) ;
anx78xx_poweroff ( anx78xx ) ;
return err ;
}
static int anx78xx_init_pdata ( struct anx78xx * anx78xx )
{
struct anx78xx_platform_data * pdata = & anx78xx - > pdata ;
struct device * dev = & anx78xx - > client - > dev ;
/* 1.0V digital core power regulator */
pdata - > dvdd10 = devm_regulator_get ( dev , " dvdd10 " ) ;
if ( IS_ERR ( pdata - > dvdd10 ) ) {
DRM_ERROR ( " DVDD10 regulator not found \n " ) ;
return PTR_ERR ( pdata - > dvdd10 ) ;
}
/* GPIO for HPD */
pdata - > gpiod_hpd = devm_gpiod_get ( dev , " hpd " , GPIOD_IN ) ;
if ( IS_ERR ( pdata - > gpiod_hpd ) )
return PTR_ERR ( pdata - > gpiod_hpd ) ;
/* GPIO for chip power down */
pdata - > gpiod_pd = devm_gpiod_get ( dev , " pd " , GPIOD_OUT_HIGH ) ;
if ( IS_ERR ( pdata - > gpiod_pd ) )
return PTR_ERR ( pdata - > gpiod_pd ) ;
/* GPIO for chip reset */
pdata - > gpiod_reset = devm_gpiod_get ( dev , " reset " , GPIOD_OUT_LOW ) ;
return PTR_ERR_OR_ZERO ( pdata - > gpiod_reset ) ;
}
static int anx78xx_dp_link_training ( struct anx78xx * anx78xx )
{
u8 dp_bw , value ;
int err ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_RX_P0 ] , SP_HDMI_MUTE_CTRL_REG ,
0x0 ) ;
if ( err )
return err ;
err = anx78xx_clear_bits ( anx78xx - > map [ I2C_IDX_TX_P2 ] ,
SP_POWERDOWN_CTRL_REG ,
SP_TOTAL_PD ) ;
if ( err )
return err ;
err = drm_dp_dpcd_readb ( & anx78xx - > aux , DP_MAX_LINK_RATE , & dp_bw ) ;
if ( err < 0 )
return err ;
switch ( dp_bw ) {
case DP_LINK_BW_1_62 :
case DP_LINK_BW_2_7 :
case DP_LINK_BW_5_4 :
break ;
default :
DRM_DEBUG_KMS ( " DP bandwidth (%#02x) not supported \n " , dp_bw ) ;
return - EINVAL ;
}
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_VID_CTRL1_REG ,
SP_VIDEO_MUTE ) ;
if ( err )
return err ;
err = anx78xx_clear_bits ( anx78xx - > map [ I2C_IDX_TX_P2 ] ,
SP_VID_CTRL1_REG , SP_VIDEO_EN ) ;
if ( err )
return err ;
/* Get DPCD info */
err = drm_dp_dpcd_read ( & anx78xx - > aux , DP_DPCD_REV ,
& anx78xx - > dpcd , DP_RECEIVER_CAP_SIZE ) ;
if ( err < 0 ) {
DRM_ERROR ( " Failed to read DPCD: %d \n " , err ) ;
return err ;
}
/* Clear channel x SERDES power down */
err = anx78xx_clear_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_ANALOG_POWER_DOWN_REG , SP_CH0_PD ) ;
if ( err )
return err ;
/* Check link capabilities */
err = drm_dp_link_probe ( & anx78xx - > aux , & anx78xx - > link ) ;
if ( err < 0 ) {
DRM_ERROR ( " Failed to probe link capabilities: %d \n " , err ) ;
return err ;
}
/* Power up the sink */
err = drm_dp_link_power_up ( & anx78xx - > aux , & anx78xx - > link ) ;
if ( err < 0 ) {
DRM_ERROR ( " Failed to power up DisplayPort link: %d \n " , err ) ;
return err ;
}
/* Possibly enable downspread on the sink */
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_DOWNSPREAD_CTRL1_REG , 0 ) ;
if ( err )
return err ;
if ( anx78xx - > dpcd [ DP_MAX_DOWNSPREAD ] & DP_MAX_DOWNSPREAD_0_5 ) {
DRM_DEBUG ( " Enable downspread on the sink \n " ) ;
/* 4000PPM */
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_DOWNSPREAD_CTRL1_REG , 8 ) ;
if ( err )
return err ;
err = drm_dp_dpcd_writeb ( & anx78xx - > aux , DP_DOWNSPREAD_CTRL ,
DP_SPREAD_AMP_0_5 ) ;
if ( err < 0 )
return err ;
} else {
err = drm_dp_dpcd_writeb ( & anx78xx - > aux , DP_DOWNSPREAD_CTRL , 0 ) ;
if ( err < 0 )
return err ;
}
/* Set the lane count and the link rate on the sink */
if ( drm_dp_enhanced_frame_cap ( anx78xx - > dpcd ) )
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_SYSTEM_CTRL_BASE + 4 ,
SP_ENHANCED_MODE ) ;
else
err = anx78xx_clear_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_SYSTEM_CTRL_BASE + 4 ,
SP_ENHANCED_MODE ) ;
if ( err )
return err ;
value = drm_dp_link_rate_to_bw_code ( anx78xx - > link . rate ) ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_DP_MAIN_LINK_BW_SET_REG , value ) ;
if ( err )
return err ;
err = drm_dp_link_configure ( & anx78xx - > aux , & anx78xx - > link ) ;
if ( err < 0 ) {
DRM_ERROR ( " Failed to configure DisplayPort link: %d \n " , err ) ;
return err ;
}
/* Start training on the source */
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P0 ] , SP_DP_LT_CTRL_REG ,
SP_LT_EN ) ;
if ( err )
return err ;
return 0 ;
}
static int anx78xx_config_dp_output ( struct anx78xx * anx78xx )
{
int err ;
err = anx78xx_clear_bits ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_VID_CTRL1_REG ,
SP_VIDEO_MUTE ) ;
if ( err )
return err ;
/* Enable DP output */
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_VID_CTRL1_REG ,
SP_VIDEO_EN ) ;
if ( err )
return err ;
return 0 ;
}
static int anx78xx_send_video_infoframe ( struct anx78xx * anx78xx ,
struct hdmi_avi_infoframe * frame )
{
u8 buffer [ HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE ] ;
int err ;
err = hdmi_avi_infoframe_pack ( frame , buffer , sizeof ( buffer ) ) ;
if ( err < 0 ) {
DRM_ERROR ( " Failed to pack AVI infoframe: %d \n " , err ) ;
return err ;
}
err = anx78xx_clear_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_PACKET_SEND_CTRL_REG , SP_AVI_IF_EN ) ;
if ( err )
return err ;
err = regmap_bulk_write ( anx78xx - > map [ I2C_IDX_TX_P2 ] ,
SP_INFOFRAME_AVI_DB1_REG , buffer ,
frame - > length ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_PACKET_SEND_CTRL_REG , SP_AVI_IF_UD ) ;
if ( err )
return err ;
err = anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P0 ] ,
SP_PACKET_SEND_CTRL_REG , SP_AVI_IF_EN ) ;
if ( err )
return err ;
return 0 ;
}
static int anx78xx_get_downstream_info ( struct anx78xx * anx78xx )
{
u8 value ;
int err ;
err = drm_dp_dpcd_readb ( & anx78xx - > aux , DP_SINK_COUNT , & value ) ;
if ( err < 0 ) {
DRM_ERROR ( " Get sink count failed %d \n " , err ) ;
return err ;
}
if ( ! DP_GET_SINK_COUNT ( value ) ) {
DRM_ERROR ( " Downstream disconnected \n " ) ;
return - EIO ;
}
return 0 ;
}
static int anx78xx_get_modes ( struct drm_connector * connector )
{
struct anx78xx * anx78xx = connector_to_anx78xx ( connector ) ;
int err , num_modes = 0 ;
if ( WARN_ON ( ! anx78xx - > powered ) )
return 0 ;
if ( anx78xx - > edid )
return drm_add_edid_modes ( connector , anx78xx - > edid ) ;
mutex_lock ( & anx78xx - > lock ) ;
err = anx78xx_get_downstream_info ( anx78xx ) ;
if ( err ) {
DRM_ERROR ( " Failed to get downstream info: %d \n " , err ) ;
goto unlock ;
}
anx78xx - > edid = drm_get_edid ( connector , & anx78xx - > aux . ddc ) ;
if ( ! anx78xx - > edid ) {
DRM_ERROR ( " Failed to read EDID \n " ) ;
goto unlock ;
}
2018-07-09 10:40:06 +02:00
err = drm_connector_update_edid_property ( connector ,
anx78xx - > edid ) ;
2016-05-02 09:54:26 +02:00
if ( err ) {
DRM_ERROR ( " Failed to update EDID property: %d \n " , err ) ;
goto unlock ;
}
num_modes = drm_add_edid_modes ( connector , anx78xx - > edid ) ;
unlock :
mutex_unlock ( & anx78xx - > lock ) ;
return num_modes ;
}
static const struct drm_connector_helper_funcs anx78xx_connector_helper_funcs = {
. get_modes = anx78xx_get_modes ,
} ;
static enum drm_connector_status anx78xx_detect ( struct drm_connector * connector ,
bool force )
{
struct anx78xx * anx78xx = connector_to_anx78xx ( connector ) ;
if ( ! gpiod_get_value ( anx78xx - > pdata . gpiod_hpd ) )
return connector_status_disconnected ;
return connector_status_connected ;
}
static const struct drm_connector_funcs anx78xx_connector_funcs = {
. fill_modes = drm_helper_probe_single_connector_modes ,
. detect = anx78xx_detect ,
2016-10-05 00:23:31 +02:00
. destroy = drm_connector_cleanup ,
2016-05-02 09:54:26 +02:00
. reset = drm_atomic_helper_connector_reset ,
. atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state ,
. atomic_destroy_state = drm_atomic_helper_connector_destroy_state ,
} ;
static int anx78xx_bridge_attach ( struct drm_bridge * bridge )
{
struct anx78xx * anx78xx = bridge_to_anx78xx ( bridge ) ;
int err ;
if ( ! bridge - > encoder ) {
DRM_ERROR ( " Parent encoder object not found " ) ;
return - ENODEV ;
}
/* Register aux channel */
anx78xx - > aux . name = " DP-AUX " ;
anx78xx - > aux . dev = & anx78xx - > client - > dev ;
anx78xx - > aux . transfer = anx78xx_aux_transfer ;
err = drm_dp_aux_register ( & anx78xx - > aux ) ;
if ( err < 0 ) {
DRM_ERROR ( " Failed to register aux channel: %d \n " , err ) ;
return err ;
}
err = drm_connector_init ( bridge - > dev , & anx78xx - > connector ,
& anx78xx_connector_funcs ,
DRM_MODE_CONNECTOR_DisplayPort ) ;
if ( err ) {
DRM_ERROR ( " Failed to initialize connector: %d \n " , err ) ;
return err ;
}
drm_connector_helper_add ( & anx78xx - > connector ,
& anx78xx_connector_helper_funcs ) ;
err = drm_connector_register ( & anx78xx - > connector ) ;
if ( err ) {
DRM_ERROR ( " Failed to register connector: %d \n " , err ) ;
return err ;
}
anx78xx - > connector . polled = DRM_CONNECTOR_POLL_HPD ;
2018-07-09 10:40:07 +02:00
err = drm_connector_attach_encoder ( & anx78xx - > connector ,
bridge - > encoder ) ;
2016-05-02 09:54:26 +02:00
if ( err ) {
DRM_ERROR ( " Failed to link up connector to encoder: %d \n " , err ) ;
return err ;
}
return 0 ;
}
2017-05-25 15:19:18 +01:00
static enum drm_mode_status
anx78xx_bridge_mode_valid ( struct drm_bridge * bridge ,
const struct drm_display_mode * mode )
2016-05-02 09:54:26 +02:00
{
if ( mode - > flags & DRM_MODE_FLAG_INTERLACE )
2017-05-25 15:19:18 +01:00
return MODE_NO_INTERLACE ;
2016-05-02 09:54:26 +02:00
/* Max 1200p at 5.4 Ghz, one lane */
if ( mode - > clock > 154000 )
2017-05-25 15:19:18 +01:00
return MODE_CLOCK_HIGH ;
2016-05-02 09:54:26 +02:00
2017-05-25 15:19:18 +01:00
return MODE_OK ;
2016-05-02 09:54:26 +02:00
}
static void anx78xx_bridge_disable ( struct drm_bridge * bridge )
{
struct anx78xx * anx78xx = bridge_to_anx78xx ( bridge ) ;
/* Power off all modules except configuration registers access */
anx78xx_set_bits ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_POWERDOWN_CTRL_REG ,
SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD | SP_LINK_PD ) ;
}
static void anx78xx_bridge_mode_set ( struct drm_bridge * bridge ,
struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
struct anx78xx * anx78xx = bridge_to_anx78xx ( bridge ) ;
struct hdmi_avi_infoframe frame ;
int err ;
if ( WARN_ON ( ! anx78xx - > powered ) )
return ;
mutex_lock ( & anx78xx - > lock ) ;
drm: handle HDMI 2.0 VICs in AVI info-frames
HDMI 1.4b support the CEA video modes as per range of CEA-861-D (VIC 1-64).
For any other mode, the VIC filed in AVI infoframes should be 0.
HDMI 2.0 sinks, support video modes range as per CEA-861-F spec, which is
extended to (VIC 1-107).
This patch adds a bool input variable, which indicates if the connected
sink is a HDMI 2.0 sink or not. This will make sure that we don't pass a
HDMI 2.0 VIC to a HDMI 1.4 sink.
This patch touches all drm drivers, who are callers of this function
drm_hdmi_avi_infoframe_from_display_mode but to make sure there is
no change in current behavior, is_hdmi2 is kept as false.
In case of I915 driver, this patch:
- checks if the connected display is HDMI 2.0.
- HDMI infoframes carry one of this two type of information:
- VIC for 4K modes for HDMI 1.4 sinks
- S3D information for S3D modes
As CEA-861-F has already defined VICs for 4K videomodes, this
patch doesn't allow sending HDMI infoframes for HDMI 2.0 sinks,
until the mode is 3D.
Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Jose Abreu <jose.abreu@synopsys.com>
Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
PS: This patch touches a few lines in few files, which were
already above 80 char, so checkpatch gives 80 char warning again.
- gpu/drm/omapdrm/omap_encoder.c
- gpu/drm/i915/intel_sdvo.c
V2: Rebase, Added r-b from Andrzej
V3: Addressed review comment from Ville:
- Do not send VICs in both AVI-IF and HDMI-IF
send only one of it.
V4: Rebase
V5: Added r-b from Neil.
Addressed review comments from Ville
- Do not block HDMI vendor IF, instead check for VIC while
handling AVI infoframes
V6: Rebase
V7: Rebase
Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
Signed-off-by: Shashank Sharma <shashank.sharma@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1499960000-9232-2-git-send-email-shashank.sharma@intel.com
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
2017-07-13 21:03:07 +05:30
err = drm_hdmi_avi_infoframe_from_display_mode ( & frame , adjusted_mode ,
false ) ;
2016-05-02 09:54:26 +02:00
if ( err ) {
DRM_ERROR ( " Failed to setup AVI infoframe: %d \n " , err ) ;
goto unlock ;
}
err = anx78xx_send_video_infoframe ( anx78xx , & frame ) ;
if ( err )
DRM_ERROR ( " Failed to send AVI infoframe: %d \n " , err ) ;
unlock :
mutex_unlock ( & anx78xx - > lock ) ;
}
static void anx78xx_bridge_enable ( struct drm_bridge * bridge )
{
struct anx78xx * anx78xx = bridge_to_anx78xx ( bridge ) ;
int err ;
err = anx78xx_start ( anx78xx ) ;
if ( err ) {
DRM_ERROR ( " Failed to initialize: %d \n " , err ) ;
return ;
}
err = anx78xx_set_hpd ( anx78xx ) ;
if ( err )
DRM_ERROR ( " Failed to set HPD: %d \n " , err ) ;
}
static const struct drm_bridge_funcs anx78xx_bridge_funcs = {
. attach = anx78xx_bridge_attach ,
2017-05-25 15:19:18 +01:00
. mode_valid = anx78xx_bridge_mode_valid ,
2016-05-02 09:54:26 +02:00
. disable = anx78xx_bridge_disable ,
. mode_set = anx78xx_bridge_mode_set ,
. enable = anx78xx_bridge_enable ,
} ;
static irqreturn_t anx78xx_hpd_threaded_handler ( int irq , void * data )
{
struct anx78xx * anx78xx = data ;
int err ;
if ( anx78xx - > powered )
return IRQ_HANDLED ;
mutex_lock ( & anx78xx - > lock ) ;
/* Cable is pulled, power on the chip */
anx78xx_poweron ( anx78xx ) ;
err = anx78xx_enable_interrupts ( anx78xx ) ;
if ( err )
DRM_ERROR ( " Failed to enable interrupts: %d \n " , err ) ;
mutex_unlock ( & anx78xx - > lock ) ;
return IRQ_HANDLED ;
}
static int anx78xx_handle_dp_int_1 ( struct anx78xx * anx78xx , u8 irq )
{
int err ;
DRM_DEBUG_KMS ( " Handle DP interrupt 1: %02x \n " , irq ) ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_DP_INT_STATUS1_REG ,
irq ) ;
if ( err )
return err ;
if ( irq & SP_TRAINING_FINISH ) {
DRM_DEBUG_KMS ( " IRQ: hardware link training finished \n " ) ;
err = anx78xx_config_dp_output ( anx78xx ) ;
}
return err ;
}
static bool anx78xx_handle_common_int_4 ( struct anx78xx * anx78xx , u8 irq )
{
bool event = false ;
int err ;
DRM_DEBUG_KMS ( " Handle common interrupt 4: %02x \n " , irq ) ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_TX_P2 ] ,
SP_COMMON_INT_STATUS4_REG , irq ) ;
if ( err ) {
DRM_ERROR ( " Failed to write SP_COMMON_INT_STATUS4 %d \n " , err ) ;
return event ;
}
if ( irq & SP_HPD_LOST ) {
DRM_DEBUG_KMS ( " IRQ: Hot plug detect - cable is pulled out \n " ) ;
event = true ;
anx78xx_poweroff ( anx78xx ) ;
/* Free cached EDID */
kfree ( anx78xx - > edid ) ;
anx78xx - > edid = NULL ;
} else if ( irq & SP_HPD_PLUG ) {
DRM_DEBUG_KMS ( " IRQ: Hot plug detect - cable plug \n " ) ;
event = true ;
}
return event ;
}
static void anx78xx_handle_hdmi_int_1 ( struct anx78xx * anx78xx , u8 irq )
{
unsigned int value ;
int err ;
DRM_DEBUG_KMS ( " Handle HDMI interrupt 1: %02x \n " , irq ) ;
err = regmap_write ( anx78xx - > map [ I2C_IDX_RX_P0 ] , SP_INT_STATUS1_REG ,
irq ) ;
if ( err ) {
DRM_ERROR ( " Write HDMI int 1 failed: %d \n " , err ) ;
return ;
}
if ( ( irq & SP_CKDT_CHG ) | | ( irq & SP_SCDT_CHG ) ) {
DRM_DEBUG_KMS ( " IRQ: HDMI input detected \n " ) ;
err = regmap_read ( anx78xx - > map [ I2C_IDX_RX_P0 ] ,
SP_SYSTEM_STATUS_REG , & value ) ;
if ( err ) {
DRM_ERROR ( " Read system status reg failed: %d \n " , err ) ;
return ;
}
if ( ! ( value & SP_TMDS_CLOCK_DET ) ) {
DRM_DEBUG_KMS ( " IRQ: *** Waiting for HDMI clock *** \n " ) ;
return ;
}
if ( ! ( value & SP_TMDS_DE_DET ) ) {
DRM_DEBUG_KMS ( " IRQ: *** Waiting for HDMI signal *** \n " ) ;
return ;
}
err = anx78xx_dp_link_training ( anx78xx ) ;
if ( err )
DRM_ERROR ( " Failed to start link training: %d \n " , err ) ;
}
}
static irqreturn_t anx78xx_intp_threaded_handler ( int unused , void * data )
{
struct anx78xx * anx78xx = data ;
bool event = false ;
unsigned int irq ;
int err ;
mutex_lock ( & anx78xx - > lock ) ;
err = regmap_read ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_DP_INT_STATUS1_REG ,
& irq ) ;
if ( err ) {
DRM_ERROR ( " Failed to read DP interrupt 1 status: %d \n " , err ) ;
goto unlock ;
}
if ( irq )
anx78xx_handle_dp_int_1 ( anx78xx , irq ) ;
err = regmap_read ( anx78xx - > map [ I2C_IDX_TX_P2 ] ,
SP_COMMON_INT_STATUS4_REG , & irq ) ;
if ( err ) {
DRM_ERROR ( " Failed to read common interrupt 4 status: %d \n " ,
err ) ;
goto unlock ;
}
if ( irq )
event = anx78xx_handle_common_int_4 ( anx78xx , irq ) ;
/* Make sure we are still powered after handle HPD events */
if ( ! anx78xx - > powered )
goto unlock ;
err = regmap_read ( anx78xx - > map [ I2C_IDX_RX_P0 ] , SP_INT_STATUS1_REG ,
& irq ) ;
if ( err ) {
DRM_ERROR ( " Failed to read HDMI int 1 status: %d \n " , err ) ;
goto unlock ;
}
if ( irq )
anx78xx_handle_hdmi_int_1 ( anx78xx , irq ) ;
unlock :
mutex_unlock ( & anx78xx - > lock ) ;
if ( event )
drm_helper_hpd_irq_event ( anx78xx - > connector . dev ) ;
return IRQ_HANDLED ;
}
static void unregister_i2c_dummy_clients ( struct anx78xx * anx78xx )
{
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( anx78xx - > i2c_dummy ) ; i + + )
2017-10-31 16:21:40 +02:00
i2c_unregister_device ( anx78xx - > i2c_dummy [ i ] ) ;
2016-05-02 09:54:26 +02:00
}
static const struct regmap_config anx78xx_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
} ;
static const u16 anx78xx_chipid_list [ ] = {
0x7812 ,
0x7814 ,
0x7818 ,
} ;
static int anx78xx_i2c_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
struct anx78xx * anx78xx ;
struct anx78xx_platform_data * pdata ;
unsigned int i , idl , idh , version ;
bool found = false ;
int err ;
anx78xx = devm_kzalloc ( & client - > dev , sizeof ( * anx78xx ) , GFP_KERNEL ) ;
if ( ! anx78xx )
return - ENOMEM ;
pdata = & anx78xx - > pdata ;
mutex_init ( & anx78xx - > lock ) ;
# if IS_ENABLED(CONFIG_OF)
anx78xx - > bridge . of_node = client - > dev . of_node ;
# endif
anx78xx - > client = client ;
i2c_set_clientdata ( client , anx78xx ) ;
err = anx78xx_init_pdata ( anx78xx ) ;
if ( err ) {
DRM_ERROR ( " Failed to initialize pdata: %d \n " , err ) ;
return err ;
}
pdata - > hpd_irq = gpiod_to_irq ( pdata - > gpiod_hpd ) ;
if ( pdata - > hpd_irq < 0 ) {
DRM_ERROR ( " Failed to get HPD IRQ: %d \n " , pdata - > hpd_irq ) ;
return - ENODEV ;
}
pdata - > intp_irq = client - > irq ;
if ( ! pdata - > intp_irq ) {
DRM_ERROR ( " Failed to get CABLE_DET and INTP IRQ \n " ) ;
return - ENODEV ;
}
/* Map slave addresses of ANX7814 */
for ( i = 0 ; i < I2C_NUM_ADDRESSES ; i + + ) {
anx78xx - > i2c_dummy [ i ] = i2c_new_dummy ( client - > adapter ,
anx78xx_i2c_addresses [ i ] > > 1 ) ;
if ( ! anx78xx - > i2c_dummy [ i ] ) {
err = - ENOMEM ;
DRM_ERROR ( " Failed to reserve I2C bus %02x \n " ,
anx78xx_i2c_addresses [ i ] ) ;
goto err_unregister_i2c ;
}
anx78xx - > map [ i ] = devm_regmap_init_i2c ( anx78xx - > i2c_dummy [ i ] ,
& anx78xx_regmap_config ) ;
if ( IS_ERR ( anx78xx - > map [ i ] ) ) {
err = PTR_ERR ( anx78xx - > map [ i ] ) ;
DRM_ERROR ( " Failed regmap initialization %02x \n " ,
anx78xx_i2c_addresses [ i ] ) ;
goto err_unregister_i2c ;
}
}
/* Look for supported chip ID */
anx78xx_poweron ( anx78xx ) ;
err = regmap_read ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_DEVICE_IDL_REG ,
& idl ) ;
if ( err )
goto err_poweroff ;
err = regmap_read ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_DEVICE_IDH_REG ,
& idh ) ;
if ( err )
goto err_poweroff ;
anx78xx - > chipid = ( u8 ) idl | ( ( u8 ) idh < < 8 ) ;
err = regmap_read ( anx78xx - > map [ I2C_IDX_TX_P2 ] , SP_DEVICE_VERSION_REG ,
& version ) ;
if ( err )
goto err_poweroff ;
for ( i = 0 ; i < ARRAY_SIZE ( anx78xx_chipid_list ) ; i + + ) {
if ( anx78xx - > chipid = = anx78xx_chipid_list [ i ] ) {
DRM_INFO ( " Found ANX%x (ver. %d) SlimPort Transmitter \n " ,
anx78xx - > chipid , version ) ;
found = true ;
break ;
}
}
if ( ! found ) {
DRM_ERROR ( " ANX%x (ver. %d) not supported by this driver \n " ,
anx78xx - > chipid , version ) ;
err = - ENODEV ;
goto err_poweroff ;
}
err = devm_request_threaded_irq ( & client - > dev , pdata - > hpd_irq , NULL ,
anx78xx_hpd_threaded_handler ,
IRQF_TRIGGER_RISING | IRQF_ONESHOT ,
" anx78xx-hpd " , anx78xx ) ;
if ( err ) {
DRM_ERROR ( " Failed to request CABLE_DET threaded IRQ: %d \n " ,
err ) ;
goto err_poweroff ;
}
err = devm_request_threaded_irq ( & client - > dev , pdata - > intp_irq , NULL ,
anx78xx_intp_threaded_handler ,
IRQF_TRIGGER_RISING | IRQF_ONESHOT ,
" anx78xx-intp " , anx78xx ) ;
if ( err ) {
DRM_ERROR ( " Failed to request INTP threaded IRQ: %d \n " , err ) ;
goto err_poweroff ;
}
anx78xx - > bridge . funcs = & anx78xx_bridge_funcs ;
2017-07-03 17:42:19 +09:00
drm_bridge_add ( & anx78xx - > bridge ) ;
2016-05-02 09:54:26 +02:00
/* If cable is pulled out, just poweroff and wait for HPD event */
if ( ! gpiod_get_value ( anx78xx - > pdata . gpiod_hpd ) )
anx78xx_poweroff ( anx78xx ) ;
return 0 ;
err_poweroff :
anx78xx_poweroff ( anx78xx ) ;
err_unregister_i2c :
unregister_i2c_dummy_clients ( anx78xx ) ;
return err ;
}
static int anx78xx_i2c_remove ( struct i2c_client * client )
{
struct anx78xx * anx78xx = i2c_get_clientdata ( client ) ;
drm_bridge_remove ( & anx78xx - > bridge ) ;
unregister_i2c_dummy_clients ( anx78xx ) ;
kfree ( anx78xx - > edid ) ;
return 0 ;
}
static const struct i2c_device_id anx78xx_id [ ] = {
{ " anx7814 " , 0 } ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( i2c , anx78xx_id ) ;
# if IS_ENABLED(CONFIG_OF)
static const struct of_device_id anx78xx_match_table [ ] = {
{ . compatible = " analogix,anx7814 " , } ,
{ /* sentinel */ } ,
} ;
MODULE_DEVICE_TABLE ( of , anx78xx_match_table ) ;
# endif
static struct i2c_driver anx78xx_driver = {
. driver = {
. name = " anx7814 " ,
. of_match_table = of_match_ptr ( anx78xx_match_table ) ,
} ,
. probe = anx78xx_i2c_probe ,
. remove = anx78xx_i2c_remove ,
. id_table = anx78xx_id ,
} ;
module_i2c_driver ( anx78xx_driver ) ;
MODULE_DESCRIPTION ( " ANX78xx SlimPort Transmitter driver " ) ;
MODULE_AUTHOR ( " Enric Balletbo i Serra <enric.balletbo@collabora.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;