Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
010cf269
Commit
010cf269
authored
Sep 25, 2015
by
Takashi Iwai
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'topic/drm-sync-audio-rate' into for-next
parents
0b2c8c12
7e8275c2
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
220 additions
and
1 deletion
+220
-1
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_dma.c
+1
-0
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_drv.h
+5
-0
drivers/gpu/drm/i915/intel_audio.c
drivers/gpu/drm/i915/intel_audio.c
+178
-1
include/drm/i915_component.h
include/drm/i915_component.h
+17
-0
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_hdmi.c
+19
-0
No files found.
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
Markdown
is supported
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