2013-07-31 16:51:33 -04:00
/*
* Copyright 2013 Advanced Micro Devices , Inc .
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE COPYRIGHT HOLDER ( S ) OR AUTHOR ( S ) BE LIABLE FOR ANY CLAIM , DAMAGES OR
* OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE ,
* ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE .
*
*/
# include <linux/hdmi.h>
2019-06-08 10:02:41 +02:00
2013-07-31 16:51:33 -04:00
# include "radeon.h"
2014-12-01 13:49:39 -05:00
# include "radeon_audio.h"
2013-07-31 16:51:33 -04:00
# include "sid.h"
2015-03-02 12:05:29 -05:00
# define DCE8_DCCG_AUDIO_DTO1_PHASE 0x05b8
# define DCE8_DCCG_AUDIO_DTO1_MODULE 0x05bc
2014-12-01 13:49:39 -05:00
u32 dce6_endpoint_rreg ( struct radeon_device * rdev ,
2013-07-31 16:51:33 -04:00
u32 block_offset , u32 reg )
{
2013-09-03 19:00:09 -04:00
unsigned long flags ;
2013-07-31 16:51:33 -04:00
u32 r ;
2013-09-03 19:00:09 -04:00
spin_lock_irqsave ( & rdev - > end_idx_lock , flags ) ;
2013-07-31 16:51:33 -04:00
WREG32 ( AZ_F0_CODEC_ENDPOINT_INDEX + block_offset , reg ) ;
r = RREG32 ( AZ_F0_CODEC_ENDPOINT_DATA + block_offset ) ;
2013-09-03 19:00:09 -04:00
spin_unlock_irqrestore ( & rdev - > end_idx_lock , flags ) ;
2013-07-31 16:51:33 -04:00
return r ;
}
2014-12-01 13:49:39 -05:00
void dce6_endpoint_wreg ( struct radeon_device * rdev ,
2013-07-31 16:51:33 -04:00
u32 block_offset , u32 reg , u32 v )
{
2013-09-03 19:00:09 -04:00
unsigned long flags ;
spin_lock_irqsave ( & rdev - > end_idx_lock , flags ) ;
2013-07-31 16:51:33 -04:00
if ( ASIC_IS_DCE8 ( rdev ) )
WREG32 ( AZ_F0_CODEC_ENDPOINT_INDEX + block_offset , reg ) ;
else
WREG32 ( AZ_F0_CODEC_ENDPOINT_INDEX + block_offset ,
AZ_ENDPOINT_REG_WRITE_EN | AZ_ENDPOINT_REG_INDEX ( reg ) ) ;
WREG32 ( AZ_F0_CODEC_ENDPOINT_DATA + block_offset , v ) ;
2013-09-03 19:00:09 -04:00
spin_unlock_irqrestore ( & rdev - > end_idx_lock , flags ) ;
2013-07-31 16:51:33 -04:00
}
static void dce6_afmt_get_connected_pins ( struct radeon_device * rdev )
{
int i ;
u32 offset , tmp ;
for ( i = 0 ; i < rdev - > audio . num_pins ; i + + ) {
offset = rdev - > audio . pin [ i ] . offset ;
tmp = RREG32_ENDPOINT ( offset ,
AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT ) ;
if ( ( ( tmp & PORT_CONNECTIVITY_MASK ) > > PORT_CONNECTIVITY_SHIFT ) = = 1 )
rdev - > audio . pin [ i ] . connected = false ;
else
rdev - > audio . pin [ i ] . connected = true ;
}
}
struct r600_audio_pin * dce6_audio_get_pin ( struct radeon_device * rdev )
{
2015-07-23 10:53:51 -04:00
struct drm_encoder * encoder ;
struct radeon_encoder * radeon_encoder ;
struct radeon_encoder_atom_dig * dig ;
struct r600_audio_pin * pin = NULL ;
int i , pin_count ;
2013-07-31 16:51:33 -04:00
dce6_afmt_get_connected_pins ( rdev ) ;
for ( i = 0 ; i < rdev - > audio . num_pins ; i + + ) {
2015-07-23 10:53:51 -04:00
if ( rdev - > audio . pin [ i ] . connected ) {
pin = & rdev - > audio . pin [ i ] ;
pin_count = 0 ;
list_for_each_entry ( encoder , & rdev - > ddev - > mode_config . encoder_list , head ) {
if ( radeon_encoder_is_digital ( encoder ) ) {
radeon_encoder = to_radeon_encoder ( encoder ) ;
dig = radeon_encoder - > enc_priv ;
if ( dig - > pin = = pin )
pin_count + + ;
}
}
if ( pin_count = = 0 )
return pin ;
}
2013-07-31 16:51:33 -04:00
}
2015-07-23 10:53:51 -04:00
if ( ! pin )
DRM_ERROR ( " No connected audio pins found! \n " ) ;
return pin ;
2013-07-31 16:51:33 -04:00
}
void dce6_afmt_select_pin ( struct drm_encoder * encoder )
{
struct radeon_device * rdev = encoder - > dev - > dev_private ;
struct radeon_encoder * radeon_encoder = to_radeon_encoder ( encoder ) ;
struct radeon_encoder_atom_dig * dig = radeon_encoder - > enc_priv ;
2015-07-23 10:01:09 -04:00
if ( ! dig | | ! dig - > afmt | | ! dig - > pin )
2013-07-31 16:51:33 -04:00
return ;
2015-07-23 10:01:09 -04:00
WREG32 ( AFMT_AUDIO_SRC_CONTROL + dig - > afmt - > offset ,
AFMT_AUDIO_SRC_SELECT ( dig - > pin - > id ) ) ;
2013-07-31 16:51:33 -04:00
}
2013-10-10 18:03:06 -04:00
void dce6_afmt_write_latency_fields ( struct drm_encoder * encoder ,
2015-07-23 10:01:09 -04:00
struct drm_connector * connector ,
struct drm_display_mode * mode )
2013-10-10 18:03:06 -04:00
{
struct radeon_device * rdev = encoder - > dev - > dev_private ;
struct radeon_encoder * radeon_encoder = to_radeon_encoder ( encoder ) ;
struct radeon_encoder_atom_dig * dig = radeon_encoder - > enc_priv ;
2015-07-23 10:01:09 -04:00
u32 tmp = 0 ;
2013-10-10 18:03:06 -04:00
2015-07-23 10:01:09 -04:00
if ( ! dig | | ! dig - > afmt | | ! dig - > pin )
2013-10-10 18:03:06 -04:00
return ;
if ( mode - > flags & DRM_MODE_FLAG_INTERLACE ) {
if ( connector - > latency_present [ 1 ] )
tmp = VIDEO_LIPSYNC ( connector - > video_latency [ 1 ] ) |
AUDIO_LIPSYNC ( connector - > audio_latency [ 1 ] ) ;
else
2014-07-13 01:47:14 +02:00
tmp = VIDEO_LIPSYNC ( 0 ) | AUDIO_LIPSYNC ( 0 ) ;
2013-10-10 18:03:06 -04:00
} else {
if ( connector - > latency_present [ 0 ] )
tmp = VIDEO_LIPSYNC ( connector - > video_latency [ 0 ] ) |
AUDIO_LIPSYNC ( connector - > audio_latency [ 0 ] ) ;
else
2014-07-13 01:47:14 +02:00
tmp = VIDEO_LIPSYNC ( 0 ) | AUDIO_LIPSYNC ( 0 ) ;
2013-10-10 18:03:06 -04:00
}
2015-07-23 10:01:09 -04:00
WREG32_ENDPOINT ( dig - > pin - > offset ,
AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC , tmp ) ;
2013-10-10 18:03:06 -04:00
}
2014-12-01 18:02:57 -05:00
void dce6_afmt_hdmi_write_speaker_allocation ( struct drm_encoder * encoder ,
2015-07-23 10:01:09 -04:00
u8 * sadb , int sad_count )
2013-07-31 16:51:33 -04:00
{
struct radeon_device * rdev = encoder - > dev - > dev_private ;
struct radeon_encoder * radeon_encoder = to_radeon_encoder ( encoder ) ;
struct radeon_encoder_atom_dig * dig = radeon_encoder - > enc_priv ;
2015-07-23 10:01:09 -04:00
u32 tmp ;
2013-08-15 11:16:30 +02:00
2015-07-23 10:01:09 -04:00
if ( ! dig | | ! dig - > afmt | | ! dig - > pin )
2013-08-15 11:16:30 +02:00
return ;
/* program the speaker allocation */
2015-07-23 10:01:09 -04:00
tmp = RREG32_ENDPOINT ( dig - > pin - > offset ,
AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER ) ;
2013-08-15 11:16:30 +02:00
tmp & = ~ ( DP_CONNECTION | SPEAKER_ALLOCATION_MASK ) ;
/* set HDMI mode */
tmp | = HDMI_CONNECTION ;
if ( sad_count )
tmp | = SPEAKER_ALLOCATION ( sadb [ 0 ] ) ;
else
tmp | = SPEAKER_ALLOCATION ( 5 ) ; /* stereo */
2015-07-23 10:01:09 -04:00
WREG32_ENDPOINT ( dig - > pin - > offset ,
AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER , tmp ) ;
2014-12-01 18:02:57 -05:00
}
2013-08-15 11:16:30 +02:00
2014-12-01 18:02:57 -05:00
void dce6_afmt_dp_write_speaker_allocation ( struct drm_encoder * encoder ,
2015-07-23 10:01:09 -04:00
u8 * sadb , int sad_count )
2014-12-01 18:02:57 -05:00
{
struct radeon_device * rdev = encoder - > dev - > dev_private ;
struct radeon_encoder * radeon_encoder = to_radeon_encoder ( encoder ) ;
struct radeon_encoder_atom_dig * dig = radeon_encoder - > enc_priv ;
2015-07-23 10:01:09 -04:00
u32 tmp ;
2014-12-01 18:02:57 -05:00
2015-07-23 10:01:09 -04:00
if ( ! dig | | ! dig - > afmt | | ! dig - > pin )
2014-12-01 18:02:57 -05:00
return ;
/* program the speaker allocation */
2015-07-23 10:01:09 -04:00
tmp = RREG32_ENDPOINT ( dig - > pin - > offset ,
AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER ) ;
2014-12-01 18:02:57 -05:00
tmp & = ~ ( HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK ) ;
/* set DP mode */
tmp | = DP_CONNECTION ;
if ( sad_count )
tmp | = SPEAKER_ALLOCATION ( sadb [ 0 ] ) ;
else
tmp | = SPEAKER_ALLOCATION ( 5 ) ; /* stereo */
2015-07-23 10:01:09 -04:00
WREG32_ENDPOINT ( dig - > pin - > offset ,
AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER , tmp ) ;
2013-08-15 11:16:30 +02:00
}
2015-01-22 10:41:55 -05:00
void dce6_afmt_write_sad_regs ( struct drm_encoder * encoder ,
2015-07-23 10:01:09 -04:00
struct cea_sad * sads , int sad_count )
2013-08-15 11:16:30 +02:00
{
2015-01-22 10:41:55 -05:00
int i ;
2013-08-15 11:16:30 +02:00
struct radeon_encoder * radeon_encoder = to_radeon_encoder ( encoder ) ;
struct radeon_encoder_atom_dig * dig = radeon_encoder - > enc_priv ;
2015-01-22 10:41:55 -05:00
struct radeon_device * rdev = encoder - > dev - > dev_private ;
2013-07-31 16:51:33 -04:00
static const u16 eld_reg_to_type [ ] [ 2 ] = {
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0 , HDMI_AUDIO_CODING_TYPE_PCM } ,
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1 , HDMI_AUDIO_CODING_TYPE_AC3 } ,
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR2 , HDMI_AUDIO_CODING_TYPE_MPEG1 } ,
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR3 , HDMI_AUDIO_CODING_TYPE_MP3 } ,
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR4 , HDMI_AUDIO_CODING_TYPE_MPEG2 } ,
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR5 , HDMI_AUDIO_CODING_TYPE_AAC_LC } ,
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR6 , HDMI_AUDIO_CODING_TYPE_DTS } ,
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR7 , HDMI_AUDIO_CODING_TYPE_ATRAC } ,
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR9 , HDMI_AUDIO_CODING_TYPE_EAC3 } ,
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR10 , HDMI_AUDIO_CODING_TYPE_DTS_HD } ,
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR11 , HDMI_AUDIO_CODING_TYPE_MLP } ,
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13 , HDMI_AUDIO_CODING_TYPE_WMA_PRO } ,
} ;
2015-07-23 10:01:09 -04:00
if ( ! dig | | ! dig - > afmt | | ! dig - > pin )
2013-07-31 16:51:33 -04:00
return ;
for ( i = 0 ; i < ARRAY_SIZE ( eld_reg_to_type ) ; i + + ) {
u32 value = 0 ;
2013-10-29 01:19:16 +02:00
u8 stereo_freqs = 0 ;
int max_channels = - 1 ;
2013-07-31 16:51:33 -04:00
int j ;
for ( j = 0 ; j < sad_count ; j + + ) {
struct cea_sad * sad = & sads [ j ] ;
if ( sad - > format = = eld_reg_to_type [ i ] [ 1 ] ) {
2013-10-29 01:19:16 +02:00
if ( sad - > channels > max_channels ) {
value = MAX_CHANNELS ( sad - > channels ) |
DESCRIPTOR_BYTE_2 ( sad - > byte2 ) |
SUPPORTED_FREQUENCIES ( sad - > freq ) ;
max_channels = sad - > channels ;
}
2013-07-31 16:51:33 -04:00
if ( sad - > format = = HDMI_AUDIO_CODING_TYPE_PCM )
2013-10-29 01:19:16 +02:00
stereo_freqs | = sad - > freq ;
else
break ;
2013-07-31 16:51:33 -04:00
}
}
2013-10-29 01:19:16 +02:00
value | = SUPPORTED_FREQUENCIES_STEREO ( stereo_freqs ) ;
2015-07-23 10:01:09 -04:00
WREG32_ENDPOINT ( dig - > pin - > offset , eld_reg_to_type [ i ] [ 0 ] , value ) ;
2013-07-31 16:51:33 -04:00
}
}
2014-02-18 11:07:55 -05:00
void dce6_audio_enable ( struct radeon_device * rdev ,
struct r600_audio_pin * pin ,
2014-09-18 17:26:39 -04:00
u8 enable_mask )
2013-07-31 16:51:33 -04:00
{
2014-02-18 11:07:55 -05:00
if ( ! pin )
return ;
2014-09-18 16:19:04 -04:00
WREG32_ENDPOINT ( pin - > offset , AZ_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL ,
2014-09-18 17:26:39 -04:00
enable_mask ? AUDIO_ENABLED : 0 ) ;
2013-07-31 16:51:33 -04:00
}
2014-12-05 13:38:31 -05:00
void dce6_hdmi_audio_set_dto ( struct radeon_device * rdev ,
2015-07-23 10:01:09 -04:00
struct radeon_crtc * crtc , unsigned int clock )
2014-12-05 13:38:31 -05:00
{
2015-03-02 11:31:07 -05:00
/* Two dtos; generally use dto0 for HDMI */
2014-12-05 13:38:31 -05:00
u32 value = 0 ;
2015-03-02 11:31:07 -05:00
if ( crtc )
2014-12-05 13:38:31 -05:00
value | = DCCG_AUDIO_DTO0_SOURCE_SEL ( crtc - > crtc_id ) ;
WREG32 ( DCCG_AUDIO_DTO_SOURCE , value ) ;
2015-03-02 11:31:07 -05:00
/* Express [24MHz / target pixel clock] as an exact rational
* number ( coefficient of two integer numbers . DCCG_AUDIO_DTOx_PHASE
* is the numerator , DCCG_AUDIO_DTOx_MODULE is the denominator
*/
WREG32 ( DCCG_AUDIO_DTO0_PHASE , 24000 ) ;
WREG32 ( DCCG_AUDIO_DTO0_MODULE , clock ) ;
2014-12-05 13:38:31 -05:00
}
void dce6_dp_audio_set_dto ( struct radeon_device * rdev ,
2015-07-23 10:01:09 -04:00
struct radeon_crtc * crtc , unsigned int clock )
2014-12-05 13:38:31 -05:00
{
2015-03-02 11:31:07 -05:00
/* Two dtos; generally use dto1 for DP */
2014-12-05 13:38:31 -05:00
u32 value = 0 ;
value | = DCCG_AUDIO_DTO_SEL ;
2015-03-02 11:31:07 -05:00
if ( crtc )
2014-12-05 13:38:31 -05:00
value | = DCCG_AUDIO_DTO0_SOURCE_SEL ( crtc - > crtc_id ) ;
WREG32 ( DCCG_AUDIO_DTO_SOURCE , value ) ;
2015-03-02 11:31:07 -05:00
/* Express [24MHz / target pixel clock] as an exact rational
* number ( coefficient of two integer numbers . DCCG_AUDIO_DTOx_PHASE
* is the numerator , DCCG_AUDIO_DTOx_MODULE is the denominator
*/
2015-03-02 12:05:29 -05:00
if ( ASIC_IS_DCE8 ( rdev ) ) {
2015-12-17 11:09:58 -05:00
unsigned int div = ( RREG32 ( DENTIST_DISPCLK_CNTL ) &
DENTIST_DPREFCLK_WDIVIDER_MASK ) > >
DENTIST_DPREFCLK_WDIVIDER_SHIFT ;
2016-01-26 16:56:25 -05:00
div = radeon_audio_decode_dfs_div ( div ) ;
2015-12-17 11:09:58 -05:00
if ( div )
2016-01-26 16:56:25 -05:00
clock = clock * 100 / div ;
2015-12-17 11:09:58 -05:00
2015-03-02 12:05:29 -05:00
WREG32 ( DCE8_DCCG_AUDIO_DTO1_PHASE , 24000 ) ;
WREG32 ( DCE8_DCCG_AUDIO_DTO1_MODULE , clock ) ;
} else {
WREG32 ( DCCG_AUDIO_DTO1_PHASE , 24000 ) ;
WREG32 ( DCCG_AUDIO_DTO1_MODULE , clock ) ;
}
2014-12-05 13:38:31 -05:00
}