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
nexedi
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