2013-11-29 08:46:32 -02:00
/*
* Copyright ( C ) 2011 - 2013 Freescale Semiconductor , Inc .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
2014-12-05 14:26:31 +08:00
* Designware High - Definition Multimedia Interface ( HDMI ) driver
2013-11-29 08:46:32 -02:00
*
* Copyright ( C ) 2010 , Guennadi Liakhovetski < g . liakhovetski @ gmx . de >
*/
2014-12-05 14:26:31 +08:00
# include <linux/module.h>
2013-11-29 08:46:32 -02:00
# include <linux/irq.h>
# include <linux/delay.h>
# include <linux/err.h>
# include <linux/clk.h>
2014-01-28 10:33:16 +05:30
# include <linux/hdmi.h>
2015-02-02 11:01:08 +00:00
# include <linux/mutex.h>
2013-11-29 08:46:32 -02:00
# include <linux/of_device.h>
2015-03-27 12:59:58 +00:00
# include <linux/spinlock.h>
2013-11-29 08:46:32 -02:00
2014-12-05 14:25:05 +08:00
# include <drm/drm_of.h>
2013-11-29 08:46:32 -02:00
# include <drm/drmP.h>
# include <drm/drm_crtc_helper.h>
# include <drm/drm_edid.h>
# include <drm/drm_encoder_slave.h>
2014-12-05 14:26:31 +08:00
# include <drm/bridge/dw_hdmi.h>
2013-11-29 08:46:32 -02:00
2014-12-05 14:26:31 +08:00
# include "dw_hdmi.h"
2013-11-29 08:46:32 -02:00
# define HDMI_EDID_LEN 512
# define RGB 0
# define YCBCR444 1
# define YCBCR422_16BITS 2
# define YCBCR422_8BITS 3
# define XVYCC444 4
enum hdmi_datamap {
RGB444_8B = 0x01 ,
RGB444_10B = 0x03 ,
RGB444_12B = 0x05 ,
RGB444_16B = 0x07 ,
YCbCr444_8B = 0x09 ,
YCbCr444_10B = 0x0B ,
YCbCr444_12B = 0x0D ,
YCbCr444_16B = 0x0F ,
YCbCr422_8B = 0x16 ,
YCbCr422_10B = 0x14 ,
YCbCr422_12B = 0x12 ,
} ;
static const u16 csc_coeff_default [ 3 ] [ 4 ] = {
{ 0x2000 , 0x0000 , 0x0000 , 0x0000 } ,
{ 0x0000 , 0x2000 , 0x0000 , 0x0000 } ,
{ 0x0000 , 0x0000 , 0x2000 , 0x0000 }
} ;
static const u16 csc_coeff_rgb_out_eitu601 [ 3 ] [ 4 ] = {
{ 0x2000 , 0x6926 , 0x74fd , 0x010e } ,
{ 0x2000 , 0x2cdd , 0x0000 , 0x7e9a } ,
{ 0x2000 , 0x0000 , 0x38b4 , 0x7e3b }
} ;
static const u16 csc_coeff_rgb_out_eitu709 [ 3 ] [ 4 ] = {
{ 0x2000 , 0x7106 , 0x7a02 , 0x00a7 } ,
{ 0x2000 , 0x3264 , 0x0000 , 0x7e6d } ,
{ 0x2000 , 0x0000 , 0x3b61 , 0x7e25 }
} ;
static const u16 csc_coeff_rgb_in_eitu601 [ 3 ] [ 4 ] = {
{ 0x2591 , 0x1322 , 0x074b , 0x0000 } ,
{ 0x6535 , 0x2000 , 0x7acc , 0x0200 } ,
{ 0x6acd , 0x7534 , 0x2000 , 0x0200 }
} ;
static const u16 csc_coeff_rgb_in_eitu709 [ 3 ] [ 4 ] = {
{ 0x2dc5 , 0x0d9b , 0x049e , 0x0000 } ,
{ 0x62f0 , 0x2000 , 0x7d11 , 0x0200 } ,
{ 0x6756 , 0x78ab , 0x2000 , 0x0200 }
} ;
struct hdmi_vmode {
bool mdataenablepolarity ;
unsigned int mpixelclock ;
unsigned int mpixelrepetitioninput ;
unsigned int mpixelrepetitionoutput ;
} ;
struct hdmi_data_info {
unsigned int enc_in_format ;
unsigned int enc_out_format ;
unsigned int enc_color_depth ;
unsigned int colorimetry ;
unsigned int pix_repet_factor ;
unsigned int hdcp_enable ;
struct hdmi_vmode video_mode ;
} ;
2014-12-05 14:26:31 +08:00
struct dw_hdmi {
2013-11-29 08:46:32 -02:00
struct drm_connector connector ;
2014-12-05 14:25:05 +08:00
struct drm_encoder * encoder ;
struct drm_bridge * bridge ;
2013-11-29 08:46:32 -02:00
2014-12-05 14:26:31 +08:00
enum dw_hdmi_devtype dev_type ;
2013-11-29 08:46:32 -02:00
struct device * dev ;
struct clk * isfr_clk ;
struct clk * iahb_clk ;
struct hdmi_data_info hdmi_data ;
2014-12-05 14:26:31 +08:00
const struct dw_hdmi_plat_data * plat_data ;
2013-11-29 08:46:32 -02:00
int vic ;
u8 edid [ HDMI_EDID_LEN ] ;
bool cable_plugin ;
bool phy_enabled ;
struct drm_display_mode previous_mode ;
struct i2c_adapter * ddc ;
void __iomem * regs ;
2015-07-21 15:35:52 +01:00
bool sink_is_hdmi ;
2013-11-29 08:46:32 -02:00
2015-03-27 12:59:58 +00:00
spinlock_t audio_lock ;
2015-02-02 11:01:08 +00:00
struct mutex audio_mutex ;
2013-11-29 08:46:32 -02:00
unsigned int sample_rate ;
2015-03-27 12:59:58 +00:00
unsigned int audio_cts ;
unsigned int audio_n ;
bool audio_enable ;
2013-11-29 08:46:32 -02:00
int ratio ;
2014-12-05 14:28:24 +08:00
void ( * write ) ( struct dw_hdmi * hdmi , u8 val , int offset ) ;
u8 ( * read ) ( struct dw_hdmi * hdmi , int offset ) ;
2013-11-29 08:46:32 -02:00
} ;
2014-12-05 14:28:24 +08:00
static void dw_hdmi_writel ( struct dw_hdmi * hdmi , u8 val , int offset )
{
writel ( val , hdmi - > regs + ( offset < < 2 ) ) ;
}
static u8 dw_hdmi_readl ( struct dw_hdmi * hdmi , int offset )
{
return readl ( hdmi - > regs + ( offset < < 2 ) ) ;
}
static void dw_hdmi_writeb ( struct dw_hdmi * hdmi , u8 val , int offset )
2013-11-29 08:46:32 -02:00
{
writeb ( val , hdmi - > regs + offset ) ;
}
2014-12-05 14:28:24 +08:00
static u8 dw_hdmi_readb ( struct dw_hdmi * hdmi , int offset )
2013-11-29 08:46:32 -02:00
{
return readb ( hdmi - > regs + offset ) ;
}
2014-12-05 14:28:24 +08:00
static inline void hdmi_writeb ( struct dw_hdmi * hdmi , u8 val , int offset )
{
hdmi - > write ( hdmi , val , offset ) ;
}
static inline u8 hdmi_readb ( struct dw_hdmi * hdmi , int offset )
{
return hdmi - > read ( hdmi , offset ) ;
}
2014-12-05 14:26:31 +08:00
static void hdmi_modb ( struct dw_hdmi * hdmi , u8 data , u8 mask , unsigned reg )
2013-11-04 12:42:02 +00:00
{
u8 val = hdmi_readb ( hdmi , reg ) & ~ mask ;
2014-04-28 08:01:07 -03:00
2013-11-04 12:42:02 +00:00
val | = data & mask ;
hdmi_writeb ( hdmi , val , reg ) ;
}
2014-12-05 14:26:31 +08:00
static void hdmi_mask_writeb ( struct dw_hdmi * hdmi , u8 data , unsigned int reg ,
2014-12-05 14:23:52 +08:00
u8 shift , u8 mask )
2013-11-29 08:46:32 -02:00
{
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , data < < shift , mask , reg ) ;
2013-11-29 08:46:32 -02:00
}
2015-01-31 14:50:23 +00:00
static void hdmi_set_cts_n ( struct dw_hdmi * hdmi , unsigned int cts ,
unsigned int n )
2013-11-29 08:46:32 -02:00
{
2015-02-02 10:55:38 +00:00
/* Must be set/cleared first */
hdmi_modb ( hdmi , 0 , HDMI_AUD_CTS3_CTS_MANUAL , HDMI_AUD_CTS3 ) ;
2013-11-29 08:46:32 -02:00
/* nshift factor = 0 */
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , 0 , HDMI_AUD_CTS3_N_SHIFT_MASK , HDMI_AUD_CTS3 ) ;
2013-11-29 08:46:32 -02:00
hdmi_writeb ( hdmi , ( ( cts > > 16 ) & HDMI_AUD_CTS3_AUDCTS19_16_MASK ) |
HDMI_AUD_CTS3_CTS_MANUAL , HDMI_AUD_CTS3 ) ;
2015-02-02 10:55:38 +00:00
hdmi_writeb ( hdmi , ( cts > > 8 ) & 0xff , HDMI_AUD_CTS2 ) ;
hdmi_writeb ( hdmi , cts & 0xff , HDMI_AUD_CTS1 ) ;
hdmi_writeb ( hdmi , ( n > > 16 ) & 0x0f , HDMI_AUD_N3 ) ;
hdmi_writeb ( hdmi , ( n > > 8 ) & 0xff , HDMI_AUD_N2 ) ;
hdmi_writeb ( hdmi , n & 0xff , HDMI_AUD_N1 ) ;
2013-11-29 08:46:32 -02:00
}
static unsigned int hdmi_compute_n ( unsigned int freq , unsigned long pixel_clk ,
unsigned int ratio )
{
unsigned int n = ( 128 * freq ) / 1000 ;
switch ( freq ) {
case 32000 :
if ( pixel_clk = = 25170000 )
n = ( ratio = = 150 ) ? 9152 : 4576 ;
else if ( pixel_clk = = 27020000 )
n = ( ratio = = 150 ) ? 8192 : 4096 ;
else if ( pixel_clk = = 74170000 | | pixel_clk = = 148350000 )
n = 11648 ;
else
n = 4096 ;
break ;
case 44100 :
if ( pixel_clk = = 25170000 )
n = 7007 ;
else if ( pixel_clk = = 74170000 )
n = 17836 ;
else if ( pixel_clk = = 148350000 )
n = ( ratio = = 150 ) ? 17836 : 8918 ;
else
n = 6272 ;
break ;
case 48000 :
if ( pixel_clk = = 25170000 )
n = ( ratio = = 150 ) ? 9152 : 6864 ;
else if ( pixel_clk = = 27020000 )
n = ( ratio = = 150 ) ? 8192 : 6144 ;
else if ( pixel_clk = = 74170000 )
n = 11648 ;
else if ( pixel_clk = = 148350000 )
n = ( ratio = = 150 ) ? 11648 : 5824 ;
else
n = 6144 ;
break ;
case 88200 :
n = hdmi_compute_n ( 44100 , pixel_clk , ratio ) * 2 ;
break ;
case 96000 :
n = hdmi_compute_n ( 48000 , pixel_clk , ratio ) * 2 ;
break ;
case 176400 :
n = hdmi_compute_n ( 44100 , pixel_clk , ratio ) * 4 ;
break ;
case 192000 :
n = hdmi_compute_n ( 48000 , pixel_clk , ratio ) * 4 ;
break ;
default :
break ;
}
return n ;
}
static unsigned int hdmi_compute_cts ( unsigned int freq , unsigned long pixel_clk ,
unsigned int ratio )
{
unsigned int cts = 0 ;
pr_debug ( " %s: freq: %d pixel_clk: %ld ratio: %d \n " , __func__ , freq ,
pixel_clk , ratio ) ;
switch ( freq ) {
case 32000 :
if ( pixel_clk = = 297000000 ) {
cts = 222750 ;
break ;
}
case 48000 :
case 96000 :
case 192000 :
switch ( pixel_clk ) {
case 25200000 :
case 27000000 :
case 54000000 :
case 74250000 :
case 148500000 :
cts = pixel_clk / 1000 ;
break ;
case 297000000 :
cts = 247500 ;
break ;
/*
* All other TMDS clocks are not supported by
* DWC_hdmi_tx . The TMDS clocks divided or
* multiplied by 1 , 001 coefficients are not
* supported .
*/
default :
break ;
}
break ;
case 44100 :
case 88200 :
case 176400 :
switch ( pixel_clk ) {
case 25200000 :
cts = 28000 ;
break ;
case 27000000 :
cts = 30000 ;
break ;
case 54000000 :
cts = 60000 ;
break ;
case 74250000 :
cts = 82500 ;
break ;
case 148500000 :
cts = 165000 ;
break ;
case 297000000 :
cts = 247500 ;
break ;
default :
break ;
}
break ;
default :
break ;
}
if ( ratio = = 100 )
return cts ;
2014-09-24 14:27:36 -07:00
return ( cts * ratio ) / 100 ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static void hdmi_set_clk_regenerator ( struct dw_hdmi * hdmi ,
2015-03-27 12:53:29 +00:00
unsigned long pixel_clk , unsigned int sample_rate , unsigned int ratio )
2013-11-29 08:46:32 -02:00
{
2015-03-27 12:53:29 +00:00
unsigned int n , cts ;
n = hdmi_compute_n ( sample_rate , pixel_clk , ratio ) ;
cts = hdmi_compute_cts ( sample_rate , pixel_clk , ratio ) ;
if ( ! cts ) {
dev_err ( hdmi - > dev ,
" %s: pixel clock/sample rate not supported: %luMHz / %ukHz \n " ,
__func__ , pixel_clk , sample_rate ) ;
2013-11-29 08:46:32 -02:00
}
2015-03-27 12:53:29 +00:00
dev_dbg ( hdmi - > dev , " %s: samplerate=%ukHz ratio=%d pixelclk=%luMHz N=%d cts=%d \n " ,
__func__ , sample_rate , ratio , pixel_clk , n , cts ) ;
2013-11-29 08:46:32 -02:00
2015-03-27 12:59:58 +00:00
spin_lock_irq ( & hdmi - > audio_lock ) ;
hdmi - > audio_n = n ;
hdmi - > audio_cts = cts ;
hdmi_set_cts_n ( hdmi , cts , hdmi - > audio_enable ? n : 0 ) ;
spin_unlock_irq ( & hdmi - > audio_lock ) ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static void hdmi_init_clk_regenerator ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
2015-02-02 11:01:08 +00:00
mutex_lock ( & hdmi - > audio_mutex ) ;
2015-03-27 12:53:29 +00:00
hdmi_set_clk_regenerator ( hdmi , 74250000 , hdmi - > sample_rate ,
hdmi - > ratio ) ;
2015-02-02 11:01:08 +00:00
mutex_unlock ( & hdmi - > audio_mutex ) ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static void hdmi_clk_regenerator_update_pixel_clock ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
2015-02-02 11:01:08 +00:00
mutex_lock ( & hdmi - > audio_mutex ) ;
2015-03-27 12:53:29 +00:00
hdmi_set_clk_regenerator ( hdmi , hdmi - > hdmi_data . video_mode . mpixelclock ,
hdmi - > sample_rate , hdmi - > ratio ) ;
2015-02-02 11:01:08 +00:00
mutex_unlock ( & hdmi - > audio_mutex ) ;
2013-11-29 08:46:32 -02:00
}
2015-03-27 12:50:58 +00:00
void dw_hdmi_set_sample_rate ( struct dw_hdmi * hdmi , unsigned int rate )
{
mutex_lock ( & hdmi - > audio_mutex ) ;
hdmi - > sample_rate = rate ;
hdmi_set_clk_regenerator ( hdmi , hdmi - > hdmi_data . video_mode . mpixelclock ,
hdmi - > sample_rate , hdmi - > ratio ) ;
mutex_unlock ( & hdmi - > audio_mutex ) ;
}
EXPORT_SYMBOL_GPL ( dw_hdmi_set_sample_rate ) ;
2015-03-27 12:59:58 +00:00
void dw_hdmi_audio_enable ( struct dw_hdmi * hdmi )
{
unsigned long flags ;
spin_lock_irqsave ( & hdmi - > audio_lock , flags ) ;
hdmi - > audio_enable = true ;
hdmi_set_cts_n ( hdmi , hdmi - > audio_cts , hdmi - > audio_n ) ;
spin_unlock_irqrestore ( & hdmi - > audio_lock , flags ) ;
}
EXPORT_SYMBOL_GPL ( dw_hdmi_audio_enable ) ;
void dw_hdmi_audio_disable ( struct dw_hdmi * hdmi )
{
unsigned long flags ;
spin_lock_irqsave ( & hdmi - > audio_lock , flags ) ;
hdmi - > audio_enable = false ;
hdmi_set_cts_n ( hdmi , hdmi - > audio_cts , 0 ) ;
spin_unlock_irqrestore ( & hdmi - > audio_lock , flags ) ;
}
EXPORT_SYMBOL_GPL ( dw_hdmi_audio_disable ) ;
2013-11-29 08:46:32 -02:00
/*
* this submodule is responsible for the video data synchronization .
* for example , for RGB 4 : 4 : 4 input , the data map is defined as
* pin { 47 ~ 40 } < = = > R [ 7 : 0 ]
* pin { 31 ~ 24 } < = = > G [ 7 : 0 ]
* pin { 15 ~ 8 } < = = > B [ 7 : 0 ]
*/
2014-12-05 14:26:31 +08:00
static void hdmi_video_sample ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
int color_format = 0 ;
u8 val ;
if ( hdmi - > hdmi_data . enc_in_format = = RGB ) {
if ( hdmi - > hdmi_data . enc_color_depth = = 8 )
color_format = 0x01 ;
else if ( hdmi - > hdmi_data . enc_color_depth = = 10 )
color_format = 0x03 ;
else if ( hdmi - > hdmi_data . enc_color_depth = = 12 )
color_format = 0x05 ;
else if ( hdmi - > hdmi_data . enc_color_depth = = 16 )
color_format = 0x07 ;
else
return ;
} else if ( hdmi - > hdmi_data . enc_in_format = = YCBCR444 ) {
if ( hdmi - > hdmi_data . enc_color_depth = = 8 )
color_format = 0x09 ;
else if ( hdmi - > hdmi_data . enc_color_depth = = 10 )
color_format = 0x0B ;
else if ( hdmi - > hdmi_data . enc_color_depth = = 12 )
color_format = 0x0D ;
else if ( hdmi - > hdmi_data . enc_color_depth = = 16 )
color_format = 0x0F ;
else
return ;
} else if ( hdmi - > hdmi_data . enc_in_format = = YCBCR422_8BITS ) {
if ( hdmi - > hdmi_data . enc_color_depth = = 8 )
color_format = 0x16 ;
else if ( hdmi - > hdmi_data . enc_color_depth = = 10 )
color_format = 0x14 ;
else if ( hdmi - > hdmi_data . enc_color_depth = = 12 )
color_format = 0x12 ;
else
return ;
}
val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
( ( color_format < < HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET ) &
HDMI_TX_INVID0_VIDEO_MAPPING_MASK ) ;
hdmi_writeb ( hdmi , val , HDMI_TX_INVID0 ) ;
/* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE ;
hdmi_writeb ( hdmi , val , HDMI_TX_INSTUFFING ) ;
hdmi_writeb ( hdmi , 0x0 , HDMI_TX_GYDATA0 ) ;
hdmi_writeb ( hdmi , 0x0 , HDMI_TX_GYDATA1 ) ;
hdmi_writeb ( hdmi , 0x0 , HDMI_TX_RCRDATA0 ) ;
hdmi_writeb ( hdmi , 0x0 , HDMI_TX_RCRDATA1 ) ;
hdmi_writeb ( hdmi , 0x0 , HDMI_TX_BCBDATA0 ) ;
hdmi_writeb ( hdmi , 0x0 , HDMI_TX_BCBDATA1 ) ;
}
2014-12-05 14:26:31 +08:00
static int is_color_space_conversion ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
2014-02-06 10:12:03 -02:00
return hdmi - > hdmi_data . enc_in_format ! = hdmi - > hdmi_data . enc_out_format ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static int is_color_space_decimation ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
2014-02-06 10:12:03 -02:00
if ( hdmi - > hdmi_data . enc_out_format ! = YCBCR422_8BITS )
return 0 ;
if ( hdmi - > hdmi_data . enc_in_format = = RGB | |
hdmi - > hdmi_data . enc_in_format = = YCBCR444 )
return 1 ;
return 0 ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static int is_color_space_interpolation ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
2014-02-06 10:12:03 -02:00
if ( hdmi - > hdmi_data . enc_in_format ! = YCBCR422_8BITS )
return 0 ;
if ( hdmi - > hdmi_data . enc_out_format = = RGB | |
hdmi - > hdmi_data . enc_out_format = = YCBCR444 )
return 1 ;
return 0 ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_update_csc_coeffs ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
const u16 ( * csc_coeff ) [ 3 ] [ 4 ] = & csc_coeff_default ;
2013-11-04 12:10:40 +00:00
unsigned i ;
2013-11-29 08:46:32 -02:00
u32 csc_scale = 1 ;
if ( is_color_space_conversion ( hdmi ) ) {
if ( hdmi - > hdmi_data . enc_out_format = = RGB ) {
2014-03-09 20:11:07 +02:00
if ( hdmi - > hdmi_data . colorimetry = =
HDMI_COLORIMETRY_ITU_601 )
2013-11-29 08:46:32 -02:00
csc_coeff = & csc_coeff_rgb_out_eitu601 ;
else
csc_coeff = & csc_coeff_rgb_out_eitu709 ;
} else if ( hdmi - > hdmi_data . enc_in_format = = RGB ) {
2014-03-09 20:11:07 +02:00
if ( hdmi - > hdmi_data . colorimetry = =
HDMI_COLORIMETRY_ITU_601 )
2013-11-29 08:46:32 -02:00
csc_coeff = & csc_coeff_rgb_in_eitu601 ;
else
csc_coeff = & csc_coeff_rgb_in_eitu709 ;
csc_scale = 0 ;
}
}
2013-11-04 12:10:40 +00:00
/* The CSC registers are sequential, alternating MSB then LSB */
for ( i = 0 ; i < ARRAY_SIZE ( csc_coeff_default [ 0 ] ) ; i + + ) {
u16 coeff_a = ( * csc_coeff ) [ 0 ] [ i ] ;
u16 coeff_b = ( * csc_coeff ) [ 1 ] [ i ] ;
u16 coeff_c = ( * csc_coeff ) [ 2 ] [ i ] ;
2014-12-05 14:23:52 +08:00
hdmi_writeb ( hdmi , coeff_a & 0xff , HDMI_CSC_COEF_A1_LSB + i * 2 ) ;
2013-11-04 12:10:40 +00:00
hdmi_writeb ( hdmi , coeff_a > > 8 , HDMI_CSC_COEF_A1_MSB + i * 2 ) ;
hdmi_writeb ( hdmi , coeff_b & 0xff , HDMI_CSC_COEF_B1_LSB + i * 2 ) ;
hdmi_writeb ( hdmi , coeff_b > > 8 , HDMI_CSC_COEF_B1_MSB + i * 2 ) ;
2014-12-05 14:23:52 +08:00
hdmi_writeb ( hdmi , coeff_c & 0xff , HDMI_CSC_COEF_C1_LSB + i * 2 ) ;
2013-11-04 12:10:40 +00:00
hdmi_writeb ( hdmi , coeff_c > > 8 , HDMI_CSC_COEF_C1_MSB + i * 2 ) ;
}
2013-11-29 08:46:32 -02:00
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , csc_scale , HDMI_CSC_SCALE_CSCSCALE_MASK ,
HDMI_CSC_SCALE ) ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static void hdmi_video_csc ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
int color_depth = 0 ;
int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE ;
int decimation = 0 ;
/* YCC422 interpolation to 444 mode */
if ( is_color_space_interpolation ( hdmi ) )
interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1 ;
else if ( is_color_space_decimation ( hdmi ) )
decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3 ;
if ( hdmi - > hdmi_data . enc_color_depth = = 8 )
color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP ;
else if ( hdmi - > hdmi_data . enc_color_depth = = 10 )
color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP ;
else if ( hdmi - > hdmi_data . enc_color_depth = = 12 )
color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP ;
else if ( hdmi - > hdmi_data . enc_color_depth = = 16 )
color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP ;
else
return ;
/* Configure the CSC registers */
hdmi_writeb ( hdmi , interpolation | decimation , HDMI_CSC_CFG ) ;
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , color_depth , HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK ,
HDMI_CSC_SCALE ) ;
2013-11-29 08:46:32 -02:00
2014-12-05 14:26:31 +08:00
dw_hdmi_update_csc_coeffs ( hdmi ) ;
2013-11-29 08:46:32 -02:00
}
/*
* HDMI video packetizer is used to packetize the data .
* for example , if input is YCC422 mode or repeater is used ,
* data should be repacked this module can be bypassed .
*/
2014-12-05 14:26:31 +08:00
static void hdmi_video_packetize ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
unsigned int color_depth = 0 ;
unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit ;
unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP ;
struct hdmi_data_info * hdmi_data = & hdmi - > hdmi_data ;
2013-11-04 12:55:30 +00:00
u8 val , vp_conf ;
2013-11-29 08:46:32 -02:00
2014-12-05 14:23:52 +08:00
if ( hdmi_data - > enc_out_format = = RGB | |
hdmi_data - > enc_out_format = = YCBCR444 ) {
if ( ! hdmi_data - > enc_color_depth ) {
2013-11-29 08:46:32 -02:00
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS ;
2014-12-05 14:23:52 +08:00
} else if ( hdmi_data - > enc_color_depth = = 8 ) {
2013-11-29 08:46:32 -02:00
color_depth = 4 ;
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS ;
2014-12-05 14:23:52 +08:00
} else if ( hdmi_data - > enc_color_depth = = 10 ) {
2013-11-29 08:46:32 -02:00
color_depth = 5 ;
2014-12-05 14:23:52 +08:00
} else if ( hdmi_data - > enc_color_depth = = 12 ) {
2013-11-29 08:46:32 -02:00
color_depth = 6 ;
2014-12-05 14:23:52 +08:00
} else if ( hdmi_data - > enc_color_depth = = 16 ) {
2013-11-29 08:46:32 -02:00
color_depth = 7 ;
2014-12-05 14:23:52 +08:00
} else {
2013-11-29 08:46:32 -02:00
return ;
2014-12-05 14:23:52 +08:00
}
2013-11-29 08:46:32 -02:00
} else if ( hdmi_data - > enc_out_format = = YCBCR422_8BITS ) {
if ( ! hdmi_data - > enc_color_depth | |
hdmi_data - > enc_color_depth = = 8 )
remap_size = HDMI_VP_REMAP_YCC422_16bit ;
else if ( hdmi_data - > enc_color_depth = = 10 )
remap_size = HDMI_VP_REMAP_YCC422_20bit ;
else if ( hdmi_data - > enc_color_depth = = 12 )
remap_size = HDMI_VP_REMAP_YCC422_24bit ;
else
return ;
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422 ;
2014-12-05 14:23:52 +08:00
} else {
2013-11-29 08:46:32 -02:00
return ;
2014-12-05 14:23:52 +08:00
}
2013-11-29 08:46:32 -02:00
/* set the packetizer registers */
val = ( ( color_depth < < HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET ) &
HDMI_VP_PR_CD_COLOR_DEPTH_MASK ) |
( ( hdmi_data - > pix_repet_factor < <
HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET ) &
HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK ) ;
hdmi_writeb ( hdmi , val , HDMI_VP_PR_CD ) ;
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE ,
HDMI_VP_STUFF_PR_STUFFING_MASK , HDMI_VP_STUFF ) ;
2013-11-29 08:46:32 -02:00
/* Data from pixel repeater block */
if ( hdmi_data - > pix_repet_factor > 1 ) {
2013-11-04 12:55:30 +00:00
vp_conf = HDMI_VP_CONF_PR_EN_ENABLE |
HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER ;
2013-11-29 08:46:32 -02:00
} else { /* data from packetizer block */
2013-11-04 12:55:30 +00:00
vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER ;
2013-11-29 08:46:32 -02:00
}
2013-11-04 12:55:30 +00:00
hdmi_modb ( hdmi , vp_conf ,
HDMI_VP_CONF_PR_EN_MASK |
HDMI_VP_CONF_BYPASS_SELECT_MASK , HDMI_VP_CONF ) ;
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , 1 < < HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET ,
HDMI_VP_STUFF_IDEFAULT_PHASE_MASK , HDMI_VP_STUFF ) ;
2013-11-29 08:46:32 -02:00
hdmi_writeb ( hdmi , remap_size , HDMI_VP_REMAP ) ;
if ( output_select = = HDMI_VP_CONF_OUTPUT_SELECTOR_PP ) {
2013-11-04 12:55:30 +00:00
vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
HDMI_VP_CONF_PP_EN_ENABLE |
HDMI_VP_CONF_YCC422_EN_DISABLE ;
2013-11-29 08:46:32 -02:00
} else if ( output_select = = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422 ) {
2013-11-04 12:55:30 +00:00
vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
HDMI_VP_CONF_PP_EN_DISABLE |
HDMI_VP_CONF_YCC422_EN_ENABLE ;
2013-11-29 08:46:32 -02:00
} else if ( output_select = = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS ) {
2013-11-04 12:55:30 +00:00
vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
HDMI_VP_CONF_PP_EN_DISABLE |
HDMI_VP_CONF_YCC422_EN_DISABLE ;
2013-11-29 08:46:32 -02:00
} else {
return ;
}
2013-11-04 12:55:30 +00:00
hdmi_modb ( hdmi , vp_conf ,
HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK |
HDMI_VP_CONF_YCC422_EN_MASK , HDMI_VP_CONF ) ;
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE ,
HDMI_VP_STUFF_PP_STUFFING_MASK |
HDMI_VP_STUFF_YCC422_STUFFING_MASK , HDMI_VP_STUFF ) ;
2013-11-29 08:46:32 -02:00
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , output_select , HDMI_VP_CONF_OUTPUT_SELECTOR_MASK ,
HDMI_VP_CONF ) ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static inline void hdmi_phy_test_clear ( struct dw_hdmi * hdmi ,
2014-12-05 14:23:52 +08:00
unsigned char bit )
2013-11-29 08:46:32 -02:00
{
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , bit < < HDMI_PHY_TST0_TSTCLR_OFFSET ,
HDMI_PHY_TST0_TSTCLR_MASK , HDMI_PHY_TST0 ) ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static inline void hdmi_phy_test_enable ( struct dw_hdmi * hdmi ,
2014-12-05 14:23:52 +08:00
unsigned char bit )
2013-11-29 08:46:32 -02:00
{
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , bit < < HDMI_PHY_TST0_TSTEN_OFFSET ,
HDMI_PHY_TST0_TSTEN_MASK , HDMI_PHY_TST0 ) ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static inline void hdmi_phy_test_clock ( struct dw_hdmi * hdmi ,
2014-12-05 14:23:52 +08:00
unsigned char bit )
2013-11-29 08:46:32 -02:00
{
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , bit < < HDMI_PHY_TST0_TSTCLK_OFFSET ,
HDMI_PHY_TST0_TSTCLK_MASK , HDMI_PHY_TST0 ) ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static inline void hdmi_phy_test_din ( struct dw_hdmi * hdmi ,
2014-12-05 14:23:52 +08:00
unsigned char bit )
2013-11-29 08:46:32 -02:00
{
hdmi_writeb ( hdmi , bit , HDMI_PHY_TST1 ) ;
}
2014-12-05 14:26:31 +08:00
static inline void hdmi_phy_test_dout ( struct dw_hdmi * hdmi ,
2014-12-05 14:23:52 +08:00
unsigned char bit )
2013-11-29 08:46:32 -02:00
{
hdmi_writeb ( hdmi , bit , HDMI_PHY_TST2 ) ;
}
2014-12-05 14:26:31 +08:00
static bool hdmi_phy_wait_i2c_done ( struct dw_hdmi * hdmi , int msec )
2013-11-29 08:46:32 -02:00
{
2014-12-05 14:31:09 +08:00
u32 val ;
while ( ( val = hdmi_readb ( hdmi , HDMI_IH_I2CMPHY_STAT0 ) & 0x3 ) = = 0 ) {
2013-11-29 08:46:32 -02:00
if ( msec - - = = 0 )
return false ;
2014-03-30 00:21:21 +01:00
udelay ( 1000 ) ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:31:09 +08:00
hdmi_writeb ( hdmi , val , HDMI_IH_I2CMPHY_STAT0 ) ;
2013-11-29 08:46:32 -02:00
return true ;
}
2014-12-05 14:26:31 +08:00
static void __hdmi_phy_i2c_write ( struct dw_hdmi * hdmi , unsigned short data ,
2014-12-05 14:23:52 +08:00
unsigned char addr )
2013-11-29 08:46:32 -02:00
{
hdmi_writeb ( hdmi , 0xFF , HDMI_IH_I2CMPHY_STAT0 ) ;
hdmi_writeb ( hdmi , addr , HDMI_PHY_I2CM_ADDRESS_ADDR ) ;
hdmi_writeb ( hdmi , ( unsigned char ) ( data > > 8 ) ,
2014-12-05 14:23:52 +08:00
HDMI_PHY_I2CM_DATAO_1_ADDR ) ;
2013-11-29 08:46:32 -02:00
hdmi_writeb ( hdmi , ( unsigned char ) ( data > > 0 ) ,
2014-12-05 14:23:52 +08:00
HDMI_PHY_I2CM_DATAO_0_ADDR ) ;
2013-11-29 08:46:32 -02:00
hdmi_writeb ( hdmi , HDMI_PHY_I2CM_OPERATION_ADDR_WRITE ,
2014-12-05 14:23:52 +08:00
HDMI_PHY_I2CM_OPERATION_ADDR ) ;
2013-11-29 08:46:32 -02:00
hdmi_phy_wait_i2c_done ( hdmi , 1000 ) ;
}
2014-12-05 14:26:31 +08:00
static int hdmi_phy_i2c_write ( struct dw_hdmi * hdmi , unsigned short data ,
2014-12-05 14:23:52 +08:00
unsigned char addr )
2013-11-29 08:46:32 -02:00
{
__hdmi_phy_i2c_write ( hdmi , data , addr ) ;
return 0 ;
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_phy_enable_power ( struct dw_hdmi * hdmi , u8 enable )
2013-11-29 08:46:32 -02:00
{
hdmi_mask_writeb ( hdmi , enable , HDMI_PHY_CONF0 ,
HDMI_PHY_CONF0_PDZ_OFFSET ,
HDMI_PHY_CONF0_PDZ_MASK ) ;
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_phy_enable_tmds ( struct dw_hdmi * hdmi , u8 enable )
2013-11-29 08:46:32 -02:00
{
hdmi_mask_writeb ( hdmi , enable , HDMI_PHY_CONF0 ,
HDMI_PHY_CONF0_ENTMDS_OFFSET ,
HDMI_PHY_CONF0_ENTMDS_MASK ) ;
}
2014-12-05 14:31:53 +08:00
static void dw_hdmi_phy_enable_spare ( struct dw_hdmi * hdmi , u8 enable )
{
hdmi_mask_writeb ( hdmi , enable , HDMI_PHY_CONF0 ,
HDMI_PHY_CONF0_SPARECTRL_OFFSET ,
HDMI_PHY_CONF0_SPARECTRL_MASK ) ;
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_phy_gen2_pddq ( struct dw_hdmi * hdmi , u8 enable )
2013-11-29 08:46:32 -02:00
{
hdmi_mask_writeb ( hdmi , enable , HDMI_PHY_CONF0 ,
HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET ,
HDMI_PHY_CONF0_GEN2_PDDQ_MASK ) ;
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_phy_gen2_txpwron ( struct dw_hdmi * hdmi , u8 enable )
2013-11-29 08:46:32 -02:00
{
hdmi_mask_writeb ( hdmi , enable , HDMI_PHY_CONF0 ,
HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET ,
HDMI_PHY_CONF0_GEN2_TXPWRON_MASK ) ;
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_phy_sel_data_en_pol ( struct dw_hdmi * hdmi , u8 enable )
2013-11-29 08:46:32 -02:00
{
hdmi_mask_writeb ( hdmi , enable , HDMI_PHY_CONF0 ,
HDMI_PHY_CONF0_SELDATAENPOL_OFFSET ,
HDMI_PHY_CONF0_SELDATAENPOL_MASK ) ;
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_phy_sel_interface_control ( struct dw_hdmi * hdmi , u8 enable )
2013-11-29 08:46:32 -02:00
{
hdmi_mask_writeb ( hdmi , enable , HDMI_PHY_CONF0 ,
HDMI_PHY_CONF0_SELDIPIF_OFFSET ,
HDMI_PHY_CONF0_SELDIPIF_MASK ) ;
}
2014-12-05 14:26:31 +08:00
static int hdmi_phy_configure ( struct dw_hdmi * hdmi , unsigned char prep ,
2013-11-29 08:46:32 -02:00
unsigned char res , int cscon )
{
2015-03-31 18:34:11 +01:00
unsigned res_idx ;
2013-11-29 08:46:32 -02:00
u8 val , msec ;
2015-03-31 18:34:11 +01:00
const struct dw_hdmi_plat_data * pdata = hdmi - > plat_data ;
const struct dw_hdmi_mpll_config * mpll_config = pdata - > mpll_cfg ;
const struct dw_hdmi_curr_ctrl * curr_ctrl = pdata - > cur_ctr ;
const struct dw_hdmi_phy_config * phy_config = pdata - > phy_config ;
2013-11-29 08:46:32 -02:00
if ( prep )
return - EINVAL ;
2013-11-04 11:24:00 +00:00
switch ( res ) {
case 0 : /* color resolution 0 is 8 bit colour depth */
case 8 :
2014-12-05 14:26:31 +08:00
res_idx = DW_HDMI_RES_8 ;
2013-11-04 11:24:00 +00:00
break ;
case 10 :
2014-12-05 14:26:31 +08:00
res_idx = DW_HDMI_RES_10 ;
2013-11-04 11:24:00 +00:00
break ;
case 12 :
2014-12-05 14:26:31 +08:00
res_idx = DW_HDMI_RES_12 ;
2013-11-04 11:24:00 +00:00
break ;
default :
2013-11-29 08:46:32 -02:00
return - EINVAL ;
2013-11-04 11:24:00 +00:00
}
2013-11-29 08:46:32 -02:00
2015-03-31 18:34:11 +01:00
/* PLL/MPLL Cfg - always match on final entry */
for ( ; mpll_config - > mpixelclock ! = ~ 0UL ; mpll_config + + )
if ( hdmi - > hdmi_data . video_mode . mpixelclock < =
mpll_config - > mpixelclock )
break ;
for ( ; curr_ctrl - > mpixelclock ! = ~ 0UL ; curr_ctrl + + )
if ( hdmi - > hdmi_data . video_mode . mpixelclock < =
curr_ctrl - > mpixelclock )
break ;
for ( ; phy_config - > mpixelclock ! = ~ 0UL ; phy_config + + )
if ( hdmi - > hdmi_data . video_mode . mpixelclock < =
phy_config - > mpixelclock )
break ;
if ( mpll_config - > mpixelclock = = ~ 0UL | |
curr_ctrl - > mpixelclock = = ~ 0UL | |
phy_config - > mpixelclock = = ~ 0UL ) {
dev_err ( hdmi - > dev , " Pixel clock %d - unsupported by HDMI \n " ,
hdmi - > hdmi_data . video_mode . mpixelclock ) ;
return - EINVAL ;
}
2013-11-29 08:46:32 -02:00
/* Enable csc path */
if ( cscon )
val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH ;
else
val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS ;
hdmi_writeb ( hdmi , val , HDMI_MC_FLOWCTRL ) ;
/* gen2 tx power off */
2014-12-05 14:26:31 +08:00
dw_hdmi_phy_gen2_txpwron ( hdmi , 0 ) ;
2013-11-29 08:46:32 -02:00
/* gen2 pddq */
2014-12-05 14:26:31 +08:00
dw_hdmi_phy_gen2_pddq ( hdmi , 1 ) ;
2013-11-29 08:46:32 -02:00
/* PHY reset */
hdmi_writeb ( hdmi , HDMI_MC_PHYRSTZ_DEASSERT , HDMI_MC_PHYRSTZ ) ;
hdmi_writeb ( hdmi , HDMI_MC_PHYRSTZ_ASSERT , HDMI_MC_PHYRSTZ ) ;
hdmi_writeb ( hdmi , HDMI_MC_HEACPHY_RST_ASSERT , HDMI_MC_HEACPHY_RST ) ;
hdmi_phy_test_clear ( hdmi , 1 ) ;
hdmi_writeb ( hdmi , HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2 ,
2014-12-05 14:23:52 +08:00
HDMI_PHY_I2CM_SLAVE_ADDR ) ;
2013-11-29 08:46:32 -02:00
hdmi_phy_test_clear ( hdmi , 0 ) ;
2015-03-31 18:34:11 +01:00
hdmi_phy_i2c_write ( hdmi , mpll_config - > res [ res_idx ] . cpce , 0x06 ) ;
hdmi_phy_i2c_write ( hdmi , mpll_config - > res [ res_idx ] . gmp , 0x15 ) ;
2013-11-29 08:46:32 -02:00
2013-11-04 11:24:00 +00:00
/* CURRCTRL */
2015-03-31 18:34:11 +01:00
hdmi_phy_i2c_write ( hdmi , curr_ctrl - > curr [ res_idx ] , 0x10 ) ;
2013-11-04 11:24:00 +00:00
2013-11-29 08:46:32 -02:00
hdmi_phy_i2c_write ( hdmi , 0x0000 , 0x13 ) ; /* PLLPHBYCTRL */
hdmi_phy_i2c_write ( hdmi , 0x0006 , 0x17 ) ;
2014-12-05 14:25:50 +08:00
2015-03-31 18:34:11 +01:00
hdmi_phy_i2c_write ( hdmi , phy_config - > term , 0x19 ) ; /* TXTERM */
hdmi_phy_i2c_write ( hdmi , phy_config - > sym_ctr , 0x09 ) ; /* CKSYMTXCTRL */
hdmi_phy_i2c_write ( hdmi , phy_config - > vlev_ctr , 0x0E ) ; /* VLEVCTRL */
2015-03-31 23:56:10 -04:00
2013-11-29 08:46:32 -02:00
/* REMOVE CLK TERM */
hdmi_phy_i2c_write ( hdmi , 0x8000 , 0x05 ) ; /* CKCALCTRL */
2014-12-05 14:26:31 +08:00
dw_hdmi_phy_enable_power ( hdmi , 1 ) ;
2013-11-29 08:46:32 -02:00
/* toggle TMDS enable */
2014-12-05 14:26:31 +08:00
dw_hdmi_phy_enable_tmds ( hdmi , 0 ) ;
dw_hdmi_phy_enable_tmds ( hdmi , 1 ) ;
2013-11-29 08:46:32 -02:00
/* gen2 tx power on */
2014-12-05 14:26:31 +08:00
dw_hdmi_phy_gen2_txpwron ( hdmi , 1 ) ;
dw_hdmi_phy_gen2_pddq ( hdmi , 0 ) ;
2013-11-29 08:46:32 -02:00
2015-01-07 15:48:27 +08:00
if ( hdmi - > dev_type = = RK3288_HDMI )
dw_hdmi_phy_enable_spare ( hdmi , 1 ) ;
2013-11-29 08:46:32 -02:00
/*Wait for PHY PLL lock */
msec = 5 ;
do {
val = hdmi_readb ( hdmi , HDMI_PHY_STAT0 ) & HDMI_PHY_TX_PHY_LOCK ;
if ( ! val )
break ;
if ( msec = = 0 ) {
dev_err ( hdmi - > dev , " PHY PLL not locked \n " ) ;
return - ETIMEDOUT ;
}
udelay ( 1000 ) ;
msec - - ;
} while ( 1 ) ;
return 0 ;
}
2014-12-05 14:26:31 +08:00
static int dw_hdmi_phy_init ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
int i , ret ;
2015-07-21 15:35:52 +01:00
bool cscon ;
2013-11-29 08:46:32 -02:00
/*check csc whether needed activated in HDMI mode */
2015-07-21 15:35:52 +01:00
cscon = hdmi - > sink_is_hdmi & & is_color_space_conversion ( hdmi ) ;
2013-11-29 08:46:32 -02:00
/* HDMI Phy spec says to do the phy initialization sequence twice */
for ( i = 0 ; i < 2 ; i + + ) {
2014-12-05 14:26:31 +08:00
dw_hdmi_phy_sel_data_en_pol ( hdmi , 1 ) ;
dw_hdmi_phy_sel_interface_control ( hdmi , 0 ) ;
dw_hdmi_phy_enable_tmds ( hdmi , 0 ) ;
dw_hdmi_phy_enable_power ( hdmi , 0 ) ;
2013-11-29 08:46:32 -02:00
/* Enable CSC */
ret = hdmi_phy_configure ( hdmi , 0 , 8 , cscon ) ;
if ( ret )
return ret ;
}
hdmi - > phy_enabled = true ;
return 0 ;
}
2014-12-05 14:26:31 +08:00
static void hdmi_tx_hdcp_config ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
2013-11-04 12:42:02 +00:00
u8 de ;
2013-11-29 08:46:32 -02:00
if ( hdmi - > hdmi_data . video_mode . mdataenablepolarity )
de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH ;
else
de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW ;
/* disable rx detect */
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , HDMI_A_HDCPCFG0_RXDETECT_DISABLE ,
HDMI_A_HDCPCFG0_RXDETECT_MASK , HDMI_A_HDCPCFG0 ) ;
2013-11-29 08:46:32 -02:00
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , de , HDMI_A_VIDPOLCFG_DATAENPOL_MASK , HDMI_A_VIDPOLCFG ) ;
2013-11-29 08:46:32 -02:00
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE ,
HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK , HDMI_A_HDCPCFG1 ) ;
2013-11-29 08:46:32 -02:00
}
2015-03-27 20:06:50 +00:00
static void hdmi_config_AVI ( struct dw_hdmi * hdmi , struct drm_display_mode * mode )
2013-11-29 08:46:32 -02:00
{
2015-03-27 20:06:50 +00:00
struct hdmi_avi_infoframe frame ;
u8 val ;
2013-11-29 08:46:32 -02:00
2015-03-27 20:06:50 +00:00
/* Initialise info frame from DRM mode */
drm_hdmi_avi_infoframe_from_display_mode ( & frame , mode ) ;
2013-11-29 08:46:32 -02:00
if ( hdmi - > hdmi_data . enc_out_format = = YCBCR444 )
2015-03-27 20:06:50 +00:00
frame . colorspace = HDMI_COLORSPACE_YUV444 ;
2013-11-29 08:46:32 -02:00
else if ( hdmi - > hdmi_data . enc_out_format = = YCBCR422_8BITS )
2015-03-27 20:06:50 +00:00
frame . colorspace = HDMI_COLORSPACE_YUV422 ;
2013-11-29 08:46:32 -02:00
else
2015-03-27 20:06:50 +00:00
frame . colorspace = HDMI_COLORSPACE_RGB ;
2013-11-29 08:46:32 -02:00
/* Set up colorimetry */
if ( hdmi - > hdmi_data . enc_out_format = = XVYCC444 ) {
2015-03-27 20:06:50 +00:00
frame . colorimetry = HDMI_COLORIMETRY_EXTENDED ;
2014-01-28 10:33:16 +05:30
if ( hdmi - > hdmi_data . colorimetry = = HDMI_COLORIMETRY_ITU_601 )
2015-03-27 20:06:50 +00:00
frame . extended_colorimetry =
HDMI_EXTENDED_COLORIMETRY_XV_YCC_601 ;
2014-01-28 10:33:16 +05:30
else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
2015-03-27 20:06:50 +00:00
frame . extended_colorimetry =
HDMI_EXTENDED_COLORIMETRY_XV_YCC_709 ;
2013-11-29 08:46:32 -02:00
} else if ( hdmi - > hdmi_data . enc_out_format ! = RGB ) {
2015-03-27 23:14:16 +00:00
frame . colorimetry = hdmi - > hdmi_data . colorimetry ;
2015-03-27 20:06:50 +00:00
frame . extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601 ;
2013-11-29 08:46:32 -02:00
} else { /* Carries no data */
2015-03-27 20:06:50 +00:00
frame . colorimetry = HDMI_COLORIMETRY_NONE ;
frame . extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601 ;
2013-11-29 08:46:32 -02:00
}
2015-03-27 20:06:50 +00:00
frame . scan_mode = HDMI_SCAN_MODE_NONE ;
/*
* The Designware IP uses a different byte format from standard
* AVI info frames , though generally the bits are in the correct
* bytes .
*/
/*
* AVI data byte 1 differences : Colorspace in bits 4 , 5 rather than 5 , 6 ,
* active aspect present in bit 6 rather than 4.
*/
val = ( frame . colorspace & 3 ) < < 4 | ( frame . scan_mode & 0x3 ) ;
if ( frame . active_aspect & 15 )
val | = HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT ;
if ( frame . top_bar | | frame . bottom_bar )
val | = HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR ;
if ( frame . left_bar | | frame . right_bar )
val | = HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR ;
hdmi_writeb ( hdmi , val , HDMI_FC_AVICONF0 ) ;
/* AVI data byte 2 differences: none */
val = ( ( frame . colorimetry & 0x3 ) < < 6 ) |
( ( frame . picture_aspect & 0x3 ) < < 4 ) |
( frame . active_aspect & 0xf ) ;
2013-11-29 08:46:32 -02:00
hdmi_writeb ( hdmi , val , HDMI_FC_AVICONF1 ) ;
2015-03-27 20:06:50 +00:00
/* AVI data byte 3 differences: none */
val = ( ( frame . extended_colorimetry & 0x7 ) < < 4 ) |
( ( frame . quantization_range & 0x3 ) < < 2 ) |
( frame . nups & 0x3 ) ;
if ( frame . itc )
val | = HDMI_FC_AVICONF2_IT_CONTENT_VALID ;
2013-11-29 08:46:32 -02:00
hdmi_writeb ( hdmi , val , HDMI_FC_AVICONF2 ) ;
2015-03-27 20:06:50 +00:00
/* AVI data byte 4 differences: none */
val = frame . video_code & 0x7f ;
hdmi_writeb ( hdmi , val , HDMI_FC_AVIVID ) ;
2013-11-29 08:46:32 -02:00
/* AVI Data Byte 5- set up input and output pixel repetition */
val = ( ( ( hdmi - > hdmi_data . video_mode . mpixelrepetitioninput + 1 ) < <
HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET ) &
HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK ) |
( ( hdmi - > hdmi_data . video_mode . mpixelrepetitionoutput < <
HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET ) &
HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK ) ;
hdmi_writeb ( hdmi , val , HDMI_FC_PRCONF ) ;
2015-03-27 20:06:50 +00:00
/*
* AVI data byte 5 differences : content type in 0 , 1 rather than 4 , 5 ,
* ycc range in bits 2 , 3 rather than 6 , 7
*/
val = ( ( frame . ycc_quantization_range & 0x3 ) < < 2 ) |
( frame . content_type & 0x3 ) ;
2013-11-29 08:46:32 -02:00
hdmi_writeb ( hdmi , val , HDMI_FC_AVICONF3 ) ;
/* AVI Data Bytes 6-13 */
2015-03-27 20:06:50 +00:00
hdmi_writeb ( hdmi , frame . top_bar & 0xff , HDMI_FC_AVIETB0 ) ;
hdmi_writeb ( hdmi , ( frame . top_bar > > 8 ) & 0xff , HDMI_FC_AVIETB1 ) ;
hdmi_writeb ( hdmi , frame . bottom_bar & 0xff , HDMI_FC_AVISBB0 ) ;
hdmi_writeb ( hdmi , ( frame . bottom_bar > > 8 ) & 0xff , HDMI_FC_AVISBB1 ) ;
hdmi_writeb ( hdmi , frame . left_bar & 0xff , HDMI_FC_AVIELB0 ) ;
hdmi_writeb ( hdmi , ( frame . left_bar > > 8 ) & 0xff , HDMI_FC_AVIELB1 ) ;
hdmi_writeb ( hdmi , frame . right_bar & 0xff , HDMI_FC_AVISRB0 ) ;
hdmi_writeb ( hdmi , ( frame . right_bar > > 8 ) & 0xff , HDMI_FC_AVISRB1 ) ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static void hdmi_av_composer ( struct dw_hdmi * hdmi ,
2013-11-29 08:46:32 -02:00
const struct drm_display_mode * mode )
{
u8 inv_val ;
struct hdmi_vmode * vmode = & hdmi - > hdmi_data . video_mode ;
int hblank , vblank , h_de_hs , v_de_vs , hsync_len , vsync_len ;
vmode - > mpixelclock = mode - > clock * 1000 ;
dev_dbg ( hdmi - > dev , " final pixclk = %d \n " , vmode - > mpixelclock ) ;
/* Set up HDMI_FC_INVIDCONF */
inv_val = ( hdmi - > hdmi_data . hdcp_enable ?
HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE ) ;
2015-03-27 23:27:17 +00:00
inv_val | = mode - > flags & DRM_MODE_FLAG_PVSYNC ?
2013-11-29 08:46:32 -02:00
HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
2015-03-27 23:27:17 +00:00
HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW ;
2013-11-29 08:46:32 -02:00
2015-03-27 23:27:17 +00:00
inv_val | = mode - > flags & DRM_MODE_FLAG_PHSYNC ?
2013-11-29 08:46:32 -02:00
HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
2015-03-27 23:27:17 +00:00
HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW ;
2013-11-29 08:46:32 -02:00
inv_val | = ( vmode - > mdataenablepolarity ?
HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW ) ;
if ( hdmi - > vic = = 39 )
inv_val | = HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH ;
else
2015-03-27 23:27:17 +00:00
inv_val | = mode - > flags & DRM_MODE_FLAG_INTERLACE ?
2013-11-29 08:46:32 -02:00
HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
2015-03-27 23:27:17 +00:00
HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW ;
2013-11-29 08:46:32 -02:00
2015-03-27 23:27:17 +00:00
inv_val | = mode - > flags & DRM_MODE_FLAG_INTERLACE ?
2013-11-29 08:46:32 -02:00
HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
2015-03-27 23:27:17 +00:00
HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE ;
2013-11-29 08:46:32 -02:00
2015-07-21 15:35:52 +01:00
inv_val | = hdmi - > sink_is_hdmi ?
HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE :
HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE ;
2013-11-29 08:46:32 -02:00
hdmi_writeb ( hdmi , inv_val , HDMI_FC_INVIDCONF ) ;
/* Set up horizontal active pixel width */
hdmi_writeb ( hdmi , mode - > hdisplay > > 8 , HDMI_FC_INHACTV1 ) ;
hdmi_writeb ( hdmi , mode - > hdisplay , HDMI_FC_INHACTV0 ) ;
/* Set up vertical active lines */
hdmi_writeb ( hdmi , mode - > vdisplay > > 8 , HDMI_FC_INVACTV1 ) ;
hdmi_writeb ( hdmi , mode - > vdisplay , HDMI_FC_INVACTV0 ) ;
/* Set up horizontal blanking pixel region width */
hblank = mode - > htotal - mode - > hdisplay ;
hdmi_writeb ( hdmi , hblank > > 8 , HDMI_FC_INHBLANK1 ) ;
hdmi_writeb ( hdmi , hblank , HDMI_FC_INHBLANK0 ) ;
/* Set up vertical blanking pixel region width */
vblank = mode - > vtotal - mode - > vdisplay ;
hdmi_writeb ( hdmi , vblank , HDMI_FC_INVBLANK ) ;
/* Set up HSYNC active edge delay width (in pixel clks) */
h_de_hs = mode - > hsync_start - mode - > hdisplay ;
hdmi_writeb ( hdmi , h_de_hs > > 8 , HDMI_FC_HSYNCINDELAY1 ) ;
hdmi_writeb ( hdmi , h_de_hs , HDMI_FC_HSYNCINDELAY0 ) ;
/* Set up VSYNC active edge delay (in lines) */
v_de_vs = mode - > vsync_start - mode - > vdisplay ;
hdmi_writeb ( hdmi , v_de_vs , HDMI_FC_VSYNCINDELAY ) ;
/* Set up HSYNC active pulse width (in pixel clks) */
hsync_len = mode - > hsync_end - mode - > hsync_start ;
hdmi_writeb ( hdmi , hsync_len > > 8 , HDMI_FC_HSYNCINWIDTH1 ) ;
hdmi_writeb ( hdmi , hsync_len , HDMI_FC_HSYNCINWIDTH0 ) ;
/* Set up VSYNC active edge delay (in lines) */
vsync_len = mode - > vsync_end - mode - > vsync_start ;
hdmi_writeb ( hdmi , vsync_len , HDMI_FC_VSYNCINWIDTH ) ;
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_phy_disable ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
if ( ! hdmi - > phy_enabled )
return ;
2014-12-05 14:26:31 +08:00
dw_hdmi_phy_enable_tmds ( hdmi , 0 ) ;
dw_hdmi_phy_enable_power ( hdmi , 0 ) ;
2013-11-29 08:46:32 -02:00
hdmi - > phy_enabled = false ;
}
/* HDMI Initialization Step B.4 */
2014-12-05 14:26:31 +08:00
static void dw_hdmi_enable_video_path ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
u8 clkdis ;
/* control period minimum duration */
hdmi_writeb ( hdmi , 12 , HDMI_FC_CTRLDUR ) ;
hdmi_writeb ( hdmi , 32 , HDMI_FC_EXCTRLDUR ) ;
hdmi_writeb ( hdmi , 1 , HDMI_FC_EXCTRLSPAC ) ;
/* Set to fill TMDS data channels */
hdmi_writeb ( hdmi , 0x0B , HDMI_FC_CH0PREAM ) ;
hdmi_writeb ( hdmi , 0x16 , HDMI_FC_CH1PREAM ) ;
hdmi_writeb ( hdmi , 0x21 , HDMI_FC_CH2PREAM ) ;
/* Enable pixel clock and tmds data path */
clkdis = 0x7F ;
clkdis & = ~ HDMI_MC_CLKDIS_PIXELCLK_DISABLE ;
hdmi_writeb ( hdmi , clkdis , HDMI_MC_CLKDIS ) ;
clkdis & = ~ HDMI_MC_CLKDIS_TMDSCLK_DISABLE ;
hdmi_writeb ( hdmi , clkdis , HDMI_MC_CLKDIS ) ;
/* Enable csc path */
if ( is_color_space_conversion ( hdmi ) ) {
clkdis & = ~ HDMI_MC_CLKDIS_CSCCLK_DISABLE ;
hdmi_writeb ( hdmi , clkdis , HDMI_MC_CLKDIS ) ;
}
}
2014-12-05 14:26:31 +08:00
static void hdmi_enable_audio_clk ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , 0 , HDMI_MC_CLKDIS_AUDCLK_DISABLE , HDMI_MC_CLKDIS ) ;
2013-11-29 08:46:32 -02:00
}
/* Workaround to clear the overflow condition */
2014-12-05 14:26:31 +08:00
static void dw_hdmi_clear_overflow ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
int count ;
u8 val ;
/* TMDS software reset */
hdmi_writeb ( hdmi , ( u8 ) ~ HDMI_MC_SWRSTZ_TMDSSWRST_REQ , HDMI_MC_SWRSTZ ) ;
val = hdmi_readb ( hdmi , HDMI_FC_INVIDCONF ) ;
if ( hdmi - > dev_type = = IMX6DL_HDMI ) {
hdmi_writeb ( hdmi , val , HDMI_FC_INVIDCONF ) ;
return ;
}
for ( count = 0 ; count < 4 ; count + + )
hdmi_writeb ( hdmi , val , HDMI_FC_INVIDCONF ) ;
}
2014-12-05 14:26:31 +08:00
static void hdmi_enable_overflow_interrupts ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
hdmi_writeb ( hdmi , 0 , HDMI_FC_MASK2 ) ;
hdmi_writeb ( hdmi , 0 , HDMI_IH_MUTE_FC_STAT2 ) ;
}
2014-12-05 14:26:31 +08:00
static void hdmi_disable_overflow_interrupts ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
hdmi_writeb ( hdmi , HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK ,
HDMI_IH_MUTE_FC_STAT2 ) ;
}
2014-12-05 14:26:31 +08:00
static int dw_hdmi_setup ( struct dw_hdmi * hdmi , struct drm_display_mode * mode )
2013-11-29 08:46:32 -02:00
{
int ret ;
hdmi_disable_overflow_interrupts ( hdmi ) ;
hdmi - > vic = drm_match_cea_mode ( mode ) ;
if ( ! hdmi - > vic ) {
dev_dbg ( hdmi - > dev , " Non-CEA mode used in HDMI \n " ) ;
} else {
dev_dbg ( hdmi - > dev , " CEA mode used vic=%d \n " , hdmi - > vic ) ;
}
if ( ( hdmi - > vic = = 6 ) | | ( hdmi - > vic = = 7 ) | |
2014-12-05 14:23:52 +08:00
( hdmi - > vic = = 21 ) | | ( hdmi - > vic = = 22 ) | |
( hdmi - > vic = = 2 ) | | ( hdmi - > vic = = 3 ) | |
( hdmi - > vic = = 17 ) | | ( hdmi - > vic = = 18 ) )
2014-01-28 10:33:16 +05:30
hdmi - > hdmi_data . colorimetry = HDMI_COLORIMETRY_ITU_601 ;
2013-11-29 08:46:32 -02:00
else
2014-01-28 10:33:16 +05:30
hdmi - > hdmi_data . colorimetry = HDMI_COLORIMETRY_ITU_709 ;
2013-11-29 08:46:32 -02:00
2015-07-21 11:25:00 +01:00
hdmi - > hdmi_data . video_mode . mpixelrepetitionoutput = 0 ;
2013-11-29 08:46:32 -02:00
hdmi - > hdmi_data . video_mode . mpixelrepetitioninput = 0 ;
/* TODO: Get input format from IPU (via FB driver interface) */
hdmi - > hdmi_data . enc_in_format = RGB ;
hdmi - > hdmi_data . enc_out_format = RGB ;
hdmi - > hdmi_data . enc_color_depth = 8 ;
hdmi - > hdmi_data . pix_repet_factor = 0 ;
hdmi - > hdmi_data . hdcp_enable = 0 ;
hdmi - > hdmi_data . video_mode . mdataenablepolarity = true ;
/* HDMI Initialization Step B.1 */
hdmi_av_composer ( hdmi , mode ) ;
/* HDMI Initializateion Step B.2 */
2014-12-05 14:26:31 +08:00
ret = dw_hdmi_phy_init ( hdmi ) ;
2013-11-29 08:46:32 -02:00
if ( ret )
return ret ;
/* HDMI Initialization Step B.3 */
2014-12-05 14:26:31 +08:00
dw_hdmi_enable_video_path ( hdmi ) ;
2013-11-29 08:46:32 -02:00
/* not for DVI mode */
2015-07-21 15:35:52 +01:00
if ( hdmi - > sink_is_hdmi ) {
dev_dbg ( hdmi - > dev , " %s HDMI mode \n " , __func__ ) ;
2013-11-29 08:46:32 -02:00
/* HDMI Initialization Step E - Configure audio */
hdmi_clk_regenerator_update_pixel_clock ( hdmi ) ;
hdmi_enable_audio_clk ( hdmi ) ;
/* HDMI Initialization Step F - Configure AVI InfoFrame */
2015-03-27 20:06:50 +00:00
hdmi_config_AVI ( hdmi , mode ) ;
2015-07-21 15:35:52 +01:00
} else {
dev_dbg ( hdmi - > dev , " %s DVI mode \n " , __func__ ) ;
2013-11-29 08:46:32 -02:00
}
hdmi_video_packetize ( hdmi ) ;
hdmi_video_csc ( hdmi ) ;
hdmi_video_sample ( hdmi ) ;
hdmi_tx_hdcp_config ( hdmi ) ;
2014-12-05 14:26:31 +08:00
dw_hdmi_clear_overflow ( hdmi ) ;
2015-07-21 15:35:52 +01:00
if ( hdmi - > cable_plugin & & hdmi - > sink_is_hdmi )
2013-11-29 08:46:32 -02:00
hdmi_enable_overflow_interrupts ( hdmi ) ;
return 0 ;
}
/* Wait until we are registered to enable interrupts */
2014-12-05 14:26:31 +08:00
static int dw_hdmi_fb_registered ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
hdmi_writeb ( hdmi , HDMI_PHY_I2CM_INT_ADDR_DONE_POL ,
HDMI_PHY_I2CM_INT_ADDR ) ;
hdmi_writeb ( hdmi , HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL ,
HDMI_PHY_I2CM_CTLINT_ADDR ) ;
/* enable cable hot plug irq */
hdmi_writeb ( hdmi , ( u8 ) ~ HDMI_PHY_HPD , HDMI_PHY_MASK0 ) ;
/* Clear Hotplug interrupts */
hdmi_writeb ( hdmi , HDMI_IH_PHY_STAT0_HPD , HDMI_IH_PHY_STAT0 ) ;
return 0 ;
}
2014-12-05 14:26:31 +08:00
static void initialize_hdmi_ih_mutes ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
u8 ih_mute ;
/*
* Boot up defaults are :
* HDMI_IH_MUTE = 0x03 ( disabled )
* HDMI_IH_MUTE_ * = 0x00 ( enabled )
*
* Disable top level interrupt bits in HDMI block
*/
ih_mute = hdmi_readb ( hdmi , HDMI_IH_MUTE ) |
HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
HDMI_IH_MUTE_MUTE_ALL_INTERRUPT ;
hdmi_writeb ( hdmi , ih_mute , HDMI_IH_MUTE ) ;
/* by default mask all interrupts */
hdmi_writeb ( hdmi , 0xff , HDMI_VP_MASK ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_FC_MASK0 ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_FC_MASK1 ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_FC_MASK2 ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_PHY_MASK0 ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_PHY_I2CM_INT_ADDR ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_PHY_I2CM_CTLINT_ADDR ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_AUD_INT ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_AUD_SPDIFINT ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_AUD_HBR_MASK ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_GP_MASK ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_A_APIINTMSK ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_CEC_MASK ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_I2CM_INT ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_I2CM_CTLINT ) ;
/* Disable interrupts in the IH_MUTE_* registers */
hdmi_writeb ( hdmi , 0xff , HDMI_IH_MUTE_FC_STAT0 ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_IH_MUTE_FC_STAT1 ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_IH_MUTE_FC_STAT2 ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_IH_MUTE_AS_STAT0 ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_IH_MUTE_PHY_STAT0 ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_IH_MUTE_I2CM_STAT0 ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_IH_MUTE_CEC_STAT0 ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_IH_MUTE_VP_STAT0 ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_IH_MUTE_I2CMPHY_STAT0 ) ;
hdmi_writeb ( hdmi , 0xff , HDMI_IH_MUTE_AHBDMAAUD_STAT0 ) ;
/* Enable top level interrupt bits in HDMI block */
ih_mute & = ~ ( HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
HDMI_IH_MUTE_MUTE_ALL_INTERRUPT ) ;
hdmi_writeb ( hdmi , ih_mute , HDMI_IH_MUTE ) ;
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_poweron ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
2014-12-05 14:26:31 +08:00
dw_hdmi_setup ( hdmi , & hdmi - > previous_mode ) ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_poweroff ( struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
2014-12-05 14:26:31 +08:00
dw_hdmi_phy_disable ( hdmi ) ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_bridge_mode_set ( struct drm_bridge * bridge ,
2014-12-18 18:00:24 -08:00
struct drm_display_mode * orig_mode ,
struct drm_display_mode * mode )
2014-12-05 14:25:05 +08:00
{
2014-12-05 14:26:31 +08:00
struct dw_hdmi * hdmi = bridge - > driver_private ;
2014-12-05 14:25:05 +08:00
2014-12-05 14:26:31 +08:00
dw_hdmi_setup ( hdmi , mode ) ;
2014-12-05 14:25:05 +08:00
/* Store the display mode for plugin/DKMS poweron events */
memcpy ( & hdmi - > previous_mode , mode , sizeof ( hdmi - > previous_mode ) ) ;
}
2014-12-05 14:26:31 +08:00
static bool dw_hdmi_bridge_mode_fixup ( struct drm_bridge * bridge ,
const struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
2014-12-05 14:25:05 +08:00
{
return true ;
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_bridge_disable ( struct drm_bridge * bridge )
2014-12-05 14:25:05 +08:00
{
2014-12-05 14:26:31 +08:00
struct dw_hdmi * hdmi = bridge - > driver_private ;
2014-12-05 14:25:05 +08:00
2014-12-05 14:26:31 +08:00
dw_hdmi_poweroff ( hdmi ) ;
2014-12-05 14:25:05 +08:00
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_bridge_enable ( struct drm_bridge * bridge )
2014-12-05 14:25:05 +08:00
{
2014-12-05 14:26:31 +08:00
struct dw_hdmi * hdmi = bridge - > driver_private ;
2014-12-05 14:25:05 +08:00
2014-12-05 14:26:31 +08:00
dw_hdmi_poweron ( hdmi ) ;
2014-12-05 14:25:05 +08:00
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_bridge_nop ( struct drm_bridge * bridge )
2014-12-05 14:25:05 +08:00
{
/* do nothing */
}
2014-12-05 14:26:31 +08:00
static enum drm_connector_status
dw_hdmi_connector_detect ( struct drm_connector * connector , bool force )
2013-11-29 08:46:32 -02:00
{
2014-12-05 14:26:31 +08:00
struct dw_hdmi * hdmi = container_of ( connector , struct dw_hdmi ,
2013-11-03 22:23:24 +00:00
connector ) ;
2014-04-18 10:46:45 +01:00
return hdmi_readb ( hdmi , HDMI_PHY_STAT0 ) & HDMI_PHY_HPD ?
connector_status_connected : connector_status_disconnected ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static int dw_hdmi_connector_get_modes ( struct drm_connector * connector )
2013-11-29 08:46:32 -02:00
{
2014-12-05 14:26:31 +08:00
struct dw_hdmi * hdmi = container_of ( connector , struct dw_hdmi ,
2013-11-29 08:46:32 -02:00
connector ) ;
struct edid * edid ;
int ret ;
if ( ! hdmi - > ddc )
return 0 ;
edid = drm_get_edid ( connector , hdmi - > ddc ) ;
if ( edid ) {
dev_dbg ( hdmi - > dev , " got edid: width[%d] x height[%d] \n " ,
edid - > width_cm , edid - > height_cm ) ;
2015-07-21 15:35:52 +01:00
hdmi - > sink_is_hdmi = drm_detect_hdmi_monitor ( edid ) ;
2013-11-29 08:46:32 -02:00
drm_mode_connector_update_edid_property ( connector , edid ) ;
ret = drm_add_edid_modes ( connector , edid ) ;
kfree ( edid ) ;
} else {
dev_dbg ( hdmi - > dev , " failed to get edid \n " ) ;
}
return 0 ;
}
2014-12-05 14:30:21 +08:00
static enum drm_mode_status
dw_hdmi_connector_mode_valid ( struct drm_connector * connector ,
struct drm_display_mode * mode )
{
struct dw_hdmi * hdmi = container_of ( connector ,
struct dw_hdmi , connector ) ;
enum drm_mode_status mode_status = MODE_OK ;
2015-07-22 11:14:00 +01:00
/* We don't support double-clocked modes */
if ( mode - > flags & DRM_MODE_FLAG_DBLCLK )
return MODE_BAD ;
2014-12-05 14:30:21 +08:00
if ( hdmi - > plat_data - > mode_valid )
mode_status = hdmi - > plat_data - > mode_valid ( connector , mode ) ;
return mode_status ;
}
2014-12-05 14:26:31 +08:00
static struct drm_encoder * dw_hdmi_connector_best_encoder ( struct drm_connector
2013-11-29 08:46:32 -02:00
* connector )
{
2014-12-05 14:26:31 +08:00
struct dw_hdmi * hdmi = container_of ( connector , struct dw_hdmi ,
2013-11-29 08:46:32 -02:00
connector ) ;
2014-12-05 14:25:05 +08:00
return hdmi - > encoder ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static void dw_hdmi_connector_destroy ( struct drm_connector * connector )
2013-11-29 08:46:32 -02:00
{
2014-12-05 14:25:05 +08:00
drm_connector_unregister ( connector ) ;
drm_connector_cleanup ( connector ) ;
2013-11-29 08:46:32 -02:00
}
2014-12-05 14:26:31 +08:00
static struct drm_connector_funcs dw_hdmi_connector_funcs = {
2013-11-29 08:46:32 -02:00
. dpms = drm_helper_connector_dpms ,
. fill_modes = drm_helper_probe_single_connector_modes ,
2014-12-05 14:26:31 +08:00
. detect = dw_hdmi_connector_detect ,
. destroy = dw_hdmi_connector_destroy ,
2013-11-29 08:46:32 -02:00
} ;
2014-12-05 14:26:31 +08:00
static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
. get_modes = dw_hdmi_connector_get_modes ,
2014-12-05 14:30:21 +08:00
. mode_valid = dw_hdmi_connector_mode_valid ,
2014-12-05 14:26:31 +08:00
. best_encoder = dw_hdmi_connector_best_encoder ,
2013-11-29 08:46:32 -02:00
} ;
2014-12-05 14:26:31 +08:00
struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
. enable = dw_hdmi_bridge_enable ,
. disable = dw_hdmi_bridge_disable ,
. pre_enable = dw_hdmi_bridge_nop ,
. post_disable = dw_hdmi_bridge_nop ,
. mode_set = dw_hdmi_bridge_mode_set ,
. mode_fixup = dw_hdmi_bridge_mode_fixup ,
2014-12-05 14:25:05 +08:00
} ;
2014-12-05 14:26:31 +08:00
static irqreturn_t dw_hdmi_hardirq ( int irq , void * dev_id )
2013-11-03 22:23:24 +00:00
{
2014-12-05 14:26:31 +08:00
struct dw_hdmi * hdmi = dev_id ;
2013-11-03 22:23:24 +00:00
u8 intr_stat ;
intr_stat = hdmi_readb ( hdmi , HDMI_IH_PHY_STAT0 ) ;
if ( intr_stat )
hdmi_writeb ( hdmi , ~ 0 , HDMI_IH_MUTE_PHY_STAT0 ) ;
return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE ;
}
2014-12-05 14:26:31 +08:00
static irqreturn_t dw_hdmi_irq ( int irq , void * dev_id )
2013-11-29 08:46:32 -02:00
{
2014-12-05 14:26:31 +08:00
struct dw_hdmi * hdmi = dev_id ;
2013-11-29 08:46:32 -02:00
u8 intr_stat ;
u8 phy_int_pol ;
intr_stat = hdmi_readb ( hdmi , HDMI_IH_PHY_STAT0 ) ;
phy_int_pol = hdmi_readb ( hdmi , HDMI_PHY_POL0 ) ;
if ( intr_stat & HDMI_IH_PHY_STAT0_HPD ) {
if ( phy_int_pol & HDMI_PHY_HPD ) {
dev_dbg ( hdmi - > dev , " EVENT=plugin \n " ) ;
2013-11-04 12:42:02 +00:00
hdmi_modb ( hdmi , 0 , HDMI_PHY_HPD , HDMI_PHY_POL0 ) ;
2013-11-29 08:46:32 -02:00
2014-12-05 14:26:31 +08:00
dw_hdmi_poweron ( hdmi ) ;
2013-11-29 08:46:32 -02:00
} else {
dev_dbg ( hdmi - > dev , " EVENT=plugout \n " ) ;
2014-03-09 20:11:07 +02:00
hdmi_modb ( hdmi , HDMI_PHY_HPD , HDMI_PHY_HPD ,
2014-12-05 14:23:52 +08:00
HDMI_PHY_POL0 ) ;
2013-11-29 08:46:32 -02:00
2014-12-05 14:26:31 +08:00
dw_hdmi_poweroff ( hdmi ) ;
2013-11-29 08:46:32 -02:00
}
2015-06-06 00:12:41 +01:00
drm_helper_hpd_irq_event ( hdmi - > bridge - > dev ) ;
2013-11-29 08:46:32 -02:00
}
hdmi_writeb ( hdmi , intr_stat , HDMI_IH_PHY_STAT0 ) ;
2013-11-03 22:23:24 +00:00
hdmi_writeb ( hdmi , ~ HDMI_IH_PHY_STAT0_HPD , HDMI_IH_MUTE_PHY_STAT0 ) ;
2013-11-29 08:46:32 -02:00
return IRQ_HANDLED ;
}
2014-12-05 14:26:31 +08:00
static int dw_hdmi_register ( struct drm_device * drm , struct dw_hdmi * hdmi )
2013-11-29 08:46:32 -02:00
{
2014-12-05 14:25:05 +08:00
struct drm_encoder * encoder = hdmi - > encoder ;
struct drm_bridge * bridge ;
2013-11-29 08:46:32 -02:00
int ret ;
2014-12-05 14:25:05 +08:00
bridge = devm_kzalloc ( drm - > dev , sizeof ( * bridge ) , GFP_KERNEL ) ;
if ( ! bridge ) {
DRM_ERROR ( " Failed to allocate drm bridge \n " ) ;
return - ENOMEM ;
}
2013-11-29 08:46:32 -02:00
2014-12-05 14:25:05 +08:00
hdmi - > bridge = bridge ;
bridge - > driver_private = hdmi ;
2015-01-27 10:21:49 -02:00
bridge - > funcs = & dw_hdmi_bridge_funcs ;
ret = drm_bridge_attach ( drm , bridge ) ;
2014-12-05 14:25:05 +08:00
if ( ret ) {
DRM_ERROR ( " Failed to initialize bridge with drm \n " ) ;
return - EINVAL ;
}
2013-11-29 08:46:32 -02:00
2014-12-05 14:25:05 +08:00
encoder - > bridge = bridge ;
hdmi - > connector . polled = DRM_CONNECTOR_POLL_HPD ;
2013-11-29 08:46:32 -02:00
drm_connector_helper_add ( & hdmi - > connector ,
2014-12-05 14:26:31 +08:00
& dw_hdmi_connector_helper_funcs ) ;
drm_connector_init ( drm , & hdmi - > connector , & dw_hdmi_connector_funcs ,
2013-11-03 13:30:48 +00:00
DRM_MODE_CONNECTOR_HDMIA ) ;
2013-11-29 08:46:32 -02:00
2014-12-05 14:25:05 +08:00
hdmi - > connector . encoder = encoder ;
2013-11-29 08:46:32 -02:00
2014-12-05 14:25:05 +08:00
drm_mode_connector_attach_encoder ( & hdmi - > connector , encoder ) ;
2013-11-29 08:46:32 -02:00
return 0 ;
}
2014-12-05 14:26:31 +08:00
int dw_hdmi_bind ( struct device * dev , struct device * master ,
2014-12-05 14:25:05 +08:00
void * data , struct drm_encoder * encoder ,
struct resource * iores , int irq ,
const struct dw_hdmi_plat_data * plat_data )
2013-11-29 08:46:32 -02:00
{
2013-11-03 13:30:48 +00:00
struct drm_device * drm = data ;
2013-11-03 11:23:34 +00:00
struct device_node * np = dev - > of_node ;
2013-11-29 08:46:32 -02:00
struct device_node * ddc_node ;
2014-12-05 14:26:31 +08:00
struct dw_hdmi * hdmi ;
2014-12-05 14:25:05 +08:00
int ret ;
2014-12-05 14:28:24 +08:00
u32 val = 1 ;
2013-11-29 08:46:32 -02:00
2013-11-03 11:23:34 +00:00
hdmi = devm_kzalloc ( dev , sizeof ( * hdmi ) , GFP_KERNEL ) ;
2013-11-29 08:46:32 -02:00
if ( ! hdmi )
return - ENOMEM ;
2014-12-05 14:25:05 +08:00
hdmi - > plat_data = plat_data ;
2013-11-03 11:23:34 +00:00
hdmi - > dev = dev ;
2014-12-05 14:25:05 +08:00
hdmi - > dev_type = plat_data - > dev_type ;
2013-11-07 15:35:06 +00:00
hdmi - > sample_rate = 48000 ;
hdmi - > ratio = 100 ;
2014-12-05 14:25:05 +08:00
hdmi - > encoder = encoder ;
2013-11-29 08:46:32 -02:00
2015-02-02 11:01:08 +00:00
mutex_init ( & hdmi - > audio_mutex ) ;
2015-03-27 12:59:58 +00:00
spin_lock_init ( & hdmi - > audio_lock ) ;
2015-02-02 11:01:08 +00:00
2014-12-05 14:28:24 +08:00
of_property_read_u32 ( np , " reg-io-width " , & val ) ;
switch ( val ) {
case 4 :
hdmi - > write = dw_hdmi_writel ;
hdmi - > read = dw_hdmi_readl ;
break ;
case 1 :
hdmi - > write = dw_hdmi_writeb ;
hdmi - > read = dw_hdmi_readb ;
break ;
default :
dev_err ( dev , " reg-io-width must be 1 or 4 \n " ) ;
return - EINVAL ;
}
2014-03-05 10:20:56 +01:00
ddc_node = of_parse_phandle ( np , " ddc-i2c-bus " , 0 ) ;
2013-11-29 08:46:32 -02:00
if ( ddc_node ) {
hdmi - > ddc = of_find_i2c_adapter_by_node ( ddc_node ) ;
2014-12-05 14:24:28 +08:00
of_node_put ( ddc_node ) ;
if ( ! hdmi - > ddc ) {
2013-11-29 08:46:32 -02:00
dev_dbg ( hdmi - > dev , " failed to read ddc node \n " ) ;
2014-12-05 14:24:28 +08:00
return - EPROBE_DEFER ;
}
2013-11-29 08:46:32 -02:00
} else {
dev_dbg ( hdmi - > dev , " no ddc property found \n " ) ;
}
2013-11-03 11:23:34 +00:00
hdmi - > regs = devm_ioremap_resource ( dev , iores ) ;
2013-11-29 08:46:32 -02:00
if ( IS_ERR ( hdmi - > regs ) )
return PTR_ERR ( hdmi - > regs ) ;
hdmi - > isfr_clk = devm_clk_get ( hdmi - > dev , " isfr " ) ;
if ( IS_ERR ( hdmi - > isfr_clk ) ) {
ret = PTR_ERR ( hdmi - > isfr_clk ) ;
2014-12-05 14:23:52 +08:00
dev_err ( hdmi - > dev , " Unable to get HDMI isfr clk: %d \n " , ret ) ;
2013-11-29 08:46:32 -02:00
return ret ;
}
ret = clk_prepare_enable ( hdmi - > isfr_clk ) ;
if ( ret ) {
2014-12-05 14:23:52 +08:00
dev_err ( hdmi - > dev , " Cannot enable HDMI isfr clock: %d \n " , ret ) ;
2013-11-29 08:46:32 -02:00
return ret ;
}
hdmi - > iahb_clk = devm_clk_get ( hdmi - > dev , " iahb " ) ;
if ( IS_ERR ( hdmi - > iahb_clk ) ) {
ret = PTR_ERR ( hdmi - > iahb_clk ) ;
2014-12-05 14:23:52 +08:00
dev_err ( hdmi - > dev , " Unable to get HDMI iahb clk: %d \n " , ret ) ;
2013-11-29 08:46:32 -02:00
goto err_isfr ;
}
ret = clk_prepare_enable ( hdmi - > iahb_clk ) ;
if ( ret ) {
2014-12-05 14:23:52 +08:00
dev_err ( hdmi - > dev , " Cannot enable HDMI iahb clock: %d \n " , ret ) ;
2013-11-29 08:46:32 -02:00
goto err_isfr ;
}
/* Product and revision IDs */
2013-11-03 11:23:34 +00:00
dev_info ( dev ,
2014-12-05 14:23:52 +08:00
" Detected HDMI controller 0x%x:0x%x:0x%x:0x%x \n " ,
hdmi_readb ( hdmi , HDMI_DESIGN_ID ) ,
hdmi_readb ( hdmi , HDMI_REVISION_ID ) ,
hdmi_readb ( hdmi , HDMI_PRODUCT_ID0 ) ,
hdmi_readb ( hdmi , HDMI_PRODUCT_ID1 ) ) ;
2013-11-29 08:46:32 -02:00
initialize_hdmi_ih_mutes ( hdmi ) ;
2015-01-07 13:43:50 +01:00
ret = devm_request_threaded_irq ( dev , irq , dw_hdmi_hardirq ,
dw_hdmi_irq , IRQF_SHARED ,
dev_name ( dev ) , hdmi ) ;
if ( ret )
2015-01-27 10:54:12 -02:00
goto err_iahb ;
2015-01-07 13:43:50 +01:00
2013-11-29 08:46:32 -02:00
/*
* To prevent overflows in HDMI_IH_FC_STAT2 , set the clk regenerator
* N and cts values before enabling phy
*/
hdmi_init_clk_regenerator ( hdmi ) ;
/*
* Configure registers related to HDMI interrupt
* generation before registering IRQ .
*/
hdmi_writeb ( hdmi , HDMI_PHY_HPD , HDMI_PHY_POL0 ) ;
/* Clear Hotplug interrupts */
hdmi_writeb ( hdmi , HDMI_IH_PHY_STAT0_HPD , HDMI_IH_PHY_STAT0 ) ;
2014-12-05 14:26:31 +08:00
ret = dw_hdmi_fb_registered ( hdmi ) ;
2013-11-29 08:46:32 -02:00
if ( ret )
goto err_iahb ;
2014-12-05 14:26:31 +08:00
ret = dw_hdmi_register ( drm , hdmi ) ;
2013-11-29 08:46:32 -02:00
if ( ret )
goto err_iahb ;
2013-11-03 22:23:24 +00:00
/* Unmute interrupts */
hdmi_writeb ( hdmi , ~ HDMI_IH_PHY_STAT0_HPD , HDMI_IH_MUTE_PHY_STAT0 ) ;
2013-11-29 08:46:32 -02:00
2013-11-03 11:23:34 +00:00
dev_set_drvdata ( dev , hdmi ) ;
2013-11-29 08:46:32 -02:00
return 0 ;
err_iahb :
clk_disable_unprepare ( hdmi - > iahb_clk ) ;
err_isfr :
clk_disable_unprepare ( hdmi - > isfr_clk ) ;
return ret ;
}
2014-12-05 14:26:31 +08:00
EXPORT_SYMBOL_GPL ( dw_hdmi_bind ) ;
2013-11-29 08:46:32 -02:00
2014-12-05 14:26:31 +08:00
void dw_hdmi_unbind ( struct device * dev , struct device * master , void * data )
2013-11-29 08:46:32 -02:00
{
2014-12-05 14:26:31 +08:00
struct dw_hdmi * hdmi = dev_get_drvdata ( dev ) ;
2013-11-29 08:46:32 -02:00
2013-11-03 22:23:24 +00:00
/* Disable all interrupts */
hdmi_writeb ( hdmi , ~ 0 , HDMI_IH_MUTE_PHY_STAT0 ) ;
2013-11-03 13:30:48 +00:00
hdmi - > connector . funcs - > destroy ( & hdmi - > connector ) ;
2014-12-05 14:25:05 +08:00
hdmi - > encoder - > funcs - > destroy ( hdmi - > encoder ) ;
2013-11-29 08:46:32 -02:00
clk_disable_unprepare ( hdmi - > iahb_clk ) ;
clk_disable_unprepare ( hdmi - > isfr_clk ) ;
i2c_put_adapter ( hdmi - > ddc ) ;
2013-11-03 11:23:34 +00:00
}
2014-12-05 14:26:31 +08:00
EXPORT_SYMBOL_GPL ( dw_hdmi_unbind ) ;
2013-11-29 08:46:32 -02:00
MODULE_AUTHOR ( " Sascha Hauer <s.hauer@pengutronix.de> " ) ;
2014-12-05 14:25:05 +08:00
MODULE_AUTHOR ( " Andy Yan <andy.yan@rock-chips.com> " ) ;
MODULE_AUTHOR ( " Yakir Yang <ykk@rock-chips.com> " ) ;
2014-12-05 14:26:31 +08:00
MODULE_DESCRIPTION ( " DW HDMI transmitter driver " ) ;
2013-11-29 08:46:32 -02:00
MODULE_LICENSE ( " GPL " ) ;
2014-12-05 14:26:31 +08:00
MODULE_ALIAS ( " platform:dw-hdmi " ) ;