Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
xenomai
ipipe-x86
Commits
010cf269
Commit
010cf269
authored
Sep 25, 2015
by
Takashi Iwai
Browse files
Merge branch 'topic/drm-sync-audio-rate' into for-next
parents
0b2c8c12
7e8275c2
Changes
5
Hide whitespace changes
Inline
Side-by-side
drivers/gpu/drm/i915/i915_dma.c
View file @
010cf269
...
...
@@ -832,6 +832,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
mutex_init
(
&
dev_priv
->
sb_lock
);
mutex_init
(
&
dev_priv
->
modeset_restore_lock
);
mutex_init
(
&
dev_priv
->
csr_lock
);
mutex_init
(
&
dev_priv
->
av_mutex
);
intel_pm_setup
(
dev
);
...
...
drivers/gpu/drm/i915/i915_drv.h
View file @
010cf269
...
...
@@ -1885,6 +1885,11 @@ struct drm_i915_private {
/* hda/i915 audio component */
struct
i915_audio_component
*
audio_component
;
bool
audio_component_registered
;
/**
* av_mutex - mutex for audio/video sync
*
*/
struct
mutex
av_mutex
;
uint32_t
hw_context_size
;
struct
list_head
context_list
;
...
...
drivers/gpu/drm/i915/intel_audio.c
View file @
010cf269
...
...
@@ -68,6 +68,31 @@ static const struct {
{
148500
,
AUD_CONFIG_PIXEL_CLOCK_HDMI_148500
},
};
/* HDMI N/CTS table */
#define TMDS_297M 297000
#define TMDS_296M DIV_ROUND_UP(297000 * 1000, 1001)
static
const
struct
{
int
sample_rate
;
int
clock
;
int
n
;
int
cts
;
}
aud_ncts
[]
=
{
{
44100
,
TMDS_296M
,
4459
,
234375
},
{
44100
,
TMDS_297M
,
4704
,
247500
},
{
48000
,
TMDS_296M
,
5824
,
281250
},
{
48000
,
TMDS_297M
,
5120
,
247500
},
{
32000
,
TMDS_296M
,
5824
,
421875
},
{
32000
,
TMDS_297M
,
3072
,
222750
},
{
88200
,
TMDS_296M
,
8918
,
234375
},
{
88200
,
TMDS_297M
,
9408
,
247500
},
{
96000
,
TMDS_296M
,
11648
,
281250
},
{
96000
,
TMDS_297M
,
10240
,
247500
},
{
176400
,
TMDS_296M
,
17836
,
234375
},
{
176400
,
TMDS_297M
,
18816
,
247500
},
{
192000
,
TMDS_296M
,
23296
,
281250
},
{
192000
,
TMDS_297M
,
20480
,
247500
},
};
/* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */
static
u32
audio_config_hdmi_pixel_clock
(
struct
drm_display_mode
*
mode
)
{
...
...
@@ -90,6 +115,45 @@ static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode)
return
hdmi_audio_clock
[
i
].
config
;
}
static
int
audio_config_get_n
(
const
struct
drm_display_mode
*
mode
,
int
rate
)
{
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
aud_ncts
);
i
++
)
{
if
((
rate
==
aud_ncts
[
i
].
sample_rate
)
&&
(
mode
->
clock
==
aud_ncts
[
i
].
clock
))
{
return
aud_ncts
[
i
].
n
;
}
}
return
0
;
}
static
uint32_t
audio_config_setup_n_reg
(
int
n
,
uint32_t
val
)
{
int
n_low
,
n_up
;
uint32_t
tmp
=
val
;
n_low
=
n
&
0xfff
;
n_up
=
(
n
>>
12
)
&
0xff
;
tmp
&=
~
(
AUD_CONFIG_UPPER_N_MASK
|
AUD_CONFIG_LOWER_N_MASK
);
tmp
|=
((
n_up
<<
AUD_CONFIG_UPPER_N_SHIFT
)
|
(
n_low
<<
AUD_CONFIG_LOWER_N_SHIFT
)
|
AUD_CONFIG_N_PROG_ENABLE
);
return
tmp
;
}
/* check whether N/CTS/M need be set manually */
static
bool
audio_rate_need_prog
(
struct
intel_crtc
*
crtc
,
struct
drm_display_mode
*
mode
)
{
if
(((
mode
->
clock
==
TMDS_297M
)
||
(
mode
->
clock
==
TMDS_296M
))
&&
intel_pipe_has_type
(
crtc
,
INTEL_OUTPUT_HDMI
))
return
true
;
else
return
false
;
}
static
bool
intel_eld_uptodate
(
struct
drm_connector
*
connector
,
int
reg_eldv
,
uint32_t
bits_eldv
,
int
reg_elda
,
uint32_t
bits_elda
,
...
...
@@ -184,6 +248,8 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder)
DRM_DEBUG_KMS
(
"Disable audio codec on pipe %c
\n
"
,
pipe_name
(
pipe
));
mutex_lock
(
&
dev_priv
->
av_mutex
);
/* Disable timestamps */
tmp
=
I915_READ
(
HSW_AUD_CFG
(
pipe
));
tmp
&=
~
AUD_CONFIG_N_VALUE_INDEX
;
...
...
@@ -199,6 +265,8 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder)
tmp
&=
~
AUDIO_ELD_VALID
(
pipe
);
tmp
&=
~
AUDIO_OUTPUT_ENABLE
(
pipe
);
I915_WRITE
(
HSW_AUD_PIN_ELD_CP_VLD
,
tmp
);
mutex_unlock
(
&
dev_priv
->
av_mutex
);
}
static
void
hsw_audio_codec_enable
(
struct
drm_connector
*
connector
,
...
...
@@ -208,13 +276,20 @@ static void hsw_audio_codec_enable(struct drm_connector *connector,
struct
drm_i915_private
*
dev_priv
=
connector
->
dev
->
dev_private
;
struct
intel_crtc
*
intel_crtc
=
to_intel_crtc
(
encoder
->
base
.
crtc
);
enum
pipe
pipe
=
intel_crtc
->
pipe
;
struct
i915_audio_component
*
acomp
=
dev_priv
->
audio_component
;
const
uint8_t
*
eld
=
connector
->
eld
;
struct
intel_digital_port
*
intel_dig_port
=
enc_to_dig_port
(
&
encoder
->
base
);
enum
port
port
=
intel_dig_port
->
port
;
uint32_t
tmp
;
int
len
,
i
;
int
n
,
rate
;
DRM_DEBUG_KMS
(
"Enable audio codec on pipe %c, %u bytes ELD
\n
"
,
pipe_name
(
pipe
),
drm_eld_size
(
eld
));
mutex_lock
(
&
dev_priv
->
av_mutex
);
/* Enable audio presence detect, invalidate ELD */
tmp
=
I915_READ
(
HSW_AUD_PIN_ELD_CP_VLD
);
tmp
|=
AUDIO_OUTPUT_ENABLE
(
pipe
);
...
...
@@ -246,13 +321,32 @@ static void hsw_audio_codec_enable(struct drm_connector *connector,
/* Enable timestamps */
tmp
=
I915_READ
(
HSW_AUD_CFG
(
pipe
));
tmp
&=
~
AUD_CONFIG_N_VALUE_INDEX
;
tmp
&=
~
AUD_CONFIG_N_PROG_ENABLE
;
tmp
&=
~
AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK
;
if
(
intel_pipe_has_type
(
intel_crtc
,
INTEL_OUTPUT_DISPLAYPORT
))
tmp
|=
AUD_CONFIG_N_VALUE_INDEX
;
else
tmp
|=
audio_config_hdmi_pixel_clock
(
mode
);
tmp
&=
~
AUD_CONFIG_N_PROG_ENABLE
;
if
(
audio_rate_need_prog
(
intel_crtc
,
mode
))
{
if
(
!
acomp
)
rate
=
0
;
else
if
(
port
>=
PORT_A
&&
port
<=
PORT_E
)
rate
=
acomp
->
aud_sample_rate
[
port
];
else
{
DRM_ERROR
(
"invalid port: %d
\n
"
,
port
);
rate
=
0
;
}
n
=
audio_config_get_n
(
mode
,
rate
);
if
(
n
!=
0
)
tmp
=
audio_config_setup_n_reg
(
n
,
tmp
);
else
DRM_DEBUG_KMS
(
"no suitable N value is found
\n
"
);
}
I915_WRITE
(
HSW_AUD_CFG
(
pipe
),
tmp
);
mutex_unlock
(
&
dev_priv
->
av_mutex
);
}
static
void
ilk_audio_codec_disable
(
struct
intel_encoder
*
encoder
)
...
...
@@ -527,12 +621,91 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev)
return
ret
;
}
static
int
i915_audio_component_sync_audio_rate
(
struct
device
*
dev
,
int
port
,
int
rate
)
{
struct
drm_i915_private
*
dev_priv
=
dev_to_i915
(
dev
);
struct
drm_device
*
drm_dev
=
dev_priv
->
dev
;
struct
intel_encoder
*
intel_encoder
;
struct
intel_digital_port
*
intel_dig_port
;
struct
intel_crtc
*
crtc
;
struct
drm_display_mode
*
mode
;
struct
i915_audio_component
*
acomp
=
dev_priv
->
audio_component
;
enum
pipe
pipe
=
-
1
;
u32
tmp
;
int
n
;
/* HSW, BDW SKL need this fix */
if
(
!
IS_SKYLAKE
(
dev_priv
)
&&
!
IS_BROADWELL
(
dev_priv
)
&&
!
IS_HASWELL
(
dev_priv
))
return
0
;
mutex_lock
(
&
dev_priv
->
av_mutex
);
/* 1. get the pipe */
for_each_intel_encoder
(
drm_dev
,
intel_encoder
)
{
if
(
intel_encoder
->
type
!=
INTEL_OUTPUT_HDMI
)
continue
;
intel_dig_port
=
enc_to_dig_port
(
&
intel_encoder
->
base
);
if
(
port
==
intel_dig_port
->
port
)
{
crtc
=
to_intel_crtc
(
intel_encoder
->
base
.
crtc
);
if
(
!
crtc
)
{
DRM_DEBUG_KMS
(
"%s: crtc is NULL
\n
"
,
__func__
);
continue
;
}
pipe
=
crtc
->
pipe
;
break
;
}
}
if
(
pipe
==
INVALID_PIPE
)
{
DRM_DEBUG_KMS
(
"no pipe for the port %c
\n
"
,
port_name
(
port
));
mutex_unlock
(
&
dev_priv
->
av_mutex
);
return
-
ENODEV
;
}
DRM_DEBUG_KMS
(
"pipe %c connects port %c
\n
"
,
pipe_name
(
pipe
),
port_name
(
port
));
mode
=
&
crtc
->
config
->
base
.
adjusted_mode
;
/* port must be valid now, otherwise the pipe will be invalid */
acomp
->
aud_sample_rate
[
port
]
=
rate
;
/* 2. check whether to set the N/CTS/M manually or not */
if
(
!
audio_rate_need_prog
(
crtc
,
mode
))
{
tmp
=
I915_READ
(
HSW_AUD_CFG
(
pipe
));
tmp
&=
~
AUD_CONFIG_N_PROG_ENABLE
;
I915_WRITE
(
HSW_AUD_CFG
(
pipe
),
tmp
);
mutex_unlock
(
&
dev_priv
->
av_mutex
);
return
0
;
}
n
=
audio_config_get_n
(
mode
,
rate
);
if
(
n
==
0
)
{
DRM_DEBUG_KMS
(
"Using automatic mode for N value on port %c
\n
"
,
port_name
(
port
));
tmp
=
I915_READ
(
HSW_AUD_CFG
(
pipe
));
tmp
&=
~
AUD_CONFIG_N_PROG_ENABLE
;
I915_WRITE
(
HSW_AUD_CFG
(
pipe
),
tmp
);
mutex_unlock
(
&
dev_priv
->
av_mutex
);
return
0
;
}
/* 3. set the N/CTS/M */
tmp
=
I915_READ
(
HSW_AUD_CFG
(
pipe
));
tmp
=
audio_config_setup_n_reg
(
n
,
tmp
);
I915_WRITE
(
HSW_AUD_CFG
(
pipe
),
tmp
);
mutex_unlock
(
&
dev_priv
->
av_mutex
);
return
0
;
}
static
const
struct
i915_audio_component_ops
i915_audio_component_ops
=
{
.
owner
=
THIS_MODULE
,
.
get_power
=
i915_audio_component_get_power
,
.
put_power
=
i915_audio_component_put_power
,
.
codec_wake_override
=
i915_audio_component_codec_wake_override
,
.
get_cdclk_freq
=
i915_audio_component_get_cdclk_freq
,
.
sync_audio_rate
=
i915_audio_component_sync_audio_rate
,
};
static
int
i915_audio_component_bind
(
struct
device
*
i915_dev
,
...
...
@@ -540,6 +713,7 @@ static int i915_audio_component_bind(struct device *i915_dev,
{
struct
i915_audio_component
*
acomp
=
data
;
struct
drm_i915_private
*
dev_priv
=
dev_to_i915
(
i915_dev
);
int
i
;
if
(
WARN_ON
(
acomp
->
ops
||
acomp
->
dev
))
return
-
EEXIST
;
...
...
@@ -547,6 +721,9 @@ static int i915_audio_component_bind(struct device *i915_dev,
drm_modeset_lock_all
(
dev_priv
->
dev
);
acomp
->
ops
=
&
i915_audio_component_ops
;
acomp
->
dev
=
i915_dev
;
BUILD_BUG_ON
(
MAX_PORTS
!=
I915_MAX_PORTS
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
acomp
->
aud_sample_rate
);
i
++
)
acomp
->
aud_sample_rate
[
i
]
=
0
;
dev_priv
->
audio_component
=
acomp
;
drm_modeset_unlock_all
(
dev_priv
->
dev
);
...
...
include/drm/i915_component.h
View file @
010cf269
...
...
@@ -24,8 +24,18 @@
#ifndef _I915_COMPONENT_H_
#define _I915_COMPONENT_H_
/* MAX_PORT is the number of port
* It must be sync with I915_MAX_PORTS defined i915_drv.h
* 5 should be enough as only HSW, BDW, SKL need such fix.
*/
#define MAX_PORTS 5
struct
i915_audio_component
{
struct
device
*
dev
;
/**
* @aud_sample_rate: the array of audio sample rate per port
*/
int
aud_sample_rate
[
MAX_PORTS
];
const
struct
i915_audio_component_ops
{
struct
module
*
owner
;
...
...
@@ -33,6 +43,13 @@ struct i915_audio_component {
void
(
*
put_power
)(
struct
device
*
);
void
(
*
codec_wake_override
)(
struct
device
*
,
bool
enable
);
int
(
*
get_cdclk_freq
)(
struct
device
*
);
/**
* @sync_audio_rate: set n/cts based on the sample rate
*
* Called from audio driver. After audio driver sets the
* sample rate, it will call this function to set n/cts
*/
int
(
*
sync_audio_rate
)(
struct
device
*
,
int
port
,
int
rate
);
}
*
ops
;
const
struct
i915_audio_component_audio_ops
{
...
...
sound/pci/hda/patch_hdmi.c
View file @
010cf269
...
...
@@ -1775,6 +1775,16 @@ static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
return
non_pcm
;
}
/* There is a fixed mapping between audio pin node and display port
* on current Intel platforms:
* Pin Widget 5 - PORT B (port = 1 in i915 driver)
* Pin Widget 6 - PORT C (port = 2 in i915 driver)
* Pin Widget 7 - PORT D (port = 3 in i915 driver)
*/
static
int
intel_pin2port
(
hda_nid_t
pin_nid
)
{
return
pin_nid
-
4
;
}
/*
* HDMI callbacks
...
...
@@ -1791,6 +1801,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
int
pin_idx
=
hinfo_to_pin_index
(
codec
,
hinfo
);
struct
hdmi_spec_per_pin
*
per_pin
=
get_pin
(
spec
,
pin_idx
);
hda_nid_t
pin_nid
=
per_pin
->
pin_nid
;
struct
snd_pcm_runtime
*
runtime
=
substream
->
runtime
;
struct
i915_audio_component
*
acomp
=
codec
->
bus
->
core
.
audio_component
;
bool
non_pcm
;
int
pinctl
;
...
...
@@ -1807,6 +1819,13 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
intel_not_share_assigned_cvt
(
codec
,
pin_nid
,
per_pin
->
mux_idx
);
}
/* Call sync_audio_rate to set the N/CTS/M manually if necessary */
/* Todo: add DP1.2 MST audio support later */
if
(
acomp
&&
acomp
->
ops
&&
acomp
->
ops
->
sync_audio_rate
)
acomp
->
ops
->
sync_audio_rate
(
acomp
->
dev
,
intel_pin2port
(
pin_nid
),
runtime
->
rate
);
non_pcm
=
check_non_pcm_per_cvt
(
codec
,
cvt_nid
);
mutex_lock
(
&
per_pin
->
lock
);
per_pin
->
channels
=
substream
->
runtime
->
channels
;
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment