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
df91a210
Commit
df91a210
authored
Mar 13, 2016
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'asoc/topic/intel' into asoc-next
parents
a1eb3000
e2304803
Changes
27
Hide whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
2127 additions
and
260 deletions
+2127
-260
include/drm/drm_edid.h
include/drm/drm_edid.h
+12
-0
sound/soc/codecs/Kconfig
sound/soc/codecs/Kconfig
+1
-0
sound/soc/codecs/hdac_hdmi.c
sound/soc/codecs/hdac_hdmi.c
+1097
-123
sound/soc/codecs/hdac_hdmi.h
sound/soc/codecs/hdac_hdmi.h
+6
-0
sound/soc/intel/Kconfig
sound/soc/intel/Kconfig
+4
-0
sound/soc/intel/atom/sst/sst_acpi.c
sound/soc/intel/atom/sst/sst_acpi.c
+4
-0
sound/soc/intel/atom/sst/sst_ipc.c
sound/soc/intel/atom/sst/sst_ipc.c
+0
-2
sound/soc/intel/boards/bytcr_rt5640.c
sound/soc/intel/boards/bytcr_rt5640.c
+34
-16
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/boards/cht_bsw_max98090_ti.c
+2
-15
sound/soc/intel/boards/cht_bsw_rt5645.c
sound/soc/intel/boards/cht_bsw_rt5645.c
+14
-14
sound/soc/intel/boards/skl_nau88l25_max98357a.c
sound/soc/intel/boards/skl_nau88l25_max98357a.c
+105
-17
sound/soc/intel/boards/skl_nau88l25_ssm4567.c
sound/soc/intel/boards/skl_nau88l25_ssm4567.c
+112
-18
sound/soc/intel/boards/skl_rt286.c
sound/soc/intel/boards/skl_rt286.c
+104
-9
sound/soc/intel/common/sst-acpi.h
sound/soc/intel/common/sst-acpi.h
+3
-0
sound/soc/intel/common/sst-dsp-priv.h
sound/soc/intel/common/sst-dsp-priv.h
+1
-0
sound/soc/intel/common/sst-match-acpi.c
sound/soc/intel/common/sst-match-acpi.c
+40
-5
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-messages.c
+109
-15
sound/soc/intel/skylake/skl-nhlt.c
sound/soc/intel/skylake/skl-nhlt.c
+34
-0
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-pcm.c
+98
-8
sound/soc/intel/skylake/skl-sst-dsp.c
sound/soc/intel/skylake/skl-sst-dsp.c
+7
-7
sound/soc/intel/skylake/skl-sst-dsp.h
sound/soc/intel/skylake/skl-sst-dsp.h
+6
-1
sound/soc/intel/skylake/skl-sst.c
sound/soc/intel/skylake/skl-sst.c
+0
-3
sound/soc/intel/skylake/skl-topology.c
sound/soc/intel/skylake/skl-topology.c
+203
-5
sound/soc/intel/skylake/skl-topology.h
sound/soc/intel/skylake/skl-topology.h
+27
-0
sound/soc/intel/skylake/skl-tplg-interface.h
sound/soc/intel/skylake/skl-tplg-interface.h
+2
-1
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.c
+88
-0
sound/soc/intel/skylake/skl.h
sound/soc/intel/skylake/skl.h
+14
-1
No files found.
include/drm/drm_edid.h
View file @
df91a210
...
...
@@ -403,6 +403,18 @@ static inline int drm_eld_size(const uint8_t *eld)
return
DRM_ELD_HEADER_BLOCK_SIZE
+
eld
[
DRM_ELD_BASELINE_ELD_LEN
]
*
4
;
}
/**
* drm_eld_get_conn_type - Get device type hdmi/dp connected
* @eld: pointer to an ELD memory structure
*
* The caller need to use %DRM_ELD_CONN_TYPE_HDMI or %DRM_ELD_CONN_TYPE_DP to
* identify the display type connected.
*/
static
inline
u8
drm_eld_get_conn_type
(
const
uint8_t
*
eld
)
{
return
eld
[
DRM_ELD_SAD_COUNT_CONN_TYPE
]
&
DRM_ELD_CONN_TYPE_MASK
;
}
struct
edid
*
drm_do_get_edid
(
struct
drm_connector
*
connector
,
int
(
*
get_edid_block
)(
void
*
data
,
u8
*
buf
,
unsigned
int
block
,
size_t
len
),
...
...
sound/soc/codecs/Kconfig
View file @
df91a210
...
...
@@ -490,6 +490,7 @@ config SND_SOC_GTM601
config SND_SOC_HDAC_HDMI
tristate
select SND_HDA_EXT_CORE
select SND_PCM_ELD
select HDMI
config SND_SOC_ICS43432
...
...
sound/soc/codecs/hdac_hdmi.c
View file @
df91a210
...
...
@@ -22,11 +22,17 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/hdmi.h>
#include <drm/drm_edid.h>
#include <sound/pcm_params.h>
#include <sound/jack.h>
#include <sound/soc.h>
#include <sound/hdaudio_ext.h>
#include <sound/hda_i915.h>
#include <sound/pcm_drm_eld.h>
#include "../../hda/local.h"
#include "hdac_hdmi.h"
#define NAME_SIZE 32
#define AMP_OUT_MUTE 0xb080
#define AMP_OUT_UNMUTE 0xb000
...
...
@@ -34,6 +40,11 @@
#define HDA_MAX_CONNECTIONS 32
#define HDA_MAX_CVTS 3
#define ELD_MAX_SIZE 256
#define ELD_FIXED_BYTES 20
struct
hdac_hdmi_cvt_params
{
unsigned
int
channels_min
;
unsigned
int
channels_max
;
...
...
@@ -45,14 +56,34 @@ struct hdac_hdmi_cvt_params {
struct
hdac_hdmi_cvt
{
struct
list_head
head
;
hda_nid_t
nid
;
const
char
*
name
;
struct
hdac_hdmi_cvt_params
params
;
};
struct
hdac_hdmi_eld
{
bool
monitor_present
;
bool
eld_valid
;
int
eld_size
;
char
eld_buffer
[
ELD_MAX_SIZE
];
};
struct
hdac_hdmi_pin
{
struct
list_head
head
;
hda_nid_t
nid
;
int
num_mux_nids
;
hda_nid_t
mux_nids
[
HDA_MAX_CONNECTIONS
];
struct
hdac_hdmi_eld
eld
;
struct
hdac_ext_device
*
edev
;
int
repoll_count
;
struct
delayed_work
work
;
};
struct
hdac_hdmi_pcm
{
struct
list_head
head
;
int
pcm_id
;
struct
hdac_hdmi_pin
*
pin
;
struct
hdac_hdmi_cvt
*
cvt
;
struct
snd_jack
*
jack
;
};
struct
hdac_hdmi_dai_pin_map
{
...
...
@@ -62,11 +93,13 @@ struct hdac_hdmi_dai_pin_map {
};
struct
hdac_hdmi_priv
{
struct
hdac_hdmi_dai_pin_map
dai_map
[
3
];
struct
hdac_hdmi_dai_pin_map
dai_map
[
HDA_MAX_CVTS
];
struct
list_head
pin_list
;
struct
list_head
cvt_list
;
struct
list_head
pcm_list
;
int
num_pin
;
int
num_cvt
;
struct
mutex
pin_mutex
;
};
static
inline
struct
hdac_ext_device
*
to_hda_ext_device
(
struct
device
*
dev
)
...
...
@@ -76,6 +109,119 @@ static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
return
to_ehdac_device
(
hdac
);
}
static
unsigned
int
sad_format
(
const
u8
*
sad
)
{
return
((
sad
[
0
]
>>
0x3
)
&
0x1f
);
}
static
unsigned
int
sad_sample_bits_lpcm
(
const
u8
*
sad
)
{
return
(
sad
[
2
]
&
7
);
}
static
int
hdac_hdmi_eld_limit_formats
(
struct
snd_pcm_runtime
*
runtime
,
void
*
eld
)
{
u64
formats
=
SNDRV_PCM_FMTBIT_S16
;
int
i
;
const
u8
*
sad
,
*
eld_buf
=
eld
;
sad
=
drm_eld_sad
(
eld_buf
);
if
(
!
sad
)
goto
format_constraint
;
for
(
i
=
drm_eld_sad_count
(
eld_buf
);
i
>
0
;
i
--
,
sad
+=
3
)
{
if
(
sad_format
(
sad
)
==
1
)
{
/* AUDIO_CODING_TYPE_LPCM */
/*
* the controller support 20 and 24 bits in 32 bit
* container so we set S32
*/
if
(
sad_sample_bits_lpcm
(
sad
)
&
0x6
)
formats
|=
SNDRV_PCM_FMTBIT_S32
;
}
}
format_constraint:
return
snd_pcm_hw_constraint_mask64
(
runtime
,
SNDRV_PCM_HW_PARAM_FORMAT
,
formats
);
}
/* HDMI ELD routines */
static
unsigned
int
hdac_hdmi_get_eld_data
(
struct
hdac_device
*
codec
,
hda_nid_t
nid
,
int
byte_index
)
{
unsigned
int
val
;
val
=
snd_hdac_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_HDMI_ELDD
,
byte_index
);
dev_dbg
(
&
codec
->
dev
,
"HDMI: ELD data byte %d: 0x%x
\n
"
,
byte_index
,
val
);
return
val
;
}
static
int
hdac_hdmi_get_eld_size
(
struct
hdac_device
*
codec
,
hda_nid_t
nid
)
{
return
snd_hdac_codec_read
(
codec
,
nid
,
0
,
AC_VERB_GET_HDMI_DIP_SIZE
,
AC_DIPSIZE_ELD_BUF
);
}
/*
* This function queries the ELD size and ELD data and fills in the buffer
* passed by user
*/
static
int
hdac_hdmi_get_eld
(
struct
hdac_device
*
codec
,
hda_nid_t
nid
,
unsigned
char
*
buf
,
int
*
eld_size
)
{
int
i
,
size
,
ret
=
0
;
/*
* ELD size is initialized to zero in caller function. If no errors and
* ELD is valid, actual eld_size is assigned.
*/
size
=
hdac_hdmi_get_eld_size
(
codec
,
nid
);
if
(
size
<
ELD_FIXED_BYTES
||
size
>
ELD_MAX_SIZE
)
{
dev_err
(
&
codec
->
dev
,
"HDMI: invalid ELD buf size %d
\n
"
,
size
);
return
-
ERANGE
;
}
/* set ELD buffer */
for
(
i
=
0
;
i
<
size
;
i
++
)
{
unsigned
int
val
=
hdac_hdmi_get_eld_data
(
codec
,
nid
,
i
);
/*
* Graphics driver might be writing to ELD buffer right now.
* Just abort. The caller will repoll after a while.
*/
if
(
!
(
val
&
AC_ELDD_ELD_VALID
))
{
dev_err
(
&
codec
->
dev
,
"HDMI: invalid ELD data byte %d
\n
"
,
i
);
ret
=
-
EINVAL
;
goto
error
;
}
val
&=
AC_ELDD_ELD_DATA
;
/*
* The first byte cannot be zero. This can happen on some DVI
* connections. Some Intel chips may also need some 250ms delay
* to return non-zero ELD data, even when the graphics driver
* correctly writes ELD content before setting ELD_valid bit.
*/
if
(
!
val
&&
!
i
)
{
dev_err
(
&
codec
->
dev
,
"HDMI: 0 ELD data
\n
"
);
ret
=
-
EINVAL
;
goto
error
;
}
buf
[
i
]
=
val
;
}
*
eld_size
=
size
;
error:
return
ret
;
}
static
int
hdac_hdmi_setup_stream
(
struct
hdac_ext_device
*
hdac
,
hda_nid_t
cvt_nid
,
hda_nid_t
pin_nid
,
u32
stream_tag
,
int
format
)
...
...
@@ -107,27 +253,75 @@ hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid,
AC_VERB_SET_HDMI_DIP_INDEX
,
val
);
}
struct
dp_audio_infoframe
{
u8
type
;
/* 0x84 */
u8
len
;
/* 0x1b */
u8
ver
;
/* 0x11 << 2 */
u8
CC02_CT47
;
/* match with HDMI infoframe from this on */
u8
SS01_SF24
;
u8
CXT04
;
u8
CA
;
u8
LFEPBL01_LSV36_DM_INH7
;
};
static
int
hdac_hdmi_setup_audio_infoframe
(
struct
hdac_ext_device
*
hdac
,
hda_nid_t
cvt_nid
,
hda_nid_t
pin_nid
)
{
uint8_t
buffer
[
HDMI_INFOFRAME_HEADER_SIZE
+
HDMI_AUDIO_INFOFRAME_SIZE
];
struct
hdmi_audio_infoframe
frame
;
u8
*
dip
=
(
u8
*
)
&
frame
;
struct
dp_audio_infoframe
dp_ai
;
struct
hdac_hdmi_priv
*
hdmi
=
hdac
->
private_data
;
struct
hdac_hdmi_pin
*
pin
;
u8
*
dip
;
int
ret
;
int
i
;
const
u8
*
eld_buf
;
u8
conn_type
;
int
channels
=
2
;
hdmi_audio_infoframe_init
(
&
frame
);
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
{
if
(
pin
->
nid
==
pin_nid
)
break
;
}
/* Default stereo for now */
frame
.
channels
=
2
;
eld_buf
=
pin
->
eld
.
eld_buffer
;
conn_type
=
drm_eld_get_conn_type
(
eld_buf
)
;
/* setup channel count */
snd_hdac_codec_write
(
&
hdac
->
hdac
,
cvt_nid
,
0
,
AC_VERB_SET_CVT_CHAN_COUNT
,
frame
.
channels
-
1
);
AC_VERB_SET_CVT_CHAN_COUNT
,
channels
-
1
);
ret
=
hdmi_audio_infoframe_pack
(
&
frame
,
buffer
,
sizeof
(
buffer
));
if
(
ret
<
0
)
return
ret
;
switch
(
conn_type
)
{
case
DRM_ELD_CONN_TYPE_HDMI
:
hdmi_audio_infoframe_init
(
&
frame
);
/* Default stereo for now */
frame
.
channels
=
channels
;
ret
=
hdmi_audio_infoframe_pack
(
&
frame
,
buffer
,
sizeof
(
buffer
));
if
(
ret
<
0
)
return
ret
;
dip
=
(
u8
*
)
&
frame
;
break
;
case
DRM_ELD_CONN_TYPE_DP
:
memset
(
&
dp_ai
,
0
,
sizeof
(
dp_ai
));
dp_ai
.
type
=
0x84
;
dp_ai
.
len
=
0x1b
;
dp_ai
.
ver
=
0x11
<<
2
;
dp_ai
.
CC02_CT47
=
channels
-
1
;
dp_ai
.
CA
=
0
;
dip
=
(
u8
*
)
&
dp_ai
;
break
;
default:
dev_err
(
&
hdac
->
hdac
.
dev
,
"Invalid connection type: %d
\n
"
,
conn_type
);
return
-
EIO
;
}
/* stop infoframe transmission */
hdac_hdmi_set_dip_index
(
hdac
,
pin_nid
,
0x0
,
0x0
);
...
...
@@ -137,9 +331,15 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
/* Fill infoframe. Index auto-incremented */
hdac_hdmi_set_dip_index
(
hdac
,
pin_nid
,
0x0
,
0x0
);
for
(
i
=
0
;
i
<
sizeof
(
frame
);
i
++
)
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin_nid
,
0
,
if
(
conn_type
==
DRM_ELD_CONN_TYPE_HDMI
)
{
for
(
i
=
0
;
i
<
sizeof
(
frame
);
i
++
)
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin_nid
,
0
,
AC_VERB_SET_HDMI_DIP_DATA
,
dip
[
i
]);
}
else
{
for
(
i
=
0
;
i
<
sizeof
(
dp_ai
);
i
++
)
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin_nid
,
0
,
AC_VERB_SET_HDMI_DIP_DATA
,
dip
[
i
]);
}
/* Start infoframe */
hdac_hdmi_set_dip_index
(
hdac
,
pin_nid
,
0x0
,
0x0
);
...
...
@@ -174,11 +374,6 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
struct
hdac_ext_dma_params
*
dd
;
int
ret
;
if
(
dai
->
id
>
0
)
{
dev_err
(
&
hdac
->
hdac
.
dev
,
"Only one dai supported as of now
\n
"
);
return
-
ENODEV
;
}
dai_map
=
&
hdmi
->
dai_map
[
dai
->
id
];
dd
=
(
struct
hdac_ext_dma_params
*
)
snd_soc_dai_get_dma_data
(
dai
,
substream
);
...
...
@@ -198,16 +393,30 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
struct
snd_pcm_hw_params
*
hparams
,
struct
snd_soc_dai
*
dai
)
{
struct
hdac_ext_device
*
hdac
=
snd_soc_dai_get_drvdata
(
dai
);
struct
hdac_hdmi_priv
*
hdmi
=
hdac
->
private_data
;
struct
hdac_hdmi_dai_pin_map
*
dai_map
;
struct
hdac_hdmi_pin
*
pin
;
struct
hdac_ext_dma_params
*
dd
;
if
(
dai
->
id
>
0
)
{
dev_err
(
&
hdac
->
hdac
.
dev
,
"Only one dai supported as of now
\n
"
);
dai_map
=
&
hdmi
->
dai_map
[
dai
->
id
];
pin
=
dai_map
->
pin
;
if
(
!
pin
)
return
-
ENODEV
;
if
((
!
pin
->
eld
.
monitor_present
)
||
(
!
pin
->
eld
.
eld_valid
))
{
dev_err
(
&
hdac
->
hdac
.
dev
,
"device is not configured for this pin: %d
\n
"
,
pin
->
nid
);
return
-
ENODEV
;
}
dd
=
kzalloc
(
sizeof
(
*
dd
),
GFP_KERNEL
);
if
(
!
dd
)
return
-
ENOMEM
;
dd
=
snd_soc_dai_get_dma_data
(
dai
,
substream
);
if
(
!
dd
)
{
dd
=
kzalloc
(
sizeof
(
*
dd
),
GFP_KERNEL
);
if
(
!
dd
)
return
-
ENOMEM
;
}
dd
->
format
=
snd_hdac_calc_stream_format
(
params_rate
(
hparams
),
params_channels
(
hparams
),
params_format
(
hparams
),
24
,
0
);
...
...
@@ -227,50 +436,187 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
dai_map
=
&
hdmi
->
dai_map
[
dai
->
id
];
dd
=
(
struct
hdac_ext_dma_params
*
)
snd_soc_dai_get_dma_data
(
dai
,
substream
);
if
(
dd
)
{
snd_soc_dai_set_dma_data
(
dai
,
substream
,
NULL
);
kfree
(
dd
);
}
return
0
;
}
static
void
hdac_hdmi_enable_cvt
(
struct
hdac_ext_device
*
edev
,
struct
hdac_hdmi_dai_pin_map
*
dai_map
)
{
/* Enable transmission */
snd_hdac_codec_write
(
&
edev
->
hdac
,
dai_map
->
cvt
->
nid
,
0
,
AC_VERB_SET_CHANNEL_STREAMID
,
0
);
AC_VERB_SET_DIGI_CONVERT_1
,
1
);
/* Category Code (CC) to zero */
snd_hdac_codec_write
(
&
edev
->
hdac
,
dai_map
->
cvt
->
nid
,
0
,
AC_VERB_SET_STREAM_FORMAT
,
0
);
AC_VERB_SET_DIGI_CONVERT_2
,
0
);
}
dd
=
(
struct
hdac_ext_dma_params
*
)
snd_soc_dai_get_dma_data
(
dai
,
substream
);
snd_soc_dai_set_dma_data
(
dai
,
substream
,
NULL
);
static
int
hdac_hdmi_enable_pin
(
struct
hdac_ext_device
*
hdac
,
struct
hdac_hdmi_dai_pin_map
*
dai_map
)
{
int
mux_idx
;
struct
hdac_hdmi_pin
*
pin
=
dai_map
->
pin
;
for
(
mux_idx
=
0
;
mux_idx
<
pin
->
num_mux_nids
;
mux_idx
++
)
{
if
(
pin
->
mux_nids
[
mux_idx
]
==
dai_map
->
cvt
->
nid
)
{
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin
->
nid
,
0
,
AC_VERB_SET_CONNECT_SEL
,
mux_idx
);
break
;
}
}
kfree
(
dd
);
if
(
mux_idx
==
pin
->
num_mux_nids
)
return
-
EIO
;
/* Enable out path for this pin widget */
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin
->
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
);
hdac_hdmi_set_power_state
(
hdac
,
dai_map
,
AC_PWRST_D0
);
snd_hdac_codec_write
(
&
hdac
->
hdac
,
pin
->
nid
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
);
return
0
;
}
static
int
hdac_hdmi_query_pin_connlist
(
struct
hdac_ext_device
*
hdac
,
struct
hdac_hdmi_pin
*
pin
)
{
if
(
!
(
get_wcaps
(
&
hdac
->
hdac
,
pin
->
nid
)
&
AC_WCAP_CONN_LIST
))
{
dev_warn
(
&
hdac
->
hdac
.
dev
,
"HDMI: pin %d wcaps %#x does not support connection list
\n
"
,
pin
->
nid
,
get_wcaps
(
&
hdac
->
hdac
,
pin
->
nid
));
return
-
EINVAL
;
}
pin
->
num_mux_nids
=
snd_hdac_get_connections
(
&
hdac
->
hdac
,
pin
->
nid
,
pin
->
mux_nids
,
HDA_MAX_CONNECTIONS
);
if
(
pin
->
num_mux_nids
==
0
)
dev_warn
(
&
hdac
->
hdac
.
dev
,
"No connections found for pin: %d
\n
"
,
pin
->
nid
);
dev_dbg
(
&
hdac
->
hdac
.
dev
,
"num_mux_nids %d for pin: %d
\n
"
,
pin
->
num_mux_nids
,
pin
->
nid
);
return
pin
->
num_mux_nids
;
}
/*
* Query pcm list and return pin widget to which stream is routed.
*
* Also query connection list of the pin, to validate the cvt to pin map.
*
* Same stream rendering to multiple pins simultaneously can be done
* possibly, but not supported for now in driver. So return the first pin
* connected.
*/
static
struct
hdac_hdmi_pin
*
hdac_hdmi_get_pin_from_cvt
(
struct
hdac_ext_device
*
edev
,
struct
hdac_hdmi_priv
*
hdmi
,
struct
hdac_hdmi_cvt
*
cvt
)
{
struct
hdac_hdmi_pcm
*
pcm
;
struct
hdac_hdmi_pin
*
pin
=
NULL
;
int
ret
,
i
;
list_for_each_entry
(
pcm
,
&
hdmi
->
pcm_list
,
head
)
{
if
(
pcm
->
cvt
==
cvt
)
{
pin
=
pcm
->
pin
;
break
;
}
}
if
(
pin
)
{
ret
=
hdac_hdmi_query_pin_connlist
(
edev
,
pin
);
if
(
ret
<
0
)
return
NULL
;
for
(
i
=
0
;
i
<
pin
->
num_mux_nids
;
i
++
)
{
if
(
pin
->
mux_nids
[
i
]
==
cvt
->
nid
)
return
pin
;
}
}
return
NULL
;
}
/*
* This tries to get a valid pin and set the HW constraints based on the
* ELD. Even if a valid pin is not found return success so that device open
* doesn't fail.
*/
static
int
hdac_hdmi_pcm_open
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
struct
hdac_ext_device
*
hdac
=
snd_soc_dai_get_drvdata
(
dai
);
struct
hdac_hdmi_priv
*
hdmi
=
hdac
->
private_data
;
struct
hdac_hdmi_dai_pin_map
*
dai_map
;
int
val
;
if
(
dai
->
id
>
0
)
{
dev_err
(
&
hdac
->
hdac
.
dev
,
"Only one dai supported as of now
\n
"
);
return
-
ENODEV
;
}
struct
hdac_hdmi_cvt
*
cvt
;
struct
hdac_hdmi_pin
*
pin
;
int
ret
;
dai_map
=
&
hdmi
->
dai_map
[
dai
->
id
];
val
=
snd_hdac_codec_read
(
&
hdac
->
hdac
,
dai_map
->
pin
->
nid
,
0
,
AC_VERB_GET_PIN_SENSE
,
0
);
dev_info
(
&
hdac
->
hdac
.
dev
,
"Val for AC_VERB_GET_PIN_SENSE: %x
\n
"
,
val
);
cvt
=
dai_map
->
cvt
;
pin
=
hdac_hdmi_get_pin_from_cvt
(
hdac
,
hdmi
,
cvt
);
if
((
!
(
val
&
AC_PINSENSE_PRESENCE
))
||
(
!
(
val
&
AC_PINSENSE_ELDV
)))
{
dev_err
(
&
hdac
->
hdac
.
dev
,
"Monitor presence invalid with val: %x
\n
"
,
val
);
return
-
ENODEV
;
/*
* To make PA and other userland happy.
* userland scans devices so returning error does not help.
*/
if
(
!
pin
)
return
0
;
if
((
!
pin
->
eld
.
monitor_present
)
||
(
!
pin
->
eld
.
eld_valid
))
{
dev_warn
(
&
hdac
->
hdac
.
dev
,
"Failed: montior present? %d ELD valid?: %d for pin: %d
\n
"
,
pin
->
eld
.
monitor_present
,
pin
->
eld
.
eld_valid
,
pin
->
nid
);
return
0
;
}
hdac_hdmi_set_power_state
(
hdac
,
dai_map
,
AC_PWRST_D0
)
;
dai_map
->
pin
=
pin
;
snd_hdac_codec_write
(
&
hdac
->
hdac
,
dai_map
->
pin
->
nid
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_UNMUTE
);
hdac_hdmi_enable_cvt
(
hdac
,
dai_map
);
ret
=
hdac_hdmi_enable_pin
(
hdac
,
dai_map
);
if
(
ret
<
0
)
return
ret
;
snd_pcm_hw_constraint_step
(
substream
->
runtime
,
0
,
SNDRV_PCM_HW_PARAM_CHANNELS
,
2
);
ret
=
hdac_hdmi_eld_limit_formats
(
substream
->
runtime
,
pin
->
eld
.
eld_buffer
);
if
(
ret
<
0
)
return
ret
;
return
snd_pcm_hw_constraint_eld
(
substream
->
runtime
,
pin
->
eld
.
eld_buffer
);
}
static
int
hdac_hdmi_trigger
(
struct
snd_pcm_substream
*
substream
,
int
cmd
,
struct
snd_soc_dai
*
dai
)
{
struct
hdac_hdmi_dai_pin_map
*
dai_map
;
struct
hdac_ext_device
*
hdac
=
snd_soc_dai_get_drvdata
(
dai
);
struct
hdac_hdmi_priv
*
hdmi
=
hdac
->
private_data
;
int
ret
;
dai_map
=
&
hdmi
->
dai_map
[
dai
->
id
];
if
(
cmd
==
SNDRV_PCM_TRIGGER_RESUME
)
{
ret
=
hdac_hdmi_enable_pin
(
hdac
,
dai_map
);
if
(
ret
<
0
)
return
ret
;
return
hdac_hdmi_playback_prepare
(
substream
,
dai
);
}
return
0
;
}
...
...
@@ -284,10 +630,19 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
dai_map
=
&
hdmi
->
dai_map
[
dai
->
id
];
hdac_hdmi_set_power_state
(
hdac
,
dai_map
,
AC_PWRST_D3
);
if
(
dai_map
->
pin
)
{
snd_hdac_codec_write
(
&
hdac
->
hdac
,
dai_map
->
cvt
->
nid
,
0
,
AC_VERB_SET_CHANNEL_STREAMID
,
0
);
snd_hdac_codec_write
(
&
hdac
->
hdac
,
dai_map
->
cvt
->
nid
,
0
,
AC_VERB_SET_STREAM_FORMAT
,
0
);
hdac_hdmi_set_power_state
(
hdac
,
dai_map
,
AC_PWRST_D3
);
snd_hdac_codec_write
(
&
hdac
->
hdac
,
dai_map
->
pin
->
nid
,
0
,
snd_hdac_codec_write
(
&
hdac
->
hdac
,
dai_map
->
pin
->
nid
,
0
,
AC_VERB_SET_AMP_GAIN_MUTE
,
AMP_OUT_MUTE
);
dai_map
->
pin
=
NULL
;
}
}
static
int
...
...
@@ -310,85 +665,326 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
return
err
;
}
static
void
hdac_hdmi_fill_widget_info
(
struct
snd_soc_dapm_widget
*
w
,
enum
snd_soc_dapm_type
id
,
const
char
*
wname
,
const
char
*
stream
)
static
int
hdac_hdmi_fill_widget_info
(
struct
device
*
dev
,
struct
snd_soc_dapm_widget
*
w
,
enum
snd_soc_dapm_type
id
,
void
*
priv
,
const
char
*
wname
,
const
char
*
stream
,
struct
snd_kcontrol_new
*
wc
,
int
numkc
)
{
w
->
id
=
id
;
w
->
name
=
wname
;
w
->
name
=
devm_kstrdup
(
dev
,
wname
,
GFP_KERNEL
);
if
(
!
w
->
name
)
return
-
ENOMEM
;
w
->
sname
=
stream
;
w
->
reg
=
SND_SOC_NOPM
;
w
->
shift
=
0
;
w
->
kcontrol_news
=
NULL
;
w
->
num_kcontrols
=
0
;
w
->
priv
=
NULL
;
w
->
kcontrol_news
=
wc
;
w
->
num_kcontrols
=
numkc
;
w
->
priv
=
priv
;
return
0
;
}
static
void
hdac_hdmi_fill_route
(
struct
snd_soc_dapm_route
*
route
,
const
char
*
sink
,
const
char
*
control
,
const
char
*
src
)
const
char
*
sink
,
const
char
*
control
,
const
char
*
src
,
int
(
*
handler
)(
struct
snd_soc_dapm_widget
*
src
,
struct
snd_soc_dapm_widget
*
sink
))
{
route
->
sink
=
sink
;
route
->
source
=
src
;
route
->
control
=
control
;
route
->
connected
=
NULL
;
route
->
connected
=
handler
;
}
static
void
create_fill_widget_route_map
(
struct
snd_soc_dapm_context
*
dapm
,
struct
hdac_hdmi_
dai_pin_map
*
dai_map
)
static
struct
hdac_hdmi_pcm
*
hdac_hdmi_get_pcm
(
struct
hdac_ext_device
*
edev
,
struct
hdac_hdmi_
pin
*
pin
)
{
struct
snd_soc_dapm_route
route
[
1
]
;
struct
snd_soc_dapm_widget
widgets
[
2
]
=
{
{
0
}
}
;
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pcm
*
pcm
=
NULL
;
memset
(
&
route
,
0
,
sizeof
(
route
));
list_for_each_entry
(
pcm
,
&
hdmi
->
pcm_list
,
head
)
{
if
(
pcm
->
pin
==
pin
)
return
pcm
;
}
hdac_hdmi_fill_widget_info
(
&
widgets
[
0
],
snd_soc_dapm_output
,
"hif1 Output"
,
NULL
);
hdac_hdmi_fill_widget_info
(
&
widgets
[
1
],
snd_soc_dapm_aif_in
,
"Coverter 1"
,
"hif1"
);
return
NULL
;
}
hdac_hdmi_fill_route
(
&
route
[
0
],
"hif1 Output"
,
NULL
,
"Coverter 1"
);
/*
* Based on user selection, map the PINs with the PCMs.
*/
static
int
hdac_hdmi_set_pin_mux
(
struct
snd_kcontrol
*
kcontrol
,
struct
snd_ctl_elem_value
*
ucontrol
)
{
int
ret
;
struct
soc_enum
*
e
=
(
struct
soc_enum
*
)
kcontrol
->
private_value
;
struct
snd_soc_dapm_widget
*
w
=
snd_soc_dapm_kcontrol_widget
(
kcontrol
);
struct
snd_soc_dapm_context
*
dapm
=
w
->
dapm
;
struct
hdac_hdmi_pin
*
pin
=
w
->
priv
;
struct
hdac_ext_device
*
edev
=
to_hda_ext_device
(
dapm
->
dev
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pcm
*
pcm
=
NULL
;
const
char
*
cvt_name
=
e
->
texts
[
ucontrol
->
value
.
enumerated
.
item
[
0
]];
snd_soc_dapm_new_controls
(
dapm
,
widgets
,
ARRAY_SIZE
(
widgets
));
snd_soc_dapm_add_routes
(
dapm
,
route
,
ARRAY_SIZE
(
route
));
ret
=
snd_soc_dapm_put_enum_double
(
kcontrol
,
ucontrol
);
if
(
ret
<
0
)
return
ret
;
mutex_lock
(
&
hdmi
->
pin_mutex
);
list_for_each_entry
(
pcm
,
&
hdmi
->
pcm_list
,
head
)
{
if
(
pcm
->
pin
==
pin
)
pcm
->
pin
=
NULL
;
/*
* Jack status is not reported during device probe as the
* PCMs are not registered by then. So report it here.
*/
if
(
!
strcmp
(
cvt_name
,
pcm
->
cvt
->
name
)
&&
!
pcm
->
pin
)
{
pcm
->
pin
=
pin
;
if
(
pin
->
eld
.
monitor_present
&&
pin
->
eld
.
eld_valid
)
{
dev_dbg
(
&
edev
->
hdac
.
dev
,
"jack report for pcm=%d
\n
"
,
pcm
->
pcm_id
);
snd_jack_report
(
pcm
->
jack
,
SND_JACK_AVOUT
);
}
mutex_unlock
(
&
hdmi
->
pin_mutex
);
return
ret
;
}
}
mutex_unlock
(
&
hdmi
->
pin_mutex
);
return
ret
;
}
static
int
hdac_hdmi_init_dai_map
(
struct
hdac_ext_device
*
edev
)
/*
* Ideally the Mux inputs should be based on the num_muxs enumerated, but
* the display driver seem to be programming the connection list for the pin
* widget runtime.
*
* So programming all the possible inputs for the mux, the user has to take
* care of selecting the right one and leaving all other inputs selected to
* "NONE"
*/
static
int
hdac_hdmi_create_pin_muxs
(
struct
hdac_ext_device
*
edev
,
struct
hdac_hdmi_pin
*
pin
,
struct
snd_soc_dapm_widget
*
widget
,
const
char
*
widget_name
)
{
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_dai_pin_map
*
dai_map
=
&
hdmi
->
dai_map
[
0
];
struct
snd_kcontrol_new
*
kc
;
struct
hdac_hdmi_cvt
*
cvt
;
struct
soc_enum
*
se
;
char
kc_name
[
NAME_SIZE
];
char
mux_items
[
NAME_SIZE
];
/* To hold inputs to the Pin mux */
char
*
items
[
HDA_MAX_CONNECTIONS
];
int
i
=
0
;
int
num_items
=
hdmi
->
num_cvt
+
1
;
kc
=
devm_kzalloc
(
&
edev
->
hdac
.
dev
,
sizeof
(
*
kc
),
GFP_KERNEL
);
if
(
!
kc
)
return
-
ENOMEM
;
se
=
devm_kzalloc
(
&
edev
->
hdac
.
dev
,
sizeof
(
*
se
),
GFP_KERNEL
);
if
(
!
se
)
return
-
ENOMEM
;
sprintf
(
kc_name
,
"Pin %d Input"
,
pin
->
nid
);
kc
->
name
=
devm_kstrdup
(
&
edev
->
hdac
.
dev
,
kc_name
,
GFP_KERNEL
);
if
(
!
kc
->
name
)
return
-
ENOMEM
;
kc
->
private_value
=
(
long
)
se
;
kc
->
iface
=
SNDRV_CTL_ELEM_IFACE_MIXER
;
kc
->
access
=
0
;
kc
->
info
=
snd_soc_info_enum_double
;
kc
->
put
=
hdac_hdmi_set_pin_mux
;
kc
->
get
=
snd_soc_dapm_get_enum_double
;
se
->
reg
=
SND_SOC_NOPM
;
/* enum texts: ["NONE", "cvt #", "cvt #", ...] */
se
->
items
=
num_items
;
se
->
mask
=
roundup_pow_of_two
(
se
->
items
)
-
1
;
sprintf
(
mux_items
,
"NONE"
);
items
[
i
]
=
devm_kstrdup
(
&
edev
->
hdac
.
dev
,
mux_items
,
GFP_KERNEL
);
if
(
!
items
[
i
])
return
-
ENOMEM
;
list_for_each_entry
(
cvt
,
&
hdmi
->
cvt_list
,
head
)
{
i
++
;
sprintf
(
mux_items
,
"cvt %d"
,
cvt
->
nid
);
items
[
i
]
=
devm_kstrdup
(
&
edev
->
hdac
.
dev
,
mux_items
,
GFP_KERNEL
);
if
(
!
items
[
i
])
return
-
ENOMEM
;
}
se
->
texts
=
devm_kmemdup
(
&
edev
->
hdac
.
dev
,
items
,
(
num_items
*
sizeof
(
char
*
)),
GFP_KERNEL
);
if
(
!
se
->
texts
)
return
-
ENOMEM
;
return
hdac_hdmi_fill_widget_info
(
&
edev
->
hdac
.
dev
,
widget
,
snd_soc_dapm_mux
,
pin
,
widget_name
,
NULL
,
kc
,
1
);
}
/* Add cvt <- input <- mux route map */
static
void
hdac_hdmi_add_pinmux_cvt_route
(
struct
hdac_ext_device
*
edev
,
struct
snd_soc_dapm_widget
*
widgets
,
struct
snd_soc_dapm_route
*
route
,
int
rindex
)
{
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
const
struct
snd_kcontrol_new
*
kc
;
struct
soc_enum
*
se
;
int
mux_index
=
hdmi
->
num_cvt
+
hdmi
->
num_pin
;
int
i
,
j
;
for
(
i
=
0
;
i
<
hdmi
->
num_pin
;
i
++
)
{
kc
=
widgets
[
mux_index
].
kcontrol_news
;
se
=
(
struct
soc_enum
*
)
kc
->
private_value
;
for
(
j
=
0
;
j
<
hdmi
->
num_cvt
;
j
++
)
{
hdac_hdmi_fill_route
(
&
route
[
rindex
],
widgets
[
mux_index
].
name
,
se
->
texts
[
j
+
1
],
widgets
[
j
].
name
,
NULL
);
rindex
++
;
}
mux_index
++
;
}
}
/*
* Widgets are added in the below sequence
* Converter widgets for num converters enumerated
* Pin widgets for num pins enumerated
* Pin mux widgets to represent connenction list of pin widget
*
* Total widgets elements = num_cvt + num_pin + num_pin;
*
* Routes are added as below:
* pin mux -> pin (based on num_pins)
* cvt -> "Input sel control" -> pin_mux
*
* Total route elements:
* num_pins + (pin_muxes * num_cvt)
*/
static
int
create_fill_widget_route_map
(
struct
snd_soc_dapm_context
*
dapm
)
{
struct
snd_soc_dapm_widget
*
widgets
;
struct
snd_soc_dapm_route
*
route
;
struct
hdac_ext_device
*
edev
=
to_hda_ext_device
(
dapm
->
dev
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
snd_soc_dai_driver
*
dai_drv
=
dapm
->
component
->
dai_drv
;
char
widget_name
[
NAME_SIZE
];
struct
hdac_hdmi_cvt
*
cvt
;
struct
hdac_hdmi_pin
*
pin
;
int
ret
,
i
=
0
,
num_routes
=
0
;
if
(
list_empty
(
&
hdmi
->
cvt_list
)
||
list_empty
(
&
hdmi
->
pin_list
))
return
-
EINVAL
;
/*
* Currently on board only 1 pin and 1 converter is enabled for
* simplification, more will be added eventually
* So using fixed map for dai_id:pin:cvt
*/
cvt
=
list_first_entry
(
&
hdmi
->
cvt_list
,
struct
hdac_hdmi_cvt
,
head
);
pin
=
list_first_entry
(
&
hdmi
->
pin_list
,
struct
hdac_hdmi_pin
,
head
);
widgets
=
devm_kzalloc
(
dapm
->
dev
,
(
sizeof
(
*
widgets
)
*
((
2
*
hdmi
->
num_pin
)
+
hdmi
->
num_cvt
)),
GFP_KERNEL
);
dai_map
->
dai_id
=
0
;
dai_map
->
pin
=
pin
;
if
(
!
widgets
)
return
-
ENOMEM
;
dai_map
->
cvt
=
cvt
;
/* DAPM widgets to represent each converter widget */
list_for_each_entry
(
cvt
,
&
hdmi
->
cvt_list
,
head
)
{
sprintf
(
widget_name
,
"Converter %d"
,
cvt
->
nid
);
ret
=
hdac_hdmi_fill_widget_info
(
dapm
->
dev
,
&
widgets
[
i
],
snd_soc_dapm_aif_in
,
&
cvt
->
nid
,
widget_name
,
dai_drv
[
i
].
playback
.
stream_name
,
NULL
,
0
);
if
(
ret
<
0
)
return
ret
;
i
++
;
}
/* Enable out path for this pin widget */
snd_hdac_codec_write
(
&
edev
->
hdac
,
pin
->
nid
,
0
,
AC_VERB_SET_PIN_WIDGET_CONTROL
,
PIN_OUT
);
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
{
sprintf
(
widget_name
,
"hif%d Output"
,
pin
->
nid
);
ret
=
hdac_hdmi_fill_widget_info
(
dapm
->
dev
,
&
widgets
[
i
],
snd_soc_dapm_output
,
&
pin
->
nid
,
widget_name
,
NULL
,
NULL
,
0
);
if
(
ret
<
0
)
return
ret
;
i
++
;
}
/* Enable transmission */
snd_hdac_codec_write
(
&
edev
->
hdac
,
cvt
->
nid
,
0
,
AC_VERB_SET_DIGI_CONVERT_1
,
1
);
/* DAPM widgets to represent the connection list to pin widget */
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
{
sprintf
(
widget_name
,
"Pin %d Mux"
,
pin
->
nid
);
ret
=
hdac_hdmi_create_pin_muxs
(
edev
,
pin
,
&
widgets
[
i
],
widget_name
);
if
(
ret
<
0
)
return
ret
;
i
++
;
/* Category Code (CC) to zero */
snd_hdac_codec_write
(
&
edev
->
hdac
,
cvt
->
nid
,
0
,
AC_VERB_SET_DIGI_CONVERT_2
,
0
);
/* For cvt to pin_mux mapping */
num_routes
+=
hdmi
->
num_cvt
;
/* For pin_mux to pin mapping */
num_routes
++
;
}
snd_hdac_codec_write
(
&
edev
->
hdac
,
pin
->
nid
,
0
,
AC_VERB_SET_CONNECT_SEL
,
0
);
route
=
devm_kzalloc
(
dapm
->
dev
,
(
sizeof
(
*
route
)
*
num_routes
),
GFP_KERNEL
);
if
(
!
route
)
return
-
ENOMEM
;
i
=
0
;
/* Add pin <- NULL <- mux route map */
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
{
int
sink_index
=
i
+
hdmi
->
num_cvt
;
int
src_index
=
sink_index
+
hdmi
->
num_pin
;
hdac_hdmi_fill_route
(
&
route
[
i
],
widgets
[
sink_index
].
name
,
NULL
,
widgets
[
src_index
].
name
,
NULL
);
i
++
;
}
hdac_hdmi_add_pinmux_cvt_route
(
edev
,
widgets
,
route
,
i
);
snd_soc_dapm_new_controls
(
dapm
,
widgets
,
((
2
*
hdmi
->
num_pin
)
+
hdmi
->
num_cvt
));
snd_soc_dapm_add_routes
(
dapm
,
route
,
num_routes
);
snd_soc_dapm_new_widgets
(
dapm
->
card
);
return
0
;
}
static
int
hdac_hdmi_init_dai_map
(
struct
hdac_ext_device
*
edev
)
{
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_dai_pin_map
*
dai_map
;
struct
hdac_hdmi_cvt
*
cvt
;
int
dai_id
=
0
;
if
(
list_empty
(
&
hdmi
->
cvt_list
))
return
-
EINVAL
;
list_for_each_entry
(
cvt
,
&
hdmi
->
cvt_list
,
head
)
{
dai_map
=
&
hdmi
->
dai_map
[
dai_id
];
dai_map
->
dai_id
=
dai_id
;
dai_map
->
cvt
=
cvt
;
dai_id
++
;
if
(
dai_id
==
HDA_MAX_CVTS
)
{
dev_warn
(
&
edev
->
hdac
.
dev
,
"Max dais supported: %d
\n
"
,
dai_id
);
break
;
}
}
return
0
;
}
...
...
@@ -397,12 +993,15 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
{
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_cvt
*
cvt
;
char
name
[
NAME_SIZE
];
cvt
=
kzalloc
(
sizeof
(
*
cvt
),
GFP_KERNEL
);
if
(
!
cvt
)
return
-
ENOMEM
;
cvt
->
nid
=
nid
;
sprintf
(
name
,
"cvt %d"
,
cvt
->
nid
);
cvt
->
name
=
kstrdup
(
name
,
GFP_KERNEL
);
list_add_tail
(
&
cvt
->
head
,
&
hdmi
->
cvt_list
);
hdmi
->
num_cvt
++
;
...
...
@@ -410,6 +1009,106 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
return
hdac_hdmi_query_cvt_params
(
&
edev
->
hdac
,
cvt
);
}
static
void
hdac_hdmi_present_sense
(
struct
hdac_hdmi_pin
*
pin
,
int
repoll
)
{
struct
hdac_ext_device
*
edev
=
pin
->
edev
;
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pcm
*
pcm
;
int
val
;
pin
->
repoll_count
=
repoll
;
pm_runtime_get_sync
(
&
edev
->
hdac
.
dev
);
val
=
snd_hdac_codec_read
(
&
edev
->
hdac
,
pin
->
nid
,
0
,
AC_VERB_GET_PIN_SENSE
,
0
);
dev_dbg
(
&
edev
->
hdac
.
dev
,
"Pin sense val %x for pin: %d
\n
"
,
val
,
pin
->
nid
);
mutex_lock
(
&
hdmi
->
pin_mutex
);
pin
->
eld
.
monitor_present
=
!!
(
val
&
AC_PINSENSE_PRESENCE
);
pin
->
eld
.
eld_valid
=
!!
(
val
&
AC_PINSENSE_ELDV
);
pcm
=
hdac_hdmi_get_pcm
(
edev
,
pin
);
if
(
!
pin
->
eld
.
monitor_present
||
!
pin
->
eld
.
eld_valid
)
{
dev_dbg
(
&
edev
->
hdac
.
dev
,
"%s: disconnect for pin %d
\n
"
,
__func__
,
pin
->
nid
);
/*
* PCMs are not registered during device probe, so don't
* report jack here. It will be done in usermode mux
* control select.
*/
if
(
pcm
)
{
dev_dbg
(
&
edev
->
hdac
.
dev
,
"jack report for pcm=%d
\n
"
,
pcm
->
pcm_id
);
snd_jack_report
(
pcm
->
jack
,
0
);
}
mutex_unlock
(
&
hdmi
->
pin_mutex
);
goto
put_hdac_device
;
}
if
(
pin
->
eld
.
monitor_present
&&
pin
->
eld
.
eld_valid
)
{
/* TODO: use i915 component for reading ELD later */
if
(
hdac_hdmi_get_eld
(
&
edev
->
hdac
,
pin
->
nid
,
pin
->
eld
.
eld_buffer
,
&
pin
->
eld
.
eld_size
)
==
0
)
{
if
(
pcm
)
{
dev_dbg
(
&
edev
->
hdac
.
dev
,
"jack report for pcm=%d
\n
"
,
pcm
->
pcm_id
);
snd_jack_report
(
pcm
->
jack
,
SND_JACK_AVOUT
);
}
print_hex_dump_bytes
(
"ELD: "
,
DUMP_PREFIX_OFFSET
,
pin
->
eld
.
eld_buffer
,
pin
->
eld
.
eld_size
);
}
else
{
pin
->
eld
.
monitor_present
=
false
;
pin
->
eld
.
eld_valid
=
false
;
if
(
pcm
)
{
dev_dbg
(
&
edev
->
hdac
.
dev
,
"jack report for pcm=%d
\n
"
,
pcm
->
pcm_id
);
snd_jack_report
(
pcm
->
jack
,
0
);
}
}
}
mutex_unlock
(
&
hdmi
->
pin_mutex
);
/*
* Sometimes the pin_sense may present invalid monitor
* present and eld_valid. If ELD data is not valid, loop few
* more times to get correct pin sense and valid ELD.
*/
if
((
!
pin
->
eld
.
monitor_present
||
!
pin
->
eld
.
eld_valid
)
&&
repoll
)
schedule_delayed_work
(
&
pin
->
work
,
msecs_to_jiffies
(
300
));
put_hdac_device:
pm_runtime_put_sync
(
&
edev
->
hdac
.
dev
);
}
static
void
hdac_hdmi_repoll_eld
(
struct
work_struct
*
work
)
{
struct
hdac_hdmi_pin
*
pin
=
container_of
(
to_delayed_work
(
work
),
struct
hdac_hdmi_pin
,
work
);
/* picked from legacy HDA driver */
if
(
pin
->
repoll_count
++
>
6
)
pin
->
repoll_count
=
0
;
hdac_hdmi_present_sense
(
pin
,
pin
->
repoll_count
);
}
static
int
hdac_hdmi_add_pin
(
struct
hdac_ext_device
*
edev
,
hda_nid_t
nid
)
{
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
...
...
@@ -424,6 +1123,120 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
list_add_tail
(
&
pin
->
head
,
&
hdmi
->
pin_list
);
hdmi
->
num_pin
++
;
pin
->
edev
=
edev
;
INIT_DELAYED_WORK
(
&
pin
->
work
,
hdac_hdmi_repoll_eld
);
return
0
;
}
#define INTEL_VENDOR_NID 0x08
#define INTEL_GET_VENDOR_VERB 0xf81
#define INTEL_SET_VENDOR_VERB 0x781
#define INTEL_EN_DP12 0x02
/* enable DP 1.2 features */
#define INTEL_EN_ALL_PIN_CVTS 0x01
/* enable 2nd & 3rd pins and convertors */
static
void
hdac_hdmi_skl_enable_all_pins
(
struct
hdac_device
*
hdac
)
{
unsigned
int
vendor_param
;
vendor_param
=
snd_hdac_codec_read
(
hdac
,
INTEL_VENDOR_NID
,
0
,
INTEL_GET_VENDOR_VERB
,
0
);
if
(
vendor_param
==
-
1
||
vendor_param
&
INTEL_EN_ALL_PIN_CVTS
)
return
;
vendor_param
|=
INTEL_EN_ALL_PIN_CVTS
;
vendor_param
=
snd_hdac_codec_read
(
hdac
,
INTEL_VENDOR_NID
,
0
,
INTEL_SET_VENDOR_VERB
,
vendor_param
);
if
(
vendor_param
==
-
1
)
return
;
}
static
void
hdac_hdmi_skl_enable_dp12
(
struct
hdac_device
*
hdac
)
{
unsigned
int
vendor_param
;
vendor_param
=
snd_hdac_codec_read
(
hdac
,
INTEL_VENDOR_NID
,
0
,
INTEL_GET_VENDOR_VERB
,
0
);
if
(
vendor_param
==
-
1
||
vendor_param
&
INTEL_EN_DP12
)
return
;
/* enable DP1.2 mode */
vendor_param
|=
INTEL_EN_DP12
;
vendor_param
=
snd_hdac_codec_read
(
hdac
,
INTEL_VENDOR_NID
,
0
,
INTEL_SET_VENDOR_VERB
,
vendor_param
);
if
(
vendor_param
==
-
1
)
return
;
}
static
struct
snd_soc_dai_ops
hdmi_dai_ops
=
{
.
startup
=
hdac_hdmi_pcm_open
,
.
shutdown
=
hdac_hdmi_pcm_close
,
.
hw_params
=
hdac_hdmi_set_hw_params
,
.
prepare
=
hdac_hdmi_playback_prepare
,
.
trigger
=
hdac_hdmi_trigger
,
.
hw_free
=
hdac_hdmi_playback_cleanup
,
};
/*
* Each converter can support a stream independently. So a dai is created
* based on the number of converter queried.
*/
static
int
hdac_hdmi_create_dais
(
struct
hdac_device
*
hdac
,
struct
snd_soc_dai_driver
**
dais
,
struct
hdac_hdmi_priv
*
hdmi
,
int
num_dais
)
{
struct
snd_soc_dai_driver
*
hdmi_dais
;
struct
hdac_hdmi_cvt
*
cvt
;
char
name
[
NAME_SIZE
],
dai_name
[
NAME_SIZE
];
int
i
=
0
;
u32
rates
,
bps
;
unsigned
int
rate_max
=
384000
,
rate_min
=
8000
;
u64
formats
;
int
ret
;
hdmi_dais
=
devm_kzalloc
(
&
hdac
->
dev
,
(
sizeof
(
*
hdmi_dais
)
*
num_dais
),
GFP_KERNEL
);
if
(
!
hdmi_dais
)
return
-
ENOMEM
;
list_for_each_entry
(
cvt
,
&
hdmi
->
cvt_list
,
head
)
{
ret
=
snd_hdac_query_supported_pcm
(
hdac
,
cvt
->
nid
,
&
rates
,
&
formats
,
&
bps
);
if
(
ret
)
return
ret
;
sprintf
(
dai_name
,
"intel-hdmi-hifi%d"
,
i
+
1
);
hdmi_dais
[
i
].
name
=
devm_kstrdup
(
&
hdac
->
dev
,
dai_name
,
GFP_KERNEL
);
if
(
!
hdmi_dais
[
i
].
name
)
return
-
ENOMEM
;
snprintf
(
name
,
sizeof
(
name
),
"hifi%d"
,
i
+
1
);
hdmi_dais
[
i
].
playback
.
stream_name
=
devm_kstrdup
(
&
hdac
->
dev
,
name
,
GFP_KERNEL
);
if
(
!
hdmi_dais
[
i
].
playback
.
stream_name
)
return
-
ENOMEM
;
/*
* Set caps based on capability queried from the converter.
* It will be constrained runtime based on ELD queried.
*/
hdmi_dais
[
i
].
playback
.
formats
=
formats
;
hdmi_dais
[
i
].
playback
.
rates
=
rates
;
hdmi_dais
[
i
].
playback
.
rate_max
=
rate_max
;
hdmi_dais
[
i
].
playback
.
rate_min
=
rate_min
;
hdmi_dais
[
i
].
playback
.
channels_min
=
2
;
hdmi_dais
[
i
].
playback
.
channels_max
=
2
;
hdmi_dais
[
i
].
ops
=
&
hdmi_dai_ops
;
i
++
;
}
*
dais
=
hdmi_dais
;
return
0
;
}
...
...
@@ -431,7 +1244,8 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
* Parse all nodes and store the cvt/pin nids in array
* Add one time initialization for pin and cvt widgets
*/
static
int
hdac_hdmi_parse_and_map_nid
(
struct
hdac_ext_device
*
edev
)
static
int
hdac_hdmi_parse_and_map_nid
(
struct
hdac_ext_device
*
edev
,
struct
snd_soc_dai_driver
**
dais
,
int
*
num_dais
)
{
hda_nid_t
nid
;
int
i
,
num_nodes
;
...
...
@@ -439,6 +1253,9 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
int
ret
;
hdac_hdmi_skl_enable_all_pins
(
hdac
);
hdac_hdmi_skl_enable_dp12
(
hdac
);
num_nodes
=
snd_hdac_get_sub_nodes
(
hdac
,
hdac
->
afg
,
&
nid
);
if
(
!
nid
||
num_nodes
<=
0
)
{
dev_warn
(
&
hdac
->
dev
,
"HDMI: failed to get afg sub nodes
\n
"
);
...
...
@@ -479,19 +1296,107 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
if
(
!
hdmi
->
num_pin
||
!
hdmi
->
num_cvt
)
return
-
EIO
;
ret
=
hdac_hdmi_create_dais
(
hdac
,
dais
,
hdmi
,
hdmi
->
num_cvt
);
if
(
ret
)
{
dev_err
(
&
hdac
->
dev
,
"Failed to create dais with err: %d
\n
"
,
ret
);
return
ret
;
}
*
num_dais
=
hdmi
->
num_cvt
;
return
hdac_hdmi_init_dai_map
(
edev
);
}
static
void
hdac_hdmi_eld_notify_cb
(
void
*
aptr
,
int
port
)
{
struct
hdac_ext_device
*
edev
=
aptr
;
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pin
*
pin
;
struct
snd_soc_codec
*
codec
=
edev
->
scodec
;
/* Don't know how this mapping is derived */
hda_nid_t
pin_nid
=
port
+
0x04
;
dev_dbg
(
&
edev
->
hdac
.
dev
,
"%s: for pin: %d
\n
"
,
__func__
,
pin_nid
);
/*
* skip notification during system suspend (but not in runtime PM);
* the state will be updated at resume. Also since the ELD and
* connection states are updated in anyway at the end of the resume,
* we can skip it when received during PM process.
*/
if
(
snd_power_get_state
(
codec
->
component
.
card
->
snd_card
)
!=
SNDRV_CTL_POWER_D0
)
return
;
if
(
atomic_read
(
&
edev
->
hdac
.
in_pm
))
return
;
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
{
if
(
pin
->
nid
==
pin_nid
)
hdac_hdmi_present_sense
(
pin
,
1
);
}
}
static
struct
i915_audio_component_audio_ops
aops
=
{
.
pin_eld_notify
=
hdac_hdmi_eld_notify_cb
,
};
int
hdac_hdmi_jack_init
(
struct
snd_soc_dai
*
dai
,
int
device
)
{
char
jack_name
[
NAME_SIZE
];
struct
snd_soc_codec
*
codec
=
dai
->
codec
;
struct
hdac_ext_device
*
edev
=
snd_soc_codec_get_drvdata
(
codec
);
struct
snd_soc_dapm_context
*
dapm
=
snd_soc_component_get_dapm
(
&
codec
->
component
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pcm
*
pcm
;
/*
* this is a new PCM device, create new pcm and
* add to the pcm list
*/
pcm
=
kzalloc
(
sizeof
(
*
pcm
),
GFP_KERNEL
);
if
(
!
pcm
)
return
-
ENOMEM
;
pcm
->
pcm_id
=
device
;
pcm
->
cvt
=
hdmi
->
dai_map
[
dai
->
id
].
cvt
;
list_add_tail
(
&
pcm
->
head
,
&
hdmi
->
pcm_list
);
sprintf
(
jack_name
,
"HDMI/DP, pcm=%d Jack"
,
device
);
return
snd_jack_new
(
dapm
->
card
->
snd_card
,
jack_name
,
SND_JACK_AVOUT
,
&
pcm
->
jack
,
true
,
false
);
}
EXPORT_SYMBOL_GPL
(
hdac_hdmi_jack_init
);
static
int
hdmi_codec_probe
(
struct
snd_soc_codec
*
codec
)
{
struct
hdac_ext_device
*
edev
=
snd_soc_codec_get_drvdata
(
codec
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
snd_soc_dapm_context
*
dapm
=
snd_soc_component_get_dapm
(
&
codec
->
component
);
struct
hdac_hdmi_pin
*
pin
;
int
ret
;
edev
->
scodec
=
codec
;
create_fill_widget_route_map
(
dapm
,
&
hdmi
->
dai_map
[
0
]);
ret
=
create_fill_widget_route_map
(
dapm
);
if
(
ret
<
0
)
return
ret
;
aops
.
audio_ptr
=
edev
;
ret
=
snd_hdac_i915_register_notifier
(
&
aops
);
if
(
ret
<
0
)
{
dev_err
(
&
edev
->
hdac
.
dev
,
"notifier register failed: err: %d
\n
"
,
ret
);
return
ret
;
}
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
hdac_hdmi_present_sense
(
pin
,
1
);
/* Imp: Store the card pointer in hda_codec */
edev
->
card
=
dapm
->
card
->
snd_card
;
...
...
@@ -515,44 +1420,73 @@ static int hdmi_codec_remove(struct snd_soc_codec *codec)
return
0
;
}
#ifdef CONFIG_PM
static
int
hdmi_codec_resume
(
struct
snd_soc_codec
*
codec
)
{
struct
hdac_ext_device
*
edev
=
snd_soc_codec_get_drvdata
(
codec
);
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pin
*
pin
;
struct
hdac_device
*
hdac
=
&
edev
->
hdac
;
struct
hdac_bus
*
bus
=
hdac
->
bus
;
int
err
;
unsigned
long
timeout
;
hdac_hdmi_skl_enable_all_pins
(
&
edev
->
hdac
);
hdac_hdmi_skl_enable_dp12
(
&
edev
->
hdac
);
/* Power up afg */
if
(
!
snd_hdac_check_power_state
(
hdac
,
hdac
->
afg
,
AC_PWRST_D0
))
{
snd_hdac_codec_write
(
hdac
,
hdac
->
afg
,
0
,
AC_VERB_SET_POWER_STATE
,
AC_PWRST_D0
);
/* Wait till power state is set to D0 */
timeout
=
jiffies
+
msecs_to_jiffies
(
1000
);
while
(
!
snd_hdac_check_power_state
(
hdac
,
hdac
->
afg
,
AC_PWRST_D0
)
&&
time_before
(
jiffies
,
timeout
))
{
msleep
(
50
);
}
}
/*
* As the ELD notify callback request is not entertained while the
* device is in suspend state. Need to manually check detection of
* all pins here.
*/
list_for_each_entry
(
pin
,
&
hdmi
->
pin_list
,
head
)
hdac_hdmi_present_sense
(
pin
,
1
);
/*
* Codec power is turned ON during controller resume.
* Turn it OFF here
*/
err
=
snd_hdac_display_power
(
bus
,
false
);
if
(
err
<
0
)
{
dev_err
(
bus
->
dev
,
"Cannot turn OFF display power on i915, err: %d
\n
"
,
err
);
return
err
;
}
return
0
;
}
#else
#define hdmi_codec_resume NULL
#endif
static
struct
snd_soc_codec_driver
hdmi_hda_codec
=
{
.
probe
=
hdmi_codec_probe
,
.
remove
=
hdmi_codec_remove
,
.
resume
=
hdmi_codec_resume
,
.
idle_bias_off
=
true
,
};
static
struct
snd_soc_dai_ops
hdmi_dai_ops
=
{
.
startup
=
hdac_hdmi_pcm_open
,
.
shutdown
=
hdac_hdmi_pcm_close
,
.
hw_params
=
hdac_hdmi_set_hw_params
,
.
prepare
=
hdac_hdmi_playback_prepare
,
.
hw_free
=
hdac_hdmi_playback_cleanup
,
};
static
struct
snd_soc_dai_driver
hdmi_dais
[]
=
{
{
.
name
=
"intel-hdmi-hif1"
,
.
playback
=
{
.
stream_name
=
"hif1"
,
.
channels_min
=
2
,
.
channels_max
=
2
,
.
rates
=
SNDRV_PCM_RATE_32000
|
SNDRV_PCM_RATE_44100
|
SNDRV_PCM_RATE_48000
|
SNDRV_PCM_RATE_88200
|
SNDRV_PCM_RATE_96000
|
SNDRV_PCM_RATE_176400
|
SNDRV_PCM_RATE_192000
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
|
SNDRV_PCM_FMTBIT_S20_3LE
|
SNDRV_PCM_FMTBIT_S24_LE
|
SNDRV_PCM_FMTBIT_S32_LE
,
},
.
ops
=
&
hdmi_dai_ops
,
},
};
static
int
hdac_hdmi_dev_probe
(
struct
hdac_ext_device
*
edev
)
{
struct
hdac_device
*
codec
=
&
edev
->
hdac
;
struct
hdac_hdmi_priv
*
hdmi_priv
;
struct
snd_soc_dai_driver
*
hdmi_dais
=
NULL
;
int
num_dais
=
0
;
int
ret
=
0
;
hdmi_priv
=
devm_kzalloc
(
&
codec
->
dev
,
sizeof
(
*
hdmi_priv
),
GFP_KERNEL
);
...
...
@@ -565,14 +1499,31 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
INIT_LIST_HEAD
(
&
hdmi_priv
->
pin_list
);
INIT_LIST_HEAD
(
&
hdmi_priv
->
cvt_list
);
INIT_LIST_HEAD
(
&
hdmi_priv
->
pcm_list
);
mutex_init
(
&
hdmi_priv
->
pin_mutex
);
ret
=
hdac_hdmi_parse_and_map_nid
(
edev
);
if
(
ret
<
0
)
/*
* Turned off in the runtime_suspend during the first explicit
* pm_runtime_suspend call.
*/
ret
=
snd_hdac_display_power
(
edev
->
hdac
.
bus
,
true
);
if
(
ret
<
0
)
{
dev_err
(
&
edev
->
hdac
.
dev
,
"Cannot turn on display power on i915 err: %d
\n
"
,
ret
);
return
ret
;
}
ret
=
hdac_hdmi_parse_and_map_nid
(
edev
,
&
hdmi_dais
,
&
num_dais
);
if
(
ret
<
0
)
{
dev_err
(
&
codec
->
dev
,
"Failed in parse and map nid with err: %d
\n
"
,
ret
);
return
ret
;
}
/* ASoC specific initialization */
return
snd_soc_register_codec
(
&
codec
->
dev
,
&
hdmi_hda_codec
,
hdmi_dais
,
ARRAY_SIZE
(
hdmi_dais
)
);
hdmi_dais
,
num_dais
);
}
static
int
hdac_hdmi_dev_remove
(
struct
hdac_ext_device
*
edev
)
...
...
@@ -580,11 +1531,20 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
struct
hdac_hdmi_priv
*
hdmi
=
edev
->
private_data
;
struct
hdac_hdmi_pin
*
pin
,
*
pin_next
;
struct
hdac_hdmi_cvt
*
cvt
,
*
cvt_next
;
struct
hdac_hdmi_pcm
*
pcm
,
*
pcm_next
;
snd_soc_unregister_codec
(
&
edev
->
hdac
.
dev
);
list_for_each_entry_safe
(
pcm
,
pcm_next
,
&
hdmi
->
pcm_list
,
head
)
{
pcm
->
cvt
=
NULL
;
pcm
->
pin
=
NULL
;
list_del
(
&
pcm
->
head
);
kfree
(
pcm
);
}
list_for_each_entry_safe
(
cvt
,
cvt_next
,
&
hdmi
->
cvt_list
,
head
)
{
list_del
(
&
cvt
->
head
);
kfree
(
cvt
->
name
);
kfree
(
cvt
);
}
...
...
@@ -602,6 +1562,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
struct
hdac_ext_device
*
edev
=
to_hda_ext_device
(
dev
);
struct
hdac_device
*
hdac
=
&
edev
->
hdac
;
struct
hdac_bus
*
bus
=
hdac
->
bus
;
unsigned
long
timeout
;
int
err
;
dev_dbg
(
dev
,
"Enter: %s
\n
"
,
__func__
);
...
...
@@ -611,10 +1572,19 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
return
0
;
/* Power down afg */
if
(
!
snd_hdac_check_power_state
(
hdac
,
hdac
->
afg
,
AC_PWRST_D3
))
if
(
!
snd_hdac_check_power_state
(
hdac
,
hdac
->
afg
,
AC_PWRST_D3
))
{
snd_hdac_codec_write
(
hdac
,
hdac
->
afg
,
0
,
AC_VERB_SET_POWER_STATE
,
AC_PWRST_D3
);
/* Wait till power state is set to D3 */
timeout
=
jiffies
+
msecs_to_jiffies
(
1000
);
while
(
!
snd_hdac_check_power_state
(
hdac
,
hdac
->
afg
,
AC_PWRST_D3
)
&&
time_before
(
jiffies
,
timeout
))
{
msleep
(
50
);
}
}
err
=
snd_hdac_display_power
(
bus
,
false
);
if
(
err
<
0
)
{
dev_err
(
bus
->
dev
,
"Cannot turn on display power on i915
\n
"
);
...
...
@@ -643,6 +1613,9 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
return
err
;
}
hdac_hdmi_skl_enable_all_pins
(
&
edev
->
hdac
);
hdac_hdmi_skl_enable_dp12
(
&
edev
->
hdac
);
/* Power up afg */
if
(
!
snd_hdac_check_power_state
(
hdac
,
hdac
->
afg
,
AC_PWRST_D0
))
snd_hdac_codec_write
(
hdac
,
hdac
->
afg
,
0
,
...
...
@@ -661,6 +1634,7 @@ static const struct dev_pm_ops hdac_hdmi_pm = {
static
const
struct
hda_device_id
hdmi_list
[]
=
{
HDA_CODEC_EXT_ENTRY
(
0x80862809
,
0x100000
,
"Skylake HDMI"
,
0
),
HDA_CODEC_EXT_ENTRY
(
0x8086280a
,
0x100000
,
"Broxton HDMI"
,
0
),
{}
};
...
...
sound/soc/codecs/hdac_hdmi.h
0 → 100644
View file @
df91a210
#ifndef __HDAC_HDMI_H__
#define __HDAC_HDMI_H__
int
hdac_hdmi_jack_init
(
struct
snd_soc_dai
*
dai
,
int
pcm
);
#endif
/* __HDAC_HDMI_H__ */
sound/soc/intel/Kconfig
View file @
df91a210
...
...
@@ -163,6 +163,7 @@ config SND_SOC_INTEL_SKYLAKE
tristate
select SND_HDA_EXT_CORE
select SND_SOC_TOPOLOGY
select SND_HDA_I915
select SND_SOC_INTEL_SST
config SND_SOC_INTEL_SKL_RT286_MACH
...
...
@@ -172,6 +173,7 @@ config SND_SOC_INTEL_SKL_RT286_MACH
select SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT286
select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI
help
This adds support for ASoC machine driver for Skylake platforms
with RT286 I2S audio codec.
...
...
@@ -186,6 +188,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
select SND_SOC_NAU8825
select SND_SOC_SSM4567
select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI
help
This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for NAU88L25 + SSM4567.
...
...
@@ -200,6 +203,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
select SND_SOC_NAU8825
select SND_SOC_MAX98357A
select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI
help
This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for NAU88L25 + MAX98357A.
...
...
sound/soc/intel/atom/sst/sst_acpi.c
View file @
df91a210
...
...
@@ -342,6 +342,10 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
&
chv_platform_data
},
{
"193C9890"
,
"cht-bsw-max98090"
,
"intel/fw_sst_22a8.bin"
,
"cht-bsw"
,
NULL
,
&
chv_platform_data
},
/* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
{
"10EC5640"
,
"bytcr_rt5640"
,
"intel/fw_sst_22a8.bin"
,
"bytcr_rt5640"
,
NULL
,
&
chv_platform_data
},
{},
};
...
...
sound/soc/intel/atom/sst/sst_ipc.c
View file @
df91a210
...
...
@@ -318,7 +318,6 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx,
union
ipc_header_high
msg_high
;
u32
msg_low
;
struct
ipc_dsp_hdr
*
dsp_hdr
;
unsigned
int
cmd_id
;
msg_high
=
msg
->
mrfld_header
.
p
.
header_high
;
msg_low
=
msg
->
mrfld_header
.
p
.
header_low_payload
;
...
...
@@ -357,7 +356,6 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx,
return
;
/* Copy command id so that we can use to put sst to reset */
dsp_hdr
=
(
struct
ipc_dsp_hdr
*
)
data
;
cmd_id
=
dsp_hdr
->
cmd_id
;
dev_dbg
(
sst_drv_ctx
->
dev
,
"cmd_id %d
\n
"
,
dsp_hdr
->
cmd_id
);
if
(
sst_wake_up_block
(
sst_drv_ctx
,
msg_high
.
part
.
result
,
msg_high
.
part
.
drv_id
,
...
...
sound/soc/intel/boards/bytcr_rt5640.c
View file @
df91a210
...
...
@@ -32,6 +32,18 @@
#include "../atom/sst-atom-controls.h"
#include "../common/sst-acpi.h"
enum
{
BYT_RT5640_DMIC1_MAP
,
BYT_RT5640_DMIC2_MAP
,
BYT_RT5640_IN1_MAP
,
};
#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff)
#define BYT_RT5640_DMIC_EN BIT(16)
static
unsigned
long
byt_rt5640_quirk
=
BYT_RT5640_DMIC1_MAP
|
BYT_RT5640_DMIC_EN
;
static
const
struct
snd_soc_dapm_widget
byt_rt5640_widgets
[]
=
{
SND_SOC_DAPM_HP
(
"Headphone"
,
NULL
),
SND_SOC_DAPM_MIC
(
"Headset Mic"
,
NULL
),
...
...
@@ -70,18 +82,6 @@ static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
{
"IN1P"
,
NULL
,
"Internal Mic"
},
};
enum
{
BYT_RT5640_DMIC1_MAP
,
BYT_RT5640_DMIC2_MAP
,
BYT_RT5640_IN1_MAP
,
};
#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff)
#define BYT_RT5640_DMIC_EN BIT(16)
static
unsigned
long
byt_rt5640_quirk
=
BYT_RT5640_DMIC1_MAP
|
BYT_RT5640_DMIC_EN
;
static
const
struct
snd_kcontrol_new
byt_rt5640_controls
[]
=
{
SOC_DAPM_PIN_SWITCH
(
"Headphone"
),
SOC_DAPM_PIN_SWITCH
(
"Headset Mic"
),
...
...
@@ -174,7 +174,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
return
ret
;
}
dmi_check_system
(
byt_rt5640_quirk_table
);
switch
(
BYT_RT5640_MAP
(
byt_rt5640_quirk
))
{
case
BYT_RT5640_IN1_MAP
:
custom_map
=
byt_rt5640_intmic_in1_map
;
...
...
@@ -341,15 +340,34 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
{
int
ret_val
=
0
;
struct
sst_acpi_mach
*
mach
;
const
char
*
i2c_name
=
NULL
;
int
i
;
int
dai_index
;
/* register the soc card */
byt_rt5640_card
.
dev
=
&
pdev
->
dev
;
mach
=
byt_rt5640_card
.
dev
->
platform_data
;
/* fix index of codec dai */
dai_index
=
MERR_DPCM_COMPR
+
1
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
byt_rt5640_dais
);
i
++
)
{
if
(
!
strcmp
(
byt_rt5640_dais
[
i
].
codec_name
,
"i2c-10EC5640:00"
))
{
dai_index
=
i
;
break
;
}
}
/* fixup codec name based on HID */
snprintf
(
byt_rt5640_codec_name
,
sizeof
(
byt_rt5640_codec_name
),
"%s%s%s"
,
"i2c-"
,
mach
->
id
,
":00"
);
byt_rt5640_dais
[
MERR_DPCM_COMPR
+
1
].
codec_name
=
byt_rt5640_codec_name
;
i2c_name
=
sst_acpi_find_name_from_hid
(
mach
->
id
);
if
(
i2c_name
!=
NULL
)
{
snprintf
(
byt_rt5640_codec_name
,
sizeof
(
byt_rt5640_codec_name
),
"%s%s"
,
"i2c-"
,
i2c_name
);
byt_rt5640_dais
[
dai_index
].
codec_name
=
byt_rt5640_codec_name
;
}
/* check quirks before creating card */
dmi_check_system
(
byt_rt5640_quirk_table
);
ret_val
=
devm_snd_soc_register_card
(
&
pdev
->
dev
,
&
byt_rt5640_card
);
...
...
sound/soc/intel/boards/cht_bsw_max98090_ti.c
View file @
df91a210
...
...
@@ -287,33 +287,20 @@ static struct snd_soc_card snd_soc_card_cht = {
.
num_controls
=
ARRAY_SIZE
(
cht_mc_controls
),
};
static
acpi_status
snd_acpi_codec_match
(
acpi_handle
handle
,
u32
level
,
void
*
context
,
void
**
ret
)
{
*
(
bool
*
)
context
=
true
;
return
AE_OK
;
}
static
int
snd_cht_mc_probe
(
struct
platform_device
*
pdev
)
{
int
ret_val
=
0
;
bool
found
=
false
;
struct
cht_mc_private
*
drv
;
drv
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
drv
),
GFP_ATOMIC
);
if
(
!
drv
)
return
-
ENOMEM
;
if
(
ACPI_SUCCESS
(
acpi_get_devices
(
"104C227E"
,
snd_acpi_codec_match
,
&
found
,
NULL
))
&&
found
)
{
drv
->
ts3a227e_present
=
true
;
}
else
{
drv
->
ts3a227e_present
=
acpi_dev_present
(
"104C227E"
);
if
(
!
drv
->
ts3a227e_present
)
{
/* no need probe TI jack detection chip */
snd_soc_card_cht
.
aux_dev
=
NULL
;
snd_soc_card_cht
.
num_aux_devs
=
0
;
drv
->
ts3a227e_present
=
false
;
}
/* register the soc card */
...
...
sound/soc/intel/boards/cht_bsw_rt5645.c
View file @
df91a210
...
...
@@ -147,6 +147,17 @@ static const struct snd_kcontrol_new cht_mc_controls[] = {
SOC_DAPM_PIN_SWITCH
(
"Ext Spk"
),
};
static
struct
snd_soc_jack_pin
cht_bsw_jack_pins
[]
=
{
{
.
pin
=
"Headphone"
,
.
mask
=
SND_JACK_HEADPHONE
,
},
{
.
pin
=
"Headset Mic"
,
.
mask
=
SND_JACK_MICROPHONE
,
},
};
static
int
cht_aif1_hw_params
(
struct
snd_pcm_substream
*
substream
,
struct
snd_pcm_hw_params
*
params
)
{
...
...
@@ -202,9 +213,9 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
else
jack_type
=
SND_JACK_HEADPHONE
|
SND_JACK_MICROPHONE
;
ret
=
snd_soc_card_jack_new
(
runtime
->
card
,
"Headset
Jack
"
,
ret
=
snd_soc_card_jack_new
(
runtime
->
card
,
"Headset"
,
jack_type
,
&
ctx
->
jack
,
NULL
,
0
);
cht_bsw_jack_pins
,
ARRAY_SIZE
(
cht_bsw_jack_pins
)
);
if
(
ret
)
{
dev_err
(
runtime
->
dev
,
"Headset jack creation failed %d
\n
"
,
ret
);
return
ret
;
...
...
@@ -333,20 +344,12 @@ static struct cht_acpi_card snd_soc_cards[] = {
{
"10EC5650"
,
CODEC_TYPE_RT5650
,
&
snd_soc_card_chtrt5650
},
};
static
acpi_status
snd_acpi_codec_match
(
acpi_handle
handle
,
u32
level
,
void
*
context
,
void
**
ret
)
{
*
(
bool
*
)
context
=
true
;
return
AE_OK
;
}
static
int
snd_cht_mc_probe
(
struct
platform_device
*
pdev
)
{
int
ret_val
=
0
;
int
i
;
struct
cht_mc_private
*
drv
;
struct
snd_soc_card
*
card
=
snd_soc_cards
[
0
].
soc_card
;
bool
found
=
false
;
char
codec_name
[
16
];
drv
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
drv
),
GFP_ATOMIC
);
...
...
@@ -354,10 +357,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
return
-
ENOMEM
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
snd_soc_cards
);
i
++
)
{
if
(
ACPI_SUCCESS
(
acpi_get_devices
(
snd_soc_cards
[
i
].
codec_id
,
snd_acpi_codec_match
,
&
found
,
NULL
))
&&
found
)
{
if
(
acpi_dev_present
(
snd_soc_cards
[
i
].
codec_id
))
{
dev_dbg
(
&
pdev
->
dev
,
"found codec %s
\n
"
,
snd_soc_cards
[
i
].
codec_id
);
card
=
snd_soc_cards
[
i
].
soc_card
;
...
...
sound/soc/intel/boards/skl_nau88l25_max98357a.c
View file @
df91a210
...
...
@@ -22,6 +22,7 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "../../codecs/nau8825.h"
#include "../../codecs/hdac_hdmi.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
#define SKL_MAXIM_CODEC_DAI "HiFi"
...
...
@@ -29,6 +30,16 @@
static
struct
snd_soc_jack
skylake_headset
;
static
struct
snd_soc_card
skylake_audio_card
;
enum
{
SKL_DPCM_AUDIO_PB
=
0
,
SKL_DPCM_AUDIO_CP
,
SKL_DPCM_AUDIO_REF_CP
,
SKL_DPCM_AUDIO_DMIC_CP
,
SKL_DPCM_AUDIO_HDMI1_PB
,
SKL_DPCM_AUDIO_HDMI2_PB
,
SKL_DPCM_AUDIO_HDMI3_PB
,
};
static
inline
struct
snd_soc_dai
*
skl_get_codec_dai
(
struct
snd_soc_card
*
card
)
{
struct
snd_soc_pcm_runtime
*
rtd
;
...
...
@@ -87,7 +98,6 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
SND_SOC_DAPM_MIC
(
"Headset Mic"
,
NULL
),
SND_SOC_DAPM_SPK
(
"Spk"
,
NULL
),
SND_SOC_DAPM_MIC
(
"SoC DMIC"
,
NULL
),
SND_SOC_DAPM_SINK
(
"WoV Sink"
),
SND_SOC_DAPM_SPK
(
"DP"
,
NULL
),
SND_SOC_DAPM_SPK
(
"HDMI"
,
NULL
),
SND_SOC_DAPM_SUPPLY
(
"Platform Clock"
,
SND_SOC_NOPM
,
0
,
0
,
...
...
@@ -107,7 +117,6 @@ static const struct snd_soc_dapm_route skylake_map[] = {
{
"MIC"
,
NULL
,
"Headset Mic"
},
{
"DMic"
,
NULL
,
"SoC DMIC"
},
{
"WoV Sink"
,
NULL
,
"hwd_in sink"
},
{
"HDMI"
,
NULL
,
"hif5 Output"
},
{
"DP"
,
NULL
,
"hif6 Output"
},
...
...
@@ -124,8 +133,14 @@ static const struct snd_soc_dapm_route skylake_map[] = {
/* DMIC */
{
"dmic01_hifi"
,
NULL
,
"DMIC01 Rx"
},
{
"DMIC01 Rx"
,
NULL
,
"DMIC AIF"
},
{
"hifi1"
,
NULL
,
"iDisp Tx"
},
{
"iDisp Tx"
,
NULL
,
"iDisp_out"
},
{
"hifi3"
,
NULL
,
"iDisp3 Tx"
},
{
"iDisp3 Tx"
,
NULL
,
"iDisp3_out"
},
{
"hifi2"
,
NULL
,
"iDisp2 Tx"
},
{
"iDisp2 Tx"
,
NULL
,
"iDisp2_out"
},
{
"hifi1"
,
NULL
,
"iDisp1 Tx"
},
{
"iDisp1 Tx"
,
NULL
,
"iDisp1_out"
},
{
"Headphone Jack"
,
NULL
,
"Platform Clock"
},
{
"Headset Mic"
,
NULL
,
"Platform Clock"
},
};
...
...
@@ -171,11 +186,31 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
nau8825_enable_jack_detect
(
codec
,
&
skylake_headset
);
snd_soc_dapm_ignore_suspend
(
&
rtd
->
card
->
dapm
,
"SoC DMIC"
);
snd_soc_dapm_ignore_suspend
(
&
rtd
->
card
->
dapm
,
"WoV Sink"
);
return
ret
;
}
static
int
skylake_hdmi1_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
snd_soc_dai
*
dai
=
rtd
->
codec_dai
;
return
hdac_hdmi_jack_init
(
dai
,
SKL_DPCM_AUDIO_HDMI1_PB
);
}
static
int
skylake_hdmi2_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
snd_soc_dai
*
dai
=
rtd
->
codec_dai
;
return
hdac_hdmi_jack_init
(
dai
,
SKL_DPCM_AUDIO_HDMI2_PB
);
}
static
int
skylake_hdmi3_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
snd_soc_dai
*
dai
=
rtd
->
codec_dai
;
return
hdac_hdmi_jack_init
(
dai
,
SKL_DPCM_AUDIO_HDMI3_PB
);
}
static
int
skylake_nau8825_fe_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
snd_soc_dapm_context
*
dapm
;
...
...
@@ -318,7 +353,7 @@ static struct snd_soc_ops skylaye_refcap_ops = {
/* skylake digital audio interface glue - connects codec <--> CPU */
static
struct
snd_soc_dai_link
skylake_dais
[]
=
{
/* Front End DAI links */
{
[
SKL_DPCM_AUDIO_PB
]
=
{
.
name
=
"Skl Audio Port"
,
.
stream_name
=
"Audio"
,
.
cpu_dai_name
=
"System Pin"
,
...
...
@@ -333,7 +368,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.
dpcm_playback
=
1
,
.
ops
=
&
skylake_nau8825_fe_ops
,
},
{
[
SKL_DPCM_AUDIO_CP
]
=
{
.
name
=
"Skl Audio Capture Port"
,
.
stream_name
=
"Audio Record"
,
.
cpu_dai_name
=
"System Pin"
,
...
...
@@ -347,7 +382,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.
dpcm_capture
=
1
,
.
ops
=
&
skylake_nau8825_fe_ops
,
},
{
[
SKL_DPCM_AUDIO_REF_CP
]
=
{
.
name
=
"Skl Audio Reference cap"
,
.
stream_name
=
"Wake on Voice"
,
.
cpu_dai_name
=
"Reference Pin"
,
...
...
@@ -361,7 +396,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.
dynamic
=
1
,
.
ops
=
&
skylaye_refcap_ops
,
},
{
[
SKL_DPCM_AUDIO_DMIC_CP
]
=
{
.
name
=
"Skl Audio DMIC cap"
,
.
stream_name
=
"dmiccap"
,
.
cpu_dai_name
=
"DMIC Pin"
,
...
...
@@ -374,15 +409,45 @@ static struct snd_soc_dai_link skylake_dais[] = {
.
dynamic
=
1
,
.
ops
=
&
skylake_dmic_ops
,
},
{
.
name
=
"Skl HDMI Port"
,
.
stream_name
=
"Hdmi"
,
.
cpu_dai_name
=
"HDMI Pin"
,
[
SKL_DPCM_AUDIO_HDMI1_PB
]
=
{
.
name
=
"Skl HDMI Port1"
,
.
stream_name
=
"Hdmi1"
,
.
cpu_dai_name
=
"HDMI1 Pin"
,
.
codec_name
=
"snd-soc-dummy"
,
.
codec_dai_name
=
"snd-soc-dummy-dai"
,
.
platform_name
=
"0000:00:1f.3"
,
.
dpcm_playback
=
1
,
.
init
=
NULL
,
.
trigger
=
{
SND_SOC_DPCM_TRIGGER_POST
,
SND_SOC_DPCM_TRIGGER_POST
},
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
[
SKL_DPCM_AUDIO_HDMI2_PB
]
=
{
.
name
=
"Skl HDMI Port2"
,
.
stream_name
=
"Hdmi2"
,
.
cpu_dai_name
=
"HDMI2 Pin"
,
.
codec_name
=
"snd-soc-dummy"
,
.
codec_dai_name
=
"snd-soc-dummy-dai"
,
.
platform_name
=
"0000:00:1f.3"
,
.
dpcm_playback
=
1
,
.
init
=
NULL
,
.
trigger
=
{
SND_SOC_DPCM_TRIGGER_POST
,
SND_SOC_DPCM_TRIGGER_POST
},
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
[
SKL_DPCM_AUDIO_HDMI3_PB
]
=
{
.
name
=
"Skl HDMI Port3"
,
.
stream_name
=
"Hdmi3"
,
.
cpu_dai_name
=
"HDMI3 Pin"
,
.
codec_name
=
"snd-soc-dummy"
,
.
codec_dai_name
=
"snd-soc-dummy-dai"
,
.
platform_name
=
"0000:00:1f.3"
,
.
trigger
=
{
SND_SOC_DPCM_TRIGGER_POST
,
SND_SOC_DPCM_TRIGGER_POST
},
.
dpcm_playback
=
1
,
.
init
=
NULL
,
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
...
...
@@ -407,7 +472,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
{
/* SSP1 - Codec */
.
name
=
"SSP1-Codec"
,
.
be_id
=
0
,
.
be_id
=
1
,
.
cpu_dai_name
=
"SSP1 Pin"
,
.
platform_name
=
"0000:00:1f.3"
,
.
no_pcm
=
1
,
...
...
@@ -424,7 +489,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
},
{
.
name
=
"dmic01"
,
.
be_id
=
1
,
.
be_id
=
2
,
.
cpu_dai_name
=
"DMIC01 Pin"
,
.
codec_name
=
"dmic-codec"
,
.
codec_dai_name
=
"dmic-hifi"
,
...
...
@@ -435,13 +500,36 @@ static struct snd_soc_dai_link skylake_dais[] = {
.
no_pcm
=
1
,
},
{
.
name
=
"iDisp"
,
.
name
=
"iDisp
1
"
,
.
be_id
=
3
,
.
cpu_dai_name
=
"iDisp Pin"
,
.
cpu_dai_name
=
"iDisp
1
Pin"
,
.
codec_name
=
"ehdaudio0D2"
,
.
codec_dai_name
=
"intel-hdmi-hifi1"
,
.
platform_name
=
"0000:00:1f.3"
,
.
dpcm_playback
=
1
,
.
init
=
skylake_hdmi1_init
,
.
no_pcm
=
1
,
},
{
.
name
=
"iDisp2"
,
.
be_id
=
4
,
.
cpu_dai_name
=
"iDisp2 Pin"
,
.
codec_name
=
"ehdaudio0D2"
,
.
codec_dai_name
=
"intel-hdmi-hifi2"
,
.
platform_name
=
"0000:00:1f.3"
,
.
init
=
skylake_hdmi2_init
,
.
dpcm_playback
=
1
,
.
no_pcm
=
1
,
},
{
.
name
=
"iDisp3"
,
.
be_id
=
5
,
.
cpu_dai_name
=
"iDisp3 Pin"
,
.
codec_name
=
"ehdaudio0D2"
,
.
codec_dai_name
=
"intel-hdmi-hifi3"
,
.
platform_name
=
"0000:00:1f.3"
,
.
init
=
skylake_hdmi3_init
,
.
dpcm_playback
=
1
,
.
no_pcm
=
1
,
},
};
...
...
sound/soc/intel/boards/skl_nau88l25_ssm4567.c
View file @
df91a210
...
...
@@ -26,6 +26,7 @@
#include <sound/jack.h>
#include <sound/pcm_params.h>
#include "../../codecs/nau8825.h"
#include "../../codecs/hdac_hdmi.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
#define SKL_SSM_CODEC_DAI "ssm4567-hifi"
...
...
@@ -33,6 +34,16 @@
static
struct
snd_soc_jack
skylake_headset
;
static
struct
snd_soc_card
skylake_audio_card
;
enum
{
SKL_DPCM_AUDIO_PB
=
0
,
SKL_DPCM_AUDIO_CP
,
SKL_DPCM_AUDIO_REF_CP
,
SKL_DPCM_AUDIO_DMIC_CP
,
SKL_DPCM_AUDIO_HDMI1_PB
,
SKL_DPCM_AUDIO_HDMI2_PB
,
SKL_DPCM_AUDIO_HDMI3_PB
,
};
static
inline
struct
snd_soc_dai
*
skl_get_codec_dai
(
struct
snd_soc_card
*
card
)
{
struct
snd_soc_pcm_runtime
*
rtd
;
...
...
@@ -92,7 +103,6 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
SND_SOC_DAPM_SPK
(
"Left Speaker"
,
NULL
),
SND_SOC_DAPM_SPK
(
"Right Speaker"
,
NULL
),
SND_SOC_DAPM_MIC
(
"SoC DMIC"
,
NULL
),
SND_SOC_DAPM_SINK
(
"WoV Sink"
),
SND_SOC_DAPM_SPK
(
"DP"
,
NULL
),
SND_SOC_DAPM_SPK
(
"HDMI"
,
NULL
),
SND_SOC_DAPM_SUPPLY
(
"Platform Clock"
,
SND_SOC_NOPM
,
0
,
0
,
...
...
@@ -113,8 +123,6 @@ static const struct snd_soc_dapm_route skylake_map[] = {
{
"MIC"
,
NULL
,
"Headset Mic"
},
{
"DMic"
,
NULL
,
"SoC DMIC"
},
{
"WoV Sink"
,
NULL
,
"hwd_in sink"
},
{
"HDMI"
,
NULL
,
"hif5 Output"
},
{
"DP"
,
NULL
,
"hif6 Output"
},
/* CODEC BE connections */
...
...
@@ -122,6 +130,11 @@ static const struct snd_soc_dapm_route skylake_map[] = {
{
"Right Playback"
,
NULL
,
"ssp0 Tx"
},
{
"ssp0 Tx"
,
NULL
,
"codec0_out"
},
/* IV feedback path */
{
"codec0_lp_in"
,
NULL
,
"ssp0 Rx"
},
{
"ssp0 Rx"
,
NULL
,
"Left Capture Sense"
},
{
"ssp0 Rx"
,
NULL
,
"Right Capture Sense"
},
{
"Playback"
,
NULL
,
"ssp1 Tx"
},
{
"ssp1 Tx"
,
NULL
,
"codec1_out"
},
...
...
@@ -131,8 +144,14 @@ static const struct snd_soc_dapm_route skylake_map[] = {
/* DMIC */
{
"dmic01_hifi"
,
NULL
,
"DMIC01 Rx"
},
{
"DMIC01 Rx"
,
NULL
,
"DMIC AIF"
},
{
"hifi1"
,
NULL
,
"iDisp Tx"
},
{
"iDisp Tx"
,
NULL
,
"iDisp_out"
},
{
"hifi3"
,
NULL
,
"iDisp3 Tx"
},
{
"iDisp3 Tx"
,
NULL
,
"iDisp3_out"
},
{
"hifi2"
,
NULL
,
"iDisp2 Tx"
},
{
"iDisp2 Tx"
,
NULL
,
"iDisp2_out"
},
{
"hifi1"
,
NULL
,
"iDisp1 Tx"
},
{
"iDisp1 Tx"
,
NULL
,
"iDisp1_out"
},
{
"Headphone Jack"
,
NULL
,
"Platform Clock"
},
{
"Headset Mic"
,
NULL
,
"Platform Clock"
},
};
...
...
@@ -197,11 +216,32 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
nau8825_enable_jack_detect
(
codec
,
&
skylake_headset
);
snd_soc_dapm_ignore_suspend
(
&
rtd
->
card
->
dapm
,
"SoC DMIC"
);
snd_soc_dapm_ignore_suspend
(
&
rtd
->
card
->
dapm
,
"WoV Sink"
);
return
ret
;
}
static
int
skylake_hdmi1_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
snd_soc_dai
*
dai
=
rtd
->
codec_dai
;
return
hdac_hdmi_jack_init
(
dai
,
SKL_DPCM_AUDIO_HDMI1_PB
);
}
static
int
skylake_hdmi2_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
snd_soc_dai
*
dai
=
rtd
->
codec_dai
;
return
hdac_hdmi_jack_init
(
dai
,
SKL_DPCM_AUDIO_HDMI2_PB
);
}
static
int
skylake_hdmi3_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
snd_soc_dai
*
dai
=
rtd
->
codec_dai
;
return
hdac_hdmi_jack_init
(
dai
,
SKL_DPCM_AUDIO_HDMI3_PB
);
}
static
int
skylake_nau8825_fe_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
snd_soc_dapm_context
*
dapm
;
...
...
@@ -362,7 +402,7 @@ static struct snd_soc_ops skylaye_refcap_ops = {
/* skylake digital audio interface glue - connects codec <--> CPU */
static
struct
snd_soc_dai_link
skylake_dais
[]
=
{
/* Front End DAI links */
{
[
SKL_DPCM_AUDIO_PB
]
=
{
.
name
=
"Skl Audio Port"
,
.
stream_name
=
"Audio"
,
.
cpu_dai_name
=
"System Pin"
,
...
...
@@ -377,7 +417,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.
dpcm_playback
=
1
,
.
ops
=
&
skylake_nau8825_fe_ops
,
},
{
[
SKL_DPCM_AUDIO_CP
]
=
{
.
name
=
"Skl Audio Capture Port"
,
.
stream_name
=
"Audio Record"
,
.
cpu_dai_name
=
"System Pin"
,
...
...
@@ -391,7 +431,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.
dpcm_capture
=
1
,
.
ops
=
&
skylake_nau8825_fe_ops
,
},
{
[
SKL_DPCM_AUDIO_REF_CP
]
=
{
.
name
=
"Skl Audio Reference cap"
,
.
stream_name
=
"Wake on Voice"
,
.
cpu_dai_name
=
"Reference Pin"
,
...
...
@@ -405,7 +445,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.
dynamic
=
1
,
.
ops
=
&
skylaye_refcap_ops
,
},
{
[
SKL_DPCM_AUDIO_DMIC_CP
]
=
{
.
name
=
"Skl Audio DMIC cap"
,
.
stream_name
=
"dmiccap"
,
.
cpu_dai_name
=
"DMIC Pin"
,
...
...
@@ -418,13 +458,43 @@ static struct snd_soc_dai_link skylake_dais[] = {
.
dynamic
=
1
,
.
ops
=
&
skylake_dmic_ops
,
},
{
.
name
=
"Skl HDMI Port"
,
.
stream_name
=
"Hdmi"
,
.
cpu_dai_name
=
"HDMI Pin"
,
[
SKL_DPCM_AUDIO_HDMI1_PB
]
=
{
.
name
=
"Skl HDMI Port1"
,
.
stream_name
=
"Hdmi1"
,
.
cpu_dai_name
=
"HDMI1 Pin"
,
.
codec_name
=
"snd-soc-dummy"
,
.
codec_dai_name
=
"snd-soc-dummy-dai"
,
.
platform_name
=
"0000:00:1f.3"
,
.
dpcm_playback
=
1
,
.
init
=
NULL
,
.
trigger
=
{
SND_SOC_DPCM_TRIGGER_POST
,
SND_SOC_DPCM_TRIGGER_POST
},
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
[
SKL_DPCM_AUDIO_HDMI2_PB
]
=
{
.
name
=
"Skl HDMI Port2"
,
.
stream_name
=
"Hdmi2"
,
.
cpu_dai_name
=
"HDMI2 Pin"
,
.
codec_name
=
"snd-soc-dummy"
,
.
codec_dai_name
=
"snd-soc-dummy-dai"
,
.
platform_name
=
"0000:00:1f.3"
,
.
dpcm_playback
=
1
,
.
init
=
NULL
,
.
trigger
=
{
SND_SOC_DPCM_TRIGGER_POST
,
SND_SOC_DPCM_TRIGGER_POST
},
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
[
SKL_DPCM_AUDIO_HDMI3_PB
]
=
{
.
name
=
"Skl HDMI Port3"
,
.
stream_name
=
"Hdmi3"
,
.
cpu_dai_name
=
"HDMI3 Pin"
,
.
codec_name
=
"snd-soc-dummy"
,
.
codec_dai_name
=
"snd-soc-dummy-dai"
,
.
platform_name
=
"0000:00:1f.3"
,
.
trigger
=
{
SND_SOC_DPCM_TRIGGER_POST
,
SND_SOC_DPCM_TRIGGER_POST
},
.
dpcm_playback
=
1
,
.
init
=
NULL
,
.
nonatomic
=
1
,
...
...
@@ -448,11 +518,12 @@ static struct snd_soc_dai_link skylake_dais[] = {
.
ignore_pmdown_time
=
1
,
.
be_hw_params_fixup
=
skylake_ssp_fixup
,
.
dpcm_playback
=
1
,
.
dpcm_capture
=
1
,
},
{
/* SSP1 - Codec */
.
name
=
"SSP1-Codec"
,
.
be_id
=
0
,
.
be_id
=
1
,
.
cpu_dai_name
=
"SSP1 Pin"
,
.
platform_name
=
"0000:00:1f.3"
,
.
no_pcm
=
1
,
...
...
@@ -469,7 +540,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
},
{
.
name
=
"dmic01"
,
.
be_id
=
1
,
.
be_id
=
2
,
.
cpu_dai_name
=
"DMIC01 Pin"
,
.
codec_name
=
"dmic-codec"
,
.
codec_dai_name
=
"dmic-hifi"
,
...
...
@@ -480,13 +551,36 @@ static struct snd_soc_dai_link skylake_dais[] = {
.
no_pcm
=
1
,
},
{
.
name
=
"iDisp"
,
.
name
=
"iDisp
1
"
,
.
be_id
=
3
,
.
cpu_dai_name
=
"iDisp Pin"
,
.
cpu_dai_name
=
"iDisp
1
Pin"
,
.
codec_name
=
"ehdaudio0D2"
,
.
codec_dai_name
=
"intel-hdmi-hifi1"
,
.
platform_name
=
"0000:00:1f.3"
,
.
dpcm_playback
=
1
,
.
init
=
skylake_hdmi1_init
,
.
no_pcm
=
1
,
},
{
.
name
=
"iDisp2"
,
.
be_id
=
4
,
.
cpu_dai_name
=
"iDisp2 Pin"
,
.
codec_name
=
"ehdaudio0D2"
,
.
codec_dai_name
=
"intel-hdmi-hifi2"
,
.
platform_name
=
"0000:00:1f.3"
,
.
init
=
skylake_hdmi2_init
,
.
dpcm_playback
=
1
,
.
no_pcm
=
1
,
},
{
.
name
=
"iDisp3"
,
.
be_id
=
5
,
.
cpu_dai_name
=
"iDisp3 Pin"
,
.
codec_name
=
"ehdaudio0D2"
,
.
codec_dai_name
=
"intel-hdmi-hifi3"
,
.
platform_name
=
"0000:00:1f.3"
,
.
init
=
skylake_hdmi3_init
,
.
dpcm_playback
=
1
,
.
no_pcm
=
1
,
},
};
...
...
sound/soc/intel/boards/skl_rt286.c
View file @
df91a210
...
...
@@ -26,8 +26,20 @@
#include <sound/jack.h>
#include <sound/pcm_params.h>
#include "../../codecs/rt286.h"
#include "../../codecs/hdac_hdmi.h"
static
struct
snd_soc_jack
skylake_headset
;
enum
{
SKL_DPCM_AUDIO_PB
=
0
,
SKL_DPCM_AUDIO_CP
,
SKL_DPCM_AUDIO_REF_CP
,
SKL_DPCM_AUDIO_DMIC_CP
,
SKL_DPCM_AUDIO_HDMI1_PB
,
SKL_DPCM_AUDIO_HDMI2_PB
,
SKL_DPCM_AUDIO_HDMI3_PB
,
};
/* Headset jack detection DAPM pins */
static
struct
snd_soc_jack_pin
skylake_headset_pins
[]
=
{
{
...
...
@@ -52,7 +64,9 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
SND_SOC_DAPM_MIC
(
"Mic Jack"
,
NULL
),
SND_SOC_DAPM_MIC
(
"DMIC2"
,
NULL
),
SND_SOC_DAPM_MIC
(
"SoC DMIC"
,
NULL
),
SND_SOC_DAPM_SINK
(
"WoV Sink"
),
SND_SOC_DAPM_SPK
(
"HDMI1"
,
NULL
),
SND_SOC_DAPM_SPK
(
"HDMI2"
,
NULL
),
SND_SOC_DAPM_SPK
(
"HDMI3"
,
NULL
),
};
static
const
struct
snd_soc_dapm_route
skylake_rt286_map
[]
=
{
...
...
@@ -70,7 +84,9 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = {
{
"DMIC1 Pin"
,
NULL
,
"DMIC2"
},
{
"DMic"
,
NULL
,
"SoC DMIC"
},
{
"WoV Sink"
,
NULL
,
"hwd_in sink"
},
{
"HDMI1"
,
NULL
,
"hif5 Output"
},
{
"HDMI2"
,
NULL
,
"hif6 Output"
},
{
"HDMI3"
,
NULL
,
"hif7 Output"
},
/* CODEC BE connections */
{
"AIF1 Playback"
,
NULL
,
"ssp0 Tx"
},
...
...
@@ -84,8 +100,12 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = {
{
"dmic01_hifi"
,
NULL
,
"DMIC01 Rx"
},
{
"DMIC01 Rx"
,
NULL
,
"DMIC AIF"
},
{
"hif1"
,
NULL
,
"iDisp Tx"
},
{
"iDisp Tx"
,
NULL
,
"iDisp_out"
},
{
"hifi3"
,
NULL
,
"iDisp3 Tx"
},
{
"iDisp3 Tx"
,
NULL
,
"iDisp3_out"
},
{
"hifi2"
,
NULL
,
"iDisp2 Tx"
},
{
"iDisp2 Tx"
,
NULL
,
"iDisp2_out"
},
{
"hifi1"
,
NULL
,
"iDisp1 Tx"
},
{
"iDisp1 Tx"
,
NULL
,
"iDisp1_out"
},
};
...
...
@@ -116,11 +136,17 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
rt286_mic_detect
(
codec
,
&
skylake_headset
);
snd_soc_dapm_ignore_suspend
(
&
rtd
->
card
->
dapm
,
"SoC DMIC"
);
snd_soc_dapm_ignore_suspend
(
&
rtd
->
card
->
dapm
,
"WoV Sink"
);
return
0
;
}
static
int
skylake_hdmi_init
(
struct
snd_soc_pcm_runtime
*
rtd
)
{
struct
snd_soc_dai
*
dai
=
rtd
->
codec_dai
;
return
hdac_hdmi_jack_init
(
dai
,
SKL_DPCM_AUDIO_HDMI1_PB
+
dai
->
id
);
}
static
unsigned
int
rates
[]
=
{
48000
,
};
...
...
@@ -249,7 +275,7 @@ static struct snd_soc_ops skylake_dmic_ops = {
/* skylake digital audio interface glue - connects codec <--> CPU */
static
struct
snd_soc_dai_link
skylake_rt286_dais
[]
=
{
/* Front End DAI links */
{
[
SKL_DPCM_AUDIO_PB
]
=
{
.
name
=
"Skl Audio Port"
,
.
stream_name
=
"Audio"
,
.
cpu_dai_name
=
"System Pin"
,
...
...
@@ -266,7 +292,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.
dpcm_playback
=
1
,
.
ops
=
&
skylake_rt286_fe_ops
,
},
{
[
SKL_DPCM_AUDIO_CP
]
=
{
.
name
=
"Skl Audio Capture Port"
,
.
stream_name
=
"Audio Record"
,
.
cpu_dai_name
=
"System Pin"
,
...
...
@@ -282,7 +308,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.
dpcm_capture
=
1
,
.
ops
=
&
skylake_rt286_fe_ops
,
},
{
[
SKL_DPCM_AUDIO_REF_CP
]
=
{
.
name
=
"Skl Audio Reference cap"
,
.
stream_name
=
"refcap"
,
.
cpu_dai_name
=
"Reference Pin"
,
...
...
@@ -295,7 +321,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
{
[
SKL_DPCM_AUDIO_DMIC_CP
]
=
{
.
name
=
"Skl Audio DMIC cap"
,
.
stream_name
=
"dmiccap"
,
.
cpu_dai_name
=
"DMIC Pin"
,
...
...
@@ -308,6 +334,42 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.
dynamic
=
1
,
.
ops
=
&
skylake_dmic_ops
,
},
[
SKL_DPCM_AUDIO_HDMI1_PB
]
=
{
.
name
=
"Skl HDMI Port1"
,
.
stream_name
=
"Hdmi1"
,
.
cpu_dai_name
=
"HDMI1 Pin"
,
.
codec_name
=
"snd-soc-dummy"
,
.
codec_dai_name
=
"snd-soc-dummy-dai"
,
.
platform_name
=
"0000:00:1f.3"
,
.
dpcm_playback
=
1
,
.
init
=
NULL
,
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
[
SKL_DPCM_AUDIO_HDMI2_PB
]
=
{
.
name
=
"Skl HDMI Port2"
,
.
stream_name
=
"Hdmi2"
,
.
cpu_dai_name
=
"HDMI2 Pin"
,
.
codec_name
=
"snd-soc-dummy"
,
.
codec_dai_name
=
"snd-soc-dummy-dai"
,
.
platform_name
=
"0000:00:1f.3"
,
.
dpcm_playback
=
1
,
.
init
=
NULL
,
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
[
SKL_DPCM_AUDIO_HDMI3_PB
]
=
{
.
name
=
"Skl HDMI Port3"
,
.
stream_name
=
"Hdmi3"
,
.
cpu_dai_name
=
"HDMI3 Pin"
,
.
codec_name
=
"snd-soc-dummy"
,
.
codec_dai_name
=
"snd-soc-dummy-dai"
,
.
platform_name
=
"0000:00:1f.3"
,
.
dpcm_playback
=
1
,
.
init
=
NULL
,
.
nonatomic
=
1
,
.
dynamic
=
1
,
},
/* Back End DAI links */
{
...
...
@@ -341,6 +403,39 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.
dpcm_capture
=
1
,
.
no_pcm
=
1
,
},
{
.
name
=
"iDisp1"
,
.
be_id
=
2
,
.
cpu_dai_name
=
"iDisp1 Pin"
,
.
codec_name
=
"ehdaudio0D2"
,
.
codec_dai_name
=
"intel-hdmi-hifi1"
,
.
platform_name
=
"0000:00:1f.3"
,
.
init
=
skylake_hdmi_init
,
.
dpcm_playback
=
1
,
.
no_pcm
=
1
,
},
{
.
name
=
"iDisp2"
,
.
be_id
=
3
,
.
cpu_dai_name
=
"iDisp2 Pin"
,
.
codec_name
=
"ehdaudio0D2"
,
.
codec_dai_name
=
"intel-hdmi-hifi2"
,
.
platform_name
=
"0000:00:1f.3"
,
.
init
=
skylake_hdmi_init
,
.
dpcm_playback
=
1
,
.
no_pcm
=
1
,
},
{
.
name
=
"iDisp3"
,
.
be_id
=
4
,
.
cpu_dai_name
=
"iDisp3 Pin"
,
.
codec_name
=
"ehdaudio0D2"
,
.
codec_dai_name
=
"intel-hdmi-hifi3"
,
.
platform_name
=
"0000:00:1f.3"
,
.
init
=
skylake_hdmi_init
,
.
dpcm_playback
=
1
,
.
no_pcm
=
1
,
},
};
/* skylake audio machine driver for SPT + RT286S */
...
...
sound/soc/intel/common/sst-acpi.h
View file @
df91a210
...
...
@@ -14,6 +14,9 @@
#include <linux/acpi.h>
/* translation fron HID to I2C name, needed for DAI codec_name */
const
char
*
sst_acpi_find_name_from_hid
(
const
u8
hid
[
ACPI_ID_LEN
]);
/* acpi match */
struct
sst_acpi_mach
*
sst_acpi_find_machine
(
struct
sst_acpi_mach
*
machines
);
...
...
sound/soc/intel/common/sst-dsp-priv.h
View file @
df91a210
...
...
@@ -317,6 +317,7 @@ struct sst_dsp {
struct
skl_cl_dev
cl_dev
;
u32
intr_status
;
const
struct
firmware
*
fw
;
struct
snd_dma_buffer
dmab
;
};
/* Size optimised DRAM/IRAM memcpy */
...
...
sound/soc/intel/common/sst-match-acpi.c
View file @
df91a210
...
...
@@ -13,17 +13,53 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include "sst-acpi.h"
static
acpi_status
sst_acpi_find_name
(
acpi_handle
handle
,
u32
level
,
void
*
context
,
void
**
ret
)
{
struct
acpi_device
*
adev
;
const
char
*
name
=
NULL
;
if
(
acpi_bus_get_device
(
handle
,
&
adev
))
return
AE_OK
;
if
(
adev
->
status
.
present
&&
adev
->
status
.
functional
)
{
name
=
acpi_dev_name
(
adev
);
*
(
const
char
**
)
ret
=
name
;
return
AE_CTRL_TERMINATE
;
}
return
AE_OK
;
}
const
char
*
sst_acpi_find_name_from_hid
(
const
u8
hid
[
ACPI_ID_LEN
])
{
const
char
*
name
=
NULL
;
acpi_status
status
;
status
=
acpi_get_devices
(
hid
,
sst_acpi_find_name
,
NULL
,
(
void
**
)
&
name
);
if
(
ACPI_FAILURE
(
status
)
||
name
[
0
]
==
'\0'
)
return
NULL
;
return
name
;
}
EXPORT_SYMBOL_GPL
(
sst_acpi_find_name_from_hid
);
static
acpi_status
sst_acpi_mach_match
(
acpi_handle
handle
,
u32
level
,
void
*
context
,
void
**
ret
)
{
unsigned
long
long
sta
;
acpi_status
status
;
*
(
bool
*
)
context
=
true
;
status
=
acpi_evaluate_integer
(
handle
,
"_STA"
,
NULL
,
&
sta
);
if
(
ACPI_FAILURE
(
status
)
||
!
(
sta
&
ACPI_STA_DEVICE_PRESENT
))
*
(
bool
*
)
context
=
false
;
return
AE_OK
;
}
...
...
@@ -37,7 +73,6 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines)
sst_acpi_mach_match
,
&
found
,
NULL
))
&&
found
)
return
mach
;
return
NULL
;
}
EXPORT_SYMBOL_GPL
(
sst_acpi_find_machine
);
...
...
sound/soc/intel/skylake/skl-messages.c
View file @
df91a210
...
...
@@ -72,17 +72,47 @@ static void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable)
skl_ipc_set_large_config
(
&
ctx
->
ipc
,
&
msg
,
(
u32
*
)
&
mask
);
}
static
struct
skl_dsp_loader_ops
skl_get_loader_ops
(
void
)
{
struct
skl_dsp_loader_ops
loader_ops
;
memset
(
&
loader_ops
,
0
,
sizeof
(
struct
skl_dsp_loader_ops
));
loader_ops
.
alloc_dma_buf
=
skl_alloc_dma_buf
;
loader_ops
.
free_dma_buf
=
skl_free_dma_buf
;
return
loader_ops
;
};
static
const
struct
skl_dsp_ops
dsp_ops
[]
=
{
{
.
id
=
0x9d70
,
.
loader_ops
=
skl_get_loader_ops
,
.
init
=
skl_sst_dsp_init
,
.
cleanup
=
skl_sst_dsp_cleanup
},
};
static
int
skl_get_dsp_ops
(
int
pci_id
)
{
int
i
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
dsp_ops
);
i
++
)
{
if
(
dsp_ops
[
i
].
id
==
pci_id
)
return
i
;
}
return
-
EINVAL
;
}
int
skl_init_dsp
(
struct
skl
*
skl
)
{
void
__iomem
*
mmio_base
;
struct
hdac_ext_bus
*
ebus
=
&
skl
->
ebus
;
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
int
irq
=
bus
->
irq
;
struct
skl_dsp_loader_ops
loader_ops
;
int
ret
;
loader_ops
.
alloc_dma_buf
=
skl_alloc_dma_buf
;
loader_ops
.
free_dma_buf
=
skl_free_dma_buf
;
int
irq
=
bus
->
irq
;
int
ret
,
index
;
/* enable ppcap interrupt */
snd_hdac_ext_bus_ppcap_enable
(
&
skl
->
ebus
,
true
);
...
...
@@ -95,8 +125,14 @@ int skl_init_dsp(struct skl *skl)
return
-
ENXIO
;
}
ret
=
skl_sst_dsp_init
(
bus
->
dev
,
mmio_base
,
irq
,
index
=
skl_get_dsp_ops
(
skl
->
pci
->
device
);
if
(
index
<
0
)
return
-
EINVAL
;
loader_ops
=
dsp_ops
[
index
].
loader_ops
();
ret
=
dsp_ops
[
index
].
init
(
bus
->
dev
,
mmio_base
,
irq
,
skl
->
fw_name
,
loader_ops
,
&
skl
->
skl_sst
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -106,18 +142,26 @@ int skl_init_dsp(struct skl *skl)
return
ret
;
}
void
skl_free_dsp
(
struct
skl
*
skl
)
int
skl_free_dsp
(
struct
skl
*
skl
)
{
struct
hdac_ext_bus
*
ebus
=
&
skl
->
ebus
;
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
int
index
;
/* disable ppcap interrupt */
snd_hdac_ext_bus_ppcap_int_enable
(
&
skl
->
ebus
,
false
);
skl_sst_dsp_cleanup
(
bus
->
dev
,
ctx
);
index
=
skl_get_dsp_ops
(
skl
->
pci
->
device
);
if
(
index
<
0
)
return
-
EIO
;
dsp_ops
[
index
].
cleanup
(
bus
->
dev
,
ctx
);
if
(
ctx
->
dsp
->
addr
.
lpe
)
iounmap
(
ctx
->
dsp
->
addr
.
lpe
);
return
0
;
}
int
skl_suspend_dsp
(
struct
skl
*
skl
)
...
...
@@ -238,9 +282,8 @@ static void skl_copy_copier_caps(struct skl_module_cfg *mconfig,
* Calculate the gatewat settings required for copier module, type of
* gateway and index of gateway to use
*/
static
void
skl_setup_cpr_gateway_cfg
(
struct
skl_sst
*
ctx
,
struct
skl_module_cfg
*
mconfig
,
struct
skl_cpr_cfg
*
cpr_mconfig
)
static
u32
skl_get_node_id
(
struct
skl_sst
*
ctx
,
struct
skl_module_cfg
*
mconfig
)
{
union
skl_connector_node_id
node_id
=
{
0
};
union
skl_ssp_dma_node
ssp_node
=
{
0
};
...
...
@@ -289,13 +332,24 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
break
;
default:
cpr_mconfig
->
gtw_cfg
.
node_id
=
SKL_NON_GATEWAY_CPR_NODE_ID
;
node_id
.
val
=
0xFFFFFFFF
;
break
;
}
return
node_id
.
val
;
}
static
void
skl_setup_cpr_gateway_cfg
(
struct
skl_sst
*
ctx
,
struct
skl_module_cfg
*
mconfig
,
struct
skl_cpr_cfg
*
cpr_mconfig
)
{
cpr_mconfig
->
gtw_cfg
.
node_id
=
skl_get_node_id
(
ctx
,
mconfig
);
if
(
cpr_mconfig
->
gtw_cfg
.
node_id
==
SKL_NON_GATEWAY_CPR_NODE_ID
)
{
cpr_mconfig
->
cpr_feature_mask
=
0
;
return
;
}
cpr_mconfig
->
gtw_cfg
.
node_id
=
node_id
.
val
;
if
(
SKL_CONN_SOURCE
==
mconfig
->
hw_conn_type
)
cpr_mconfig
->
gtw_cfg
.
dma_buffer_size
=
2
*
mconfig
->
obs
;
else
...
...
@@ -307,6 +361,46 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
skl_copy_copier_caps
(
mconfig
,
cpr_mconfig
);
}
#define DMA_CONTROL_ID 5
int
skl_dsp_set_dma_control
(
struct
skl_sst
*
ctx
,
struct
skl_module_cfg
*
mconfig
)
{
struct
skl_dma_control
*
dma_ctrl
;
struct
skl_i2s_config_blob
config_blob
;
struct
skl_ipc_large_config_msg
msg
=
{
0
};
int
err
=
0
;
/*
* if blob size is same as capablity size, then no dma control
* present so return
*/
if
(
mconfig
->
formats_config
.
caps_size
==
sizeof
(
config_blob
))
return
0
;
msg
.
large_param_id
=
DMA_CONTROL_ID
;
msg
.
param_data_size
=
sizeof
(
struct
skl_dma_control
)
+
mconfig
->
formats_config
.
caps_size
;
dma_ctrl
=
kzalloc
(
msg
.
param_data_size
,
GFP_KERNEL
);
if
(
dma_ctrl
==
NULL
)
return
-
ENOMEM
;
dma_ctrl
->
node_id
=
skl_get_node_id
(
ctx
,
mconfig
);
/* size in dwords */
dma_ctrl
->
config_length
=
sizeof
(
config_blob
)
/
4
;
memcpy
(
dma_ctrl
->
config_data
,
mconfig
->
formats_config
.
caps
,
mconfig
->
formats_config
.
caps_size
);
err
=
skl_ipc_set_large_config
(
&
ctx
->
ipc
,
&
msg
,
(
u32
*
)
dma_ctrl
);
kfree
(
dma_ctrl
);
return
err
;
}
static
void
skl_setup_out_format
(
struct
skl_sst
*
ctx
,
struct
skl_module_cfg
*
mconfig
,
struct
skl_audio_data_format
*
out_fmt
)
...
...
sound/soc/intel/skylake/skl-nhlt.c
View file @
df91a210
...
...
@@ -145,3 +145,37 @@ struct nhlt_specific_cfg
return
NULL
;
}
static
void
skl_nhlt_trim_space
(
struct
skl
*
skl
)
{
char
*
s
=
skl
->
tplg_name
;
int
cnt
;
int
i
;
cnt
=
0
;
for
(
i
=
0
;
s
[
i
];
i
++
)
{
if
(
!
isspace
(
s
[
i
]))
s
[
cnt
++
]
=
s
[
i
];
}
s
[
cnt
]
=
'\0'
;
}
int
skl_nhlt_update_topology_bin
(
struct
skl
*
skl
)
{
struct
nhlt_acpi_table
*
nhlt
=
(
struct
nhlt_acpi_table
*
)
skl
->
nhlt
;
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
&
skl
->
ebus
);
struct
device
*
dev
=
bus
->
dev
;
dev_dbg
(
dev
,
"oem_id %.6s, oem_table_id %8s oem_revision %d
\n
"
,
nhlt
->
header
.
oem_id
,
nhlt
->
header
.
oem_table_id
,
nhlt
->
header
.
oem_revision
);
snprintf
(
skl
->
tplg_name
,
sizeof
(
skl
->
tplg_name
),
"%x-%.6s-%.8s-%d%s"
,
skl
->
pci_id
,
nhlt
->
header
.
oem_id
,
nhlt
->
header
.
oem_table_id
,
nhlt
->
header
.
oem_revision
,
"-tplg.bin"
);
skl_nhlt_trim_space
(
skl
);
return
0
;
}
sound/soc/intel/skylake/skl-pcm.c
View file @
df91a210
...
...
@@ -206,6 +206,23 @@ static int skl_get_format(struct snd_pcm_substream *substream,
return
format_val
;
}
static
int
skl_be_prepare
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
struct
skl
*
skl
=
get_skl_ctx
(
dai
->
dev
);
struct
skl_sst
*
ctx
=
skl
->
skl_sst
;
struct
skl_module_cfg
*
mconfig
;
if
((
dai
->
playback_active
>
1
)
||
(
dai
->
capture_active
>
1
))
return
0
;
mconfig
=
skl_tplg_be_get_cpr_module
(
dai
,
substream
->
stream
);
if
(
mconfig
==
NULL
)
return
-
EINVAL
;
return
skl_dsp_set_dma_control
(
ctx
,
mconfig
);
}
static
int
skl_pcm_prepare
(
struct
snd_pcm_substream
*
substream
,
struct
snd_soc_dai
*
dai
)
{
...
...
@@ -458,7 +475,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
struct
hdac_ext_bus
*
ebus
=
dev_get_drvdata
(
dai
->
dev
);
struct
hdac_ext_stream
*
link_dev
;
struct
snd_soc_pcm_runtime
*
rtd
=
snd_pcm_substream_chip
(
substream
);
struct
skl
_dma_params
*
dma_params
;
struct
hdac_ext
_dma_params
*
dma_params
;
struct
snd_soc_dai
*
codec_dai
=
rtd
->
codec_dai
;
struct
skl_pipe_params
p_params
=
{
0
};
...
...
@@ -470,11 +487,9 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
snd_soc_dai_set_dma_data
(
dai
,
substream
,
(
void
*
)
link_dev
);
/* set the stream tag in the codec dai dma params */
dma_params
=
(
struct
skl_dma_params
*
)
snd_soc_dai_get_dma_data
(
codec_dai
,
substream
);
dma_params
=
snd_soc_dai_get_dma_data
(
codec_dai
,
substream
);
if
(
dma_params
)
dma_params
->
stream_tag
=
hdac_stream
(
link_dev
)
->
stream_tag
;
snd_soc_dai_set_dma_data
(
codec_dai
,
substream
,
(
void
*
)
dma_params
);
p_params
.
s_fmt
=
snd_pcm_format_width
(
params_format
(
params
));
p_params
.
ch
=
params_channels
(
params
);
...
...
@@ -588,6 +603,7 @@ static struct snd_soc_dai_ops skl_dmic_dai_ops = {
static
struct
snd_soc_dai_ops
skl_be_ssp_dai_ops
=
{
.
hw_params
=
skl_be_hw_params
,
.
prepare
=
skl_be_prepare
,
};
static
struct
snd_soc_dai_ops
skl_link_dai_ops
=
{
...
...
@@ -660,6 +676,51 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
|
SNDRV_PCM_FMTBIT_S24_LE
,
},
},
{
.
name
=
"HDMI1 Pin"
,
.
ops
=
&
skl_pcm_dai_ops
,
.
playback
=
{
.
stream_name
=
"HDMI1 Playback"
,
.
channels_min
=
HDA_STEREO
,
.
channels_max
=
HDA_STEREO
,
.
rates
=
SNDRV_PCM_RATE_32000
|
SNDRV_PCM_RATE_44100
|
SNDRV_PCM_RATE_48000
|
SNDRV_PCM_RATE_88200
|
SNDRV_PCM_RATE_96000
|
SNDRV_PCM_RATE_176400
|
SNDRV_PCM_RATE_192000
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
|
SNDRV_PCM_FMTBIT_S24_LE
|
SNDRV_PCM_FMTBIT_S32_LE
,
},
},
{
.
name
=
"HDMI2 Pin"
,
.
ops
=
&
skl_pcm_dai_ops
,
.
playback
=
{
.
stream_name
=
"HDMI2 Playback"
,
.
channels_min
=
HDA_STEREO
,
.
channels_max
=
HDA_STEREO
,
.
rates
=
SNDRV_PCM_RATE_32000
|
SNDRV_PCM_RATE_44100
|
SNDRV_PCM_RATE_48000
|
SNDRV_PCM_RATE_88200
|
SNDRV_PCM_RATE_96000
|
SNDRV_PCM_RATE_176400
|
SNDRV_PCM_RATE_192000
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
|
SNDRV_PCM_FMTBIT_S24_LE
|
SNDRV_PCM_FMTBIT_S32_LE
,
},
},
{
.
name
=
"HDMI3 Pin"
,
.
ops
=
&
skl_pcm_dai_ops
,
.
playback
=
{
.
stream_name
=
"HDMI3 Playback"
,
.
channels_min
=
HDA_STEREO
,
.
channels_max
=
HDA_STEREO
,
.
rates
=
SNDRV_PCM_RATE_32000
|
SNDRV_PCM_RATE_44100
|
SNDRV_PCM_RATE_48000
|
SNDRV_PCM_RATE_88200
|
SNDRV_PCM_RATE_96000
|
SNDRV_PCM_RATE_176400
|
SNDRV_PCM_RATE_192000
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
|
SNDRV_PCM_FMTBIT_S24_LE
|
SNDRV_PCM_FMTBIT_S32_LE
,
},
},
/* BE CPU Dais */
{
...
...
@@ -699,14 +760,41 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
},
},
{
.
name
=
"iDisp Pin"
,
.
name
=
"iDisp
1
Pin"
,
.
ops
=
&
skl_link_dai_ops
,
.
playback
=
{
.
stream_name
=
"iDisp Tx"
,
.
stream_name
=
"iDisp
1
Tx"
,
.
channels_min
=
HDA_STEREO
,
.
channels_max
=
HDA_STEREO
,
.
rates
=
SNDRV_PCM_RATE_8000
|
SNDRV_PCM_RATE_16000
|
SNDRV_PCM_RATE_48000
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
|
SNDRV_PCM_FMTBIT_S32_LE
|
SNDRV_PCM_FMTBIT_S24_LE
,
},
},
{
.
name
=
"iDisp2 Pin"
,
.
ops
=
&
skl_link_dai_ops
,
.
playback
=
{
.
stream_name
=
"iDisp2 Tx"
,
.
channels_min
=
HDA_STEREO
,
.
channels_max
=
HDA_STEREO
,
.
rates
=
SNDRV_PCM_RATE_8000
|
SNDRV_PCM_RATE_16000
|
SNDRV_PCM_RATE_48000
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
|
SNDRV_PCM_FMTBIT_S32_LE
|
SNDRV_PCM_FMTBIT_S24_LE
,
},
},
{
.
name
=
"iDisp3 Pin"
,
.
ops
=
&
skl_link_dai_ops
,
.
playback
=
{
.
stream_name
=
"iDisp3 Tx"
,
.
channels_min
=
HDA_STEREO
,
.
channels_max
=
HDA_STEREO
,
.
rates
=
SNDRV_PCM_RATE_8000
|
SNDRV_PCM_RATE_16000
|
SNDRV_PCM_RATE_48000
,
.
formats
=
SNDRV_PCM_FMTBIT_S16_LE
|
SNDRV_PCM_FMTBIT_S32_LE
|
SNDRV_PCM_FMTBIT_S24_LE
,
},
},
{
...
...
@@ -863,7 +951,9 @@ static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus,
else
delay
+=
hstream
->
bufsize
;
}
delay
=
(
hstream
->
bufsize
==
delay
)
?
0
:
delay
;
if
(
hstream
->
bufsize
==
delay
)
delay
=
0
;
if
(
delay
>=
hstream
->
period_bytes
)
{
dev_info
(
bus
->
dev
,
...
...
sound/soc/intel/skylake/skl-sst-dsp.c
View file @
df91a210
...
...
@@ -34,7 +34,7 @@ void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state)
mutex_unlock
(
&
ctx
->
mutex
);
}
static
int
skl_dsp_core_set_reset_state
(
struct
sst_dsp
*
ctx
)
static
int
skl_dsp_core_set_reset_state
(
struct
sst_dsp
*
ctx
)
{
int
ret
;
...
...
@@ -60,7 +60,7 @@ static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx)
return
ret
;
}
static
int
skl_dsp_core_unset_reset_state
(
struct
sst_dsp
*
ctx
)
static
int
skl_dsp_core_unset_reset_state
(
struct
sst_dsp
*
ctx
)
{
int
ret
;
...
...
@@ -87,7 +87,7 @@ static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx)
return
ret
;
}
static
bool
is_skl_dsp_core_enable
(
struct
sst_dsp
*
ctx
)
static
bool
is_skl_dsp_core_enable
(
struct
sst_dsp
*
ctx
)
{
int
val
;
bool
is_enable
;
...
...
@@ -140,7 +140,7 @@ static int skl_dsp_start_core(struct sst_dsp *ctx)
return
ret
;
}
static
int
skl_dsp_core_power_up
(
struct
sst_dsp
*
ctx
)
static
int
skl_dsp_core_power_up
(
struct
sst_dsp
*
ctx
)
{
int
ret
;
...
...
@@ -166,7 +166,7 @@ static int skl_dsp_core_power_up(struct sst_dsp *ctx)
return
ret
;
}
static
int
skl_dsp_core_power_down
(
struct
sst_dsp
*
ctx
)
static
int
skl_dsp_core_power_down
(
struct
sst_dsp
*
ctx
)
{
/* update bits */
sst_dsp_shim_update_bits_unlocked
(
ctx
,
SKL_ADSP_REG_ADSPCS
,
...
...
@@ -181,7 +181,7 @@ static int skl_dsp_core_power_down(struct sst_dsp *ctx)
"Power down"
);
}
static
int
skl_dsp_enable_core
(
struct
sst_dsp
*
ctx
)
int
skl_dsp_enable_core
(
struct
sst_dsp
*
ctx
)
{
int
ret
;
...
...
@@ -195,7 +195,7 @@ static int skl_dsp_enable_core(struct sst_dsp *ctx)
return
skl_dsp_start_core
(
ctx
);
}
int
skl_dsp_disable_core
(
struct
sst_dsp
*
ctx
)
int
skl_dsp_disable_core
(
struct
sst_dsp
*
ctx
)
{
int
ret
;
...
...
sound/soc/intel/skylake/skl-sst-dsp.h
View file @
df91a210
...
...
@@ -53,6 +53,10 @@ struct sst_dsp_device;
/* HIPCT */
#define SKL_ADSP_REG_HIPCT_BUSY BIT(31)
/* FW base IDs */
#define SKL_INSTANCE_ID 0
#define SKL_BASE_FW_MODULE_ID 0
/* Intel HD Audio SRAM Window 1 */
#define SKL_ADSP_SRAM1_BASE 0xA000
...
...
@@ -144,7 +148,8 @@ int skl_cldma_prepare(struct sst_dsp *ctx);
void
skl_dsp_set_state_locked
(
struct
sst_dsp
*
ctx
,
int
state
);
struct
sst_dsp
*
skl_dsp_ctx_init
(
struct
device
*
dev
,
struct
sst_dsp_device
*
sst_dev
,
int
irq
);
int
skl_dsp_disable_core
(
struct
sst_dsp
*
ctx
);
int
skl_dsp_enable_core
(
struct
sst_dsp
*
ctx
);
int
skl_dsp_disable_core
(
struct
sst_dsp
*
ctx
);
bool
is_skl_dsp_running
(
struct
sst_dsp
*
ctx
);
irqreturn_t
skl_dsp_sst_interrupt
(
int
irq
,
void
*
dev_id
);
int
skl_dsp_wake
(
struct
sst_dsp
*
ctx
);
...
...
sound/soc/intel/skylake/skl-sst.c
View file @
df91a210
...
...
@@ -35,9 +35,6 @@
#define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE
#define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4)
#define SKL_INSTANCE_ID 0
#define SKL_BASE_FW_MODULE_ID 0
#define SKL_NUM_MODULES 1
static
bool
skl_check_fw_status
(
struct
sst_dsp
*
ctx
,
u32
status
)
...
...
sound/soc/intel/skylake/skl-topology.c
View file @
df91a210
...
...
@@ -260,6 +260,65 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
multiplier
;
}
static
int
skl_tplg_update_be_blob
(
struct
snd_soc_dapm_widget
*
w
,
struct
skl_sst
*
ctx
)
{
struct
skl_module_cfg
*
m_cfg
=
w
->
priv
;
int
link_type
,
dir
;
u32
ch
,
s_freq
,
s_fmt
;
struct
nhlt_specific_cfg
*
cfg
;
struct
skl
*
skl
=
get_skl_ctx
(
ctx
->
dev
);
/* check if we already have blob */
if
(
m_cfg
->
formats_config
.
caps_size
>
0
)
return
0
;
dev_dbg
(
ctx
->
dev
,
"Applying default cfg blob
\n
"
);
switch
(
m_cfg
->
dev_type
)
{
case
SKL_DEVICE_DMIC
:
link_type
=
NHLT_LINK_DMIC
;
dir
=
SNDRV_PCM_STREAM_CAPTURE
;
s_freq
=
m_cfg
->
in_fmt
[
0
].
s_freq
;
s_fmt
=
m_cfg
->
in_fmt
[
0
].
bit_depth
;
ch
=
m_cfg
->
in_fmt
[
0
].
channels
;
break
;
case
SKL_DEVICE_I2S
:
link_type
=
NHLT_LINK_SSP
;
if
(
m_cfg
->
hw_conn_type
==
SKL_CONN_SOURCE
)
{
dir
=
SNDRV_PCM_STREAM_PLAYBACK
;
s_freq
=
m_cfg
->
out_fmt
[
0
].
s_freq
;
s_fmt
=
m_cfg
->
out_fmt
[
0
].
bit_depth
;
ch
=
m_cfg
->
out_fmt
[
0
].
channels
;
}
else
{
dir
=
SNDRV_PCM_STREAM_CAPTURE
;
s_freq
=
m_cfg
->
in_fmt
[
0
].
s_freq
;
s_fmt
=
m_cfg
->
in_fmt
[
0
].
bit_depth
;
ch
=
m_cfg
->
in_fmt
[
0
].
channels
;
}
break
;
default:
return
-
EINVAL
;
}
/* update the blob based on virtual bus_id and default params */
cfg
=
skl_get_ep_blob
(
skl
,
m_cfg
->
vbus_id
,
link_type
,
s_fmt
,
ch
,
s_freq
,
dir
);
if
(
cfg
)
{
m_cfg
->
formats_config
.
caps_size
=
cfg
->
size
;
m_cfg
->
formats_config
.
caps
=
(
u32
*
)
&
cfg
->
caps
;
}
else
{
dev_err
(
ctx
->
dev
,
"Blob NULL for id %x type %d dirn %d
\n
"
,
m_cfg
->
vbus_id
,
link_type
,
dir
);
dev_err
(
ctx
->
dev
,
"PCM: ch %d, freq %d, fmt %d
\n
"
,
ch
,
s_freq
,
s_fmt
);
return
-
EIO
;
}
return
0
;
}
static
void
skl_tplg_update_module_params
(
struct
snd_soc_dapm_widget
*
w
,
struct
skl_sst
*
ctx
)
{
...
...
@@ -433,6 +492,9 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
return
ret
;
}
/* update blob if blob is null for be with default value */
skl_tplg_update_be_blob
(
w
,
ctx
);
/*
* apply fix/conversion to module params based on
* FE/BE params
...
...
@@ -545,6 +607,66 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
return
0
;
}
/*
* Some modules require params to be set after the module is bound to
* all pins connected.
*
* The module provider initializes set_param flag for such modules and we
* send params after binding
*/
static
int
skl_tplg_set_module_bind_params
(
struct
snd_soc_dapm_widget
*
w
,
struct
skl_module_cfg
*
mcfg
,
struct
skl_sst
*
ctx
)
{
int
i
,
ret
;
struct
skl_module_cfg
*
mconfig
=
w
->
priv
;
const
struct
snd_kcontrol_new
*
k
;
struct
soc_bytes_ext
*
sb
;
struct
skl_algo_data
*
bc
;
struct
skl_specific_cfg
*
sp_cfg
;
/*
* check all out/in pins are in bind state.
* if so set the module param
*/
for
(
i
=
0
;
i
<
mcfg
->
max_out_queue
;
i
++
)
{
if
(
mcfg
->
m_out_pin
[
i
].
pin_state
!=
SKL_PIN_BIND_DONE
)
return
0
;
}
for
(
i
=
0
;
i
<
mcfg
->
max_in_queue
;
i
++
)
{
if
(
mcfg
->
m_in_pin
[
i
].
pin_state
!=
SKL_PIN_BIND_DONE
)
return
0
;
}
if
(
mconfig
->
formats_config
.
caps_size
>
0
&&
mconfig
->
formats_config
.
set_params
==
SKL_PARAM_BIND
)
{
sp_cfg
=
&
mconfig
->
formats_config
;
ret
=
skl_set_module_params
(
ctx
,
sp_cfg
->
caps
,
sp_cfg
->
caps_size
,
sp_cfg
->
param_id
,
mconfig
);
if
(
ret
<
0
)
return
ret
;
}
for
(
i
=
0
;
i
<
w
->
num_kcontrols
;
i
++
)
{
k
=
&
w
->
kcontrol_news
[
i
];
if
(
k
->
access
&
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK
)
{
sb
=
(
void
*
)
k
->
private_value
;
bc
=
(
struct
skl_algo_data
*
)
sb
->
dobj
.
private
;
if
(
bc
->
set_params
==
SKL_PARAM_BIND
)
{
ret
=
skl_set_module_params
(
ctx
,
(
u32
*
)
bc
->
params
,
bc
->
max
,
bc
->
param_id
,
mconfig
);
if
(
ret
<
0
)
return
ret
;
}
}
}
return
0
;
}
static
int
skl_tplg_bind_sinks
(
struct
snd_soc_dapm_widget
*
w
,
struct
skl
*
skl
,
struct
snd_soc_dapm_widget
*
src_w
,
...
...
@@ -579,11 +701,19 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
sink
=
p
->
sink
;
sink_mconfig
=
sink
->
priv
;
if
(
src_mconfig
->
m_state
==
SKL_MODULE_UNINIT
||
sink_mconfig
->
m_state
==
SKL_MODULE_UNINIT
)
continue
;
/* Bind source to sink, mixin is always source */
ret
=
skl_bind_modules
(
ctx
,
src_mconfig
,
sink_mconfig
);
if
(
ret
)
return
ret
;
/* set module params after bind */
skl_tplg_set_module_bind_params
(
src_w
,
src_mconfig
,
ctx
);
skl_tplg_set_module_bind_params
(
sink
,
sink_mconfig
,
ctx
);
/* Start sinks pipe first */
if
(
sink_mconfig
->
pipe
->
state
!=
SKL_PIPE_STARTED
)
{
if
(
sink_mconfig
->
pipe
->
conn_type
!=
...
...
@@ -714,6 +844,10 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
if
(
ret
)
return
ret
;
/* set module params after bind */
skl_tplg_set_module_bind_params
(
source
,
src_mconfig
,
ctx
);
skl_tplg_set_module_bind_params
(
sink
,
sink_mconfig
,
ctx
);
if
(
sink_mconfig
->
pipe
->
conn_type
!=
SKL_PIPE_CONN_TYPE_FE
)
ret
=
skl_run_pipe
(
ctx
,
sink_mconfig
->
pipe
);
}
...
...
@@ -1091,6 +1225,66 @@ skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
return
NULL
;
}
static
struct
skl_module_cfg
*
skl_get_mconfig_pb_cpr
(
struct
snd_soc_dai
*
dai
,
struct
snd_soc_dapm_widget
*
w
)
{
struct
snd_soc_dapm_path
*
p
;
struct
skl_module_cfg
*
mconfig
=
NULL
;
snd_soc_dapm_widget_for_each_source_path
(
w
,
p
)
{
if
(
w
->
endpoints
[
SND_SOC_DAPM_DIR_OUT
]
>
0
)
{
if
(
p
->
connect
&&
(
p
->
sink
->
id
==
snd_soc_dapm_aif_out
)
&&
p
->
source
->
priv
)
{
mconfig
=
p
->
source
->
priv
;
return
mconfig
;
}
mconfig
=
skl_get_mconfig_pb_cpr
(
dai
,
p
->
source
);
if
(
mconfig
)
return
mconfig
;
}
}
return
mconfig
;
}
static
struct
skl_module_cfg
*
skl_get_mconfig_cap_cpr
(
struct
snd_soc_dai
*
dai
,
struct
snd_soc_dapm_widget
*
w
)
{
struct
snd_soc_dapm_path
*
p
;
struct
skl_module_cfg
*
mconfig
=
NULL
;
snd_soc_dapm_widget_for_each_sink_path
(
w
,
p
)
{
if
(
w
->
endpoints
[
SND_SOC_DAPM_DIR_IN
]
>
0
)
{
if
(
p
->
connect
&&
(
p
->
source
->
id
==
snd_soc_dapm_aif_in
)
&&
p
->
sink
->
priv
)
{
mconfig
=
p
->
sink
->
priv
;
return
mconfig
;
}
mconfig
=
skl_get_mconfig_cap_cpr
(
dai
,
p
->
sink
);
if
(
mconfig
)
return
mconfig
;
}
}
return
mconfig
;
}
struct
skl_module_cfg
*
skl_tplg_be_get_cpr_module
(
struct
snd_soc_dai
*
dai
,
int
stream
)
{
struct
snd_soc_dapm_widget
*
w
;
struct
skl_module_cfg
*
mconfig
;
if
(
stream
==
SNDRV_PCM_STREAM_PLAYBACK
)
{
w
=
dai
->
playback_widget
;
mconfig
=
skl_get_mconfig_pb_cpr
(
dai
,
w
);
}
else
{
w
=
dai
->
capture_widget
;
mconfig
=
skl_get_mconfig_cap_cpr
(
dai
,
w
);
}
return
mconfig
;
}
static
u8
skl_tplg_be_link_type
(
int
dev_type
)
{
int
ret
;
...
...
@@ -1464,8 +1658,7 @@ static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
if
(
!
ac
->
params
)
return
-
ENOMEM
;
if
(
dfw_ac
->
params
)
memcpy
(
ac
->
params
,
dfw_ac
->
params
,
ac
->
max
);
memcpy
(
ac
->
params
,
dfw_ac
->
params
,
ac
->
max
);
}
be
->
dobj
.
private
=
ac
;
...
...
@@ -1523,11 +1716,16 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
struct
skl
*
skl
=
ebus_to_skl
(
ebus
);
ret
=
request_firmware
(
&
fw
,
"dfw_sst.bin"
,
bus
->
dev
);
ret
=
request_firmware
(
&
fw
,
skl
->
tplg_name
,
bus
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
bus
->
dev
,
"tplg fw %s load failed with %d
\n
"
,
"dfw_sst.bin"
,
ret
);
return
ret
;
skl
->
tplg_name
,
ret
);
ret
=
request_firmware
(
&
fw
,
"dfw_sst.bin"
,
bus
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
bus
->
dev
,
"Fallback tplg fw %s load failed with %d
\n
"
,
"dfw_sst.bin"
,
ret
);
return
ret
;
}
}
/*
...
...
sound/soc/intel/skylake/skl-topology.h
View file @
df91a210
...
...
@@ -113,6 +113,29 @@ struct skl_cpr_gtw_cfg {
u32
config_data
[
1
];
}
__packed
;
struct
skl_i2s_config_blob
{
u32
gateway_attrib
;
u32
tdm_ts_group
[
8
];
u32
ssc0
;
u32
ssc1
;
u32
sscto
;
u32
sspsp
;
u32
sstsa
;
u32
ssrsa
;
u32
ssc2
;
u32
sspsp2
;
u32
ssc3
;
u32
ssioc
;
u32
mdivc
;
u32
mdivr
;
}
__packed
;
struct
skl_dma_control
{
u32
node_id
;
u32
config_length
;
u32
config_data
[
1
];
}
__packed
;
struct
skl_cpr_cfg
{
struct
skl_base_cfg
base_cfg
;
struct
skl_audio_data_format
out_fmt
;
...
...
@@ -313,6 +336,8 @@ static inline struct skl *get_skl_ctx(struct device *dev)
int
skl_tplg_be_update_params
(
struct
snd_soc_dai
*
dai
,
struct
skl_pipe_params
*
params
);
int
skl_dsp_set_dma_control
(
struct
skl_sst
*
ctx
,
struct
skl_module_cfg
*
mconfig
);
void
skl_tplg_set_be_dmic_config
(
struct
snd_soc_dai
*
dai
,
struct
skl_pipe_params
*
params
,
int
stream
);
int
skl_tplg_init
(
struct
snd_soc_platform
*
platform
,
...
...
@@ -345,5 +370,7 @@ int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size,
int
skl_get_module_params
(
struct
skl_sst
*
ctx
,
u32
*
params
,
int
size
,
u32
param_id
,
struct
skl_module_cfg
*
mcfg
);
struct
skl_module_cfg
*
skl_tplg_be_get_cpr_module
(
struct
snd_soc_dai
*
dai
,
int
stream
);
enum
skl_bitdepth
skl_get_bit_depth
(
int
params
);
#endif
sound/soc/intel/skylake/skl-tplg-interface.h
View file @
df91a210
...
...
@@ -144,7 +144,8 @@ enum module_pin_type {
enum
skl_module_param_type
{
SKL_PARAM_DEFAULT
=
0
,
SKL_PARAM_INIT
,
SKL_PARAM_SET
SKL_PARAM_SET
,
SKL_PARAM_BIND
};
struct
skl_dfw_module_pin
{
...
...
sound/soc/intel/skylake/skl.c
View file @
df91a210
...
...
@@ -28,6 +28,9 @@
#include <linux/firmware.h>
#include <sound/pcm.h>
#include "../common/sst-acpi.h"
#include <sound/hda_register.h>
#include <sound/hdaudio.h>
#include <sound/hda_i915.h>
#include "skl.h"
#include "skl-sst-dsp.h"
#include "skl-sst-ipc.h"
...
...
@@ -243,6 +246,16 @@ static int skl_resume(struct device *dev)
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
int
ret
;
/* Turned OFF in HDMI codec driver after codec reconfiguration */
if
(
IS_ENABLED
(
CONFIG_SND_SOC_HDAC_HDMI
))
{
ret
=
snd_hdac_display_power
(
bus
,
true
);
if
(
ret
<
0
)
{
dev_err
(
bus
->
dev
,
"Cannot turn on display power on i915
\n
"
);
return
ret
;
}
}
/*
* resume only when we are not in suspend active, otherwise need to
* restore the device
...
...
@@ -481,6 +494,27 @@ static int skl_create(struct pci_dev *pci,
return
0
;
}
static
int
skl_i915_init
(
struct
hdac_bus
*
bus
)
{
int
err
;
/*
* The HDMI codec is in GPU so we need to ensure that it is powered
* up and ready for probe
*/
err
=
snd_hdac_i915_init
(
bus
);
if
(
err
<
0
)
return
err
;
err
=
snd_hdac_display_power
(
bus
,
true
);
if
(
err
<
0
)
{
dev_err
(
bus
->
dev
,
"Cannot turn on display power on i915
\n
"
);
return
err
;
}
return
err
;
}
static
int
skl_first_init
(
struct
hdac_ext_bus
*
ebus
)
{
struct
skl
*
skl
=
ebus_to_skl
(
ebus
);
...
...
@@ -543,6 +577,12 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
/* initialize chip */
skl_init_pci
(
skl
);
if
(
IS_ENABLED
(
CONFIG_SND_SOC_HDAC_HDMI
))
{
err
=
skl_i915_init
(
bus
);
if
(
err
<
0
)
return
err
;
}
skl_init_chip
(
bus
,
true
);
/* codec detection */
...
...
@@ -573,11 +613,15 @@ static int skl_probe(struct pci_dev *pci,
if
(
err
<
0
)
goto
out_free
;
skl
->
pci_id
=
pci
->
device
;
skl
->
nhlt
=
skl_nhlt_init
(
bus
->
dev
);
if
(
skl
->
nhlt
==
NULL
)
goto
out_free
;
skl_nhlt_update_topology_bin
(
skl
);
pci_set_drvdata
(
skl
->
pci
,
ebus
);
/* check if dsp is there */
...
...
@@ -613,6 +657,14 @@ static int skl_probe(struct pci_dev *pci,
if
(
err
<
0
)
goto
out_unregister
;
if
(
IS_ENABLED
(
CONFIG_SND_SOC_HDAC_HDMI
))
{
err
=
snd_hdac_display_power
(
bus
,
false
);
if
(
err
<
0
)
{
dev_err
(
bus
->
dev
,
"Cannot turn off display power on i915
\n
"
);
return
err
;
}
}
/*configure PM */
pm_runtime_put_noidle
(
bus
->
dev
);
pm_runtime_allow
(
bus
->
dev
);
...
...
@@ -634,6 +686,31 @@ static int skl_probe(struct pci_dev *pci,
return
err
;
}
static
void
skl_shutdown
(
struct
pci_dev
*
pci
)
{
struct
hdac_ext_bus
*
ebus
=
pci_get_drvdata
(
pci
);
struct
hdac_bus
*
bus
=
ebus_to_hbus
(
ebus
);
struct
hdac_stream
*
s
;
struct
hdac_ext_stream
*
stream
;
struct
skl
*
skl
;
if
(
ebus
==
NULL
)
return
;
skl
=
ebus_to_skl
(
ebus
);
if
(
skl
->
init_failed
)
return
;
snd_hdac_ext_stop_streams
(
ebus
);
list_for_each_entry
(
s
,
&
bus
->
stream_list
,
list
)
{
stream
=
stream_to_hdac_ext_stream
(
s
);
snd_hdac_ext_stream_decouple
(
ebus
,
stream
,
false
);
}
snd_hdac_bus_stop_chip
(
bus
);
}
static
void
skl_remove
(
struct
pci_dev
*
pci
)
{
struct
hdac_ext_bus
*
ebus
=
pci_get_drvdata
(
pci
);
...
...
@@ -642,6 +719,9 @@ static void skl_remove(struct pci_dev *pci)
if
(
skl
->
tplg
)
release_firmware
(
skl
->
tplg
);
if
(
IS_ENABLED
(
CONFIG_SND_SOC_HDAC_HDMI
))
snd_hdac_i915_exit
(
&
ebus
->
bus
);
if
(
pci_dev_run_wake
(
pci
))
pm_runtime_get_noresume
(
&
pci
->
dev
);
pci_dev_put
(
pci
);
...
...
@@ -662,11 +742,18 @@ static struct sst_acpi_mach sst_skl_devdata[] = {
{}
};
static
struct
sst_acpi_mach
sst_bxtp_devdata
[]
=
{
{
"INT343A"
,
"bxt_alc298s_i2s"
,
"intel/dsp_fw_bxtn.bin"
,
NULL
,
NULL
,
NULL
},
};
/* PCI IDs */
static
const
struct
pci_device_id
skl_ids
[]
=
{
/* Sunrise Point-LP */
{
PCI_DEVICE
(
0x8086
,
0x9d70
),
.
driver_data
=
(
unsigned
long
)
&
sst_skl_devdata
},
/* BXT-P */
{
PCI_DEVICE
(
0x8086
,
0x5a98
),
.
driver_data
=
(
unsigned
long
)
&
sst_bxtp_devdata
},
{
0
,
}
};
MODULE_DEVICE_TABLE
(
pci
,
skl_ids
);
...
...
@@ -677,6 +764,7 @@ static struct pci_driver skl_driver = {
.
id_table
=
skl_ids
,
.
probe
=
skl_probe
,
.
remove
=
skl_remove
,
.
shutdown
=
skl_shutdown
,
.
driver
=
{
.
pm
=
&
skl_pm
,
},
...
...
sound/soc/intel/skylake/skl.h
View file @
df91a210
...
...
@@ -73,6 +73,8 @@ struct skl {
struct
list_head
ppl_list
;
const
char
*
fw_name
;
char
tplg_name
[
64
];
unsigned
short
pci_id
;
const
struct
firmware
*
tplg
;
int
supend_active
;
...
...
@@ -88,6 +90,16 @@ struct skl_dma_params {
u8
stream_tag
;
};
struct
skl_dsp_ops
{
int
id
;
struct
skl_dsp_loader_ops
(
*
loader_ops
)(
void
);
int
(
*
init
)(
struct
device
*
dev
,
void
__iomem
*
mmio_base
,
int
irq
,
const
char
*
fw_name
,
struct
skl_dsp_loader_ops
loader_ops
,
struct
skl_sst
**
skl_sst
);
void
(
*
cleanup
)(
struct
device
*
dev
,
struct
skl_sst
*
ctx
);
};
int
skl_platform_unregister
(
struct
device
*
dev
);
int
skl_platform_register
(
struct
device
*
dev
);
...
...
@@ -96,8 +108,9 @@ void skl_nhlt_free(void *addr);
struct
nhlt_specific_cfg
*
skl_get_ep_blob
(
struct
skl
*
skl
,
u32
instance
,
u8
link_type
,
u8
s_fmt
,
u8
no_ch
,
u32
s_rate
,
u8
dirn
);
int
skl_nhlt_update_topology_bin
(
struct
skl
*
skl
);
int
skl_init_dsp
(
struct
skl
*
skl
);
void
skl_free_dsp
(
struct
skl
*
skl
);
int
skl_free_dsp
(
struct
skl
*
skl
);
int
skl_suspend_dsp
(
struct
skl
*
skl
);
int
skl_resume_dsp
(
struct
skl
*
skl
);
#endif
/* __SOUND_SOC_SKL_H */
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