Commit df91a210 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/intel' into asoc-next

parents a1eb3000 e2304803
...@@ -403,6 +403,18 @@ static inline int drm_eld_size(const uint8_t *eld) ...@@ -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; 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, struct edid *drm_do_get_edid(struct drm_connector *connector,
int (*get_edid_block)(void *data, u8 *buf, unsigned int block, int (*get_edid_block)(void *data, u8 *buf, unsigned int block,
size_t len), size_t len),
......
...@@ -490,6 +490,7 @@ config SND_SOC_GTM601 ...@@ -490,6 +490,7 @@ config SND_SOC_GTM601
config SND_SOC_HDAC_HDMI config SND_SOC_HDAC_HDMI
tristate tristate
select SND_HDA_EXT_CORE select SND_HDA_EXT_CORE
select SND_PCM_ELD
select HDMI select HDMI
config SND_SOC_ICS43432 config SND_SOC_ICS43432
......
...@@ -22,11 +22,17 @@ ...@@ -22,11 +22,17 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/hdmi.h> #include <linux/hdmi.h>
#include <drm/drm_edid.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/jack.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/hdaudio_ext.h> #include <sound/hdaudio_ext.h>
#include <sound/hda_i915.h> #include <sound/hda_i915.h>
#include <sound/pcm_drm_eld.h>
#include "../../hda/local.h" #include "../../hda/local.h"
#include "hdac_hdmi.h"
#define NAME_SIZE 32
#define AMP_OUT_MUTE 0xb080 #define AMP_OUT_MUTE 0xb080
#define AMP_OUT_UNMUTE 0xb000 #define AMP_OUT_UNMUTE 0xb000
...@@ -34,6 +40,11 @@ ...@@ -34,6 +40,11 @@
#define HDA_MAX_CONNECTIONS 32 #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 { struct hdac_hdmi_cvt_params {
unsigned int channels_min; unsigned int channels_min;
unsigned int channels_max; unsigned int channels_max;
...@@ -45,14 +56,34 @@ struct hdac_hdmi_cvt_params { ...@@ -45,14 +56,34 @@ struct hdac_hdmi_cvt_params {
struct hdac_hdmi_cvt { struct hdac_hdmi_cvt {
struct list_head head; struct list_head head;
hda_nid_t nid; hda_nid_t nid;
const char *name;
struct hdac_hdmi_cvt_params params; 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 hdac_hdmi_pin {
struct list_head head; struct list_head head;
hda_nid_t nid; hda_nid_t nid;
int num_mux_nids; int num_mux_nids;
hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; 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 { struct hdac_hdmi_dai_pin_map {
...@@ -62,11 +93,13 @@ struct hdac_hdmi_dai_pin_map { ...@@ -62,11 +93,13 @@ struct hdac_hdmi_dai_pin_map {
}; };
struct hdac_hdmi_priv { 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 pin_list;
struct list_head cvt_list; struct list_head cvt_list;
struct list_head pcm_list;
int num_pin; int num_pin;
int num_cvt; int num_cvt;
struct mutex pin_mutex;
}; };
static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) 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) ...@@ -76,6 +109,119 @@ static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
return to_ehdac_device(hdac); 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, static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac,
hda_nid_t cvt_nid, hda_nid_t pin_nid, hda_nid_t cvt_nid, hda_nid_t pin_nid,
u32 stream_tag, int format) u32 stream_tag, int format)
...@@ -107,27 +253,75 @@ hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid, ...@@ -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); 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, static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
hda_nid_t cvt_nid, hda_nid_t pin_nid) hda_nid_t cvt_nid, hda_nid_t pin_nid)
{ {
uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
struct hdmi_audio_infoframe frame; 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 ret;
int i; 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 */ eld_buf = pin->eld.eld_buffer;
frame.channels = 2; conn_type = drm_eld_get_conn_type(eld_buf);
/* setup channel count */ /* setup channel count */
snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, 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)); switch (conn_type) {
if (ret < 0) case DRM_ELD_CONN_TYPE_HDMI:
return ret; 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 */ /* stop infoframe transmission */
hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); 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, ...@@ -137,9 +331,15 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
/* Fill infoframe. Index auto-incremented */ /* Fill infoframe. Index auto-incremented */
hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
for (i = 0; i < sizeof(frame); i++) if (conn_type == DRM_ELD_CONN_TYPE_HDMI) {
snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 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]); AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
}
/* Start infoframe */ /* Start infoframe */
hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); 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, ...@@ -174,11 +374,6 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
struct hdac_ext_dma_params *dd; struct hdac_ext_dma_params *dd;
int ret; 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]; dai_map = &hdmi->dai_map[dai->id];
dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); 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, ...@@ -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 snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
{ {
struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(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; struct hdac_ext_dma_params *dd;
if (dai->id > 0) { dai_map = &hdmi->dai_map[dai->id];
dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); 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; return -ENODEV;
} }
dd = kzalloc(sizeof(*dd), GFP_KERNEL); dd = snd_soc_dai_get_dma_data(dai, substream);
if (!dd) if (!dd) {
return -ENOMEM; dd = kzalloc(sizeof(*dd), GFP_KERNEL);
if (!dd)
return -ENOMEM;
}
dd->format = snd_hdac_calc_stream_format(params_rate(hparams), dd->format = snd_hdac_calc_stream_format(params_rate(hparams),
params_channels(hparams), params_format(hparams), params_channels(hparams), params_format(hparams),
24, 0); 24, 0);
...@@ -227,50 +436,187 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, ...@@ -227,50 +436,187 @@ static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
dai_map = &hdmi->dai_map[dai->id]; 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, 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, 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); static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac,
snd_soc_dai_set_dma_data(dai, substream, NULL); 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; 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, static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
struct hdac_hdmi_priv *hdmi = hdac->private_data; struct hdac_hdmi_priv *hdmi = hdac->private_data;
struct hdac_hdmi_dai_pin_map *dai_map; struct hdac_hdmi_dai_pin_map *dai_map;
int val; struct hdac_hdmi_cvt *cvt;
struct hdac_hdmi_pin *pin;
if (dai->id > 0) { int ret;
dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
return -ENODEV;
}
dai_map = &hdmi->dai_map[dai->id]; dai_map = &hdmi->dai_map[dai->id];
val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin->nid, 0, cvt = dai_map->cvt;
AC_VERB_GET_PIN_SENSE, 0); pin = hdac_hdmi_get_pin_from_cvt(hdac, hdmi, cvt);
dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val);
if ((!(val & AC_PINSENSE_PRESENCE)) || (!(val & AC_PINSENSE_ELDV))) { /*
dev_err(&hdac->hdac.dev, "Monitor presence invalid with val: %x\n", val); * To make PA and other userland happy.
return -ENODEV; * 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, hdac_hdmi_enable_cvt(hdac, dai_map);
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); ret = hdac_hdmi_enable_pin(hdac, dai_map);
if (ret < 0)
return ret;
snd_pcm_hw_constraint_step(substream->runtime, 0, ret = hdac_hdmi_eld_limit_formats(substream->runtime,
SNDRV_PCM_HW_PARAM_CHANNELS, 2); 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; return 0;
} }
...@@ -284,10 +630,19 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, ...@@ -284,10 +630,19 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
dai_map = &hdmi->dai_map[dai->id]; 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); AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
dai_map->pin = NULL;
}
} }
static int static int
...@@ -310,85 +665,326 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) ...@@ -310,85 +665,326 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
return err; return err;
} }
static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w, static int hdac_hdmi_fill_widget_info(struct device *dev,
enum snd_soc_dapm_type id, struct snd_soc_dapm_widget *w,
const char *wname, const char *stream) 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->id = id;
w->name = wname; w->name = devm_kstrdup(dev, wname, GFP_KERNEL);
if (!w->name)
return -ENOMEM;
w->sname = stream; w->sname = stream;
w->reg = SND_SOC_NOPM; w->reg = SND_SOC_NOPM;
w->shift = 0; w->shift = 0;
w->kcontrol_news = NULL; w->kcontrol_news = wc;
w->num_kcontrols = 0; w->num_kcontrols = numkc;
w->priv = NULL; w->priv = priv;
return 0;
} }
static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, 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->sink = sink;
route->source = src; route->source = src;
route->control = control; route->control = control;
route->connected = NULL; route->connected = handler;
} }
static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm, static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev,
struct hdac_hdmi_dai_pin_map *dai_map) struct hdac_hdmi_pin *pin)
{ {
struct snd_soc_dapm_route route[1]; struct hdac_hdmi_priv *hdmi = edev->private_data;
struct snd_soc_dapm_widget widgets[2] = { {0} }; 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, return NULL;
"hif1 Output", NULL); }
hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in,
"Coverter 1", "hif1");
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)); ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route)); 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_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_cvt *cvt;
struct hdac_hdmi_pin *pin; struct hdac_hdmi_pin *pin;
int ret, i = 0, num_routes = 0;
if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
return -EINVAL; return -EINVAL;
/* widgets = devm_kzalloc(dapm->dev,
* Currently on board only 1 pin and 1 converter is enabled for (sizeof(*widgets) * ((2 * hdmi->num_pin) + hdmi->num_cvt)),
* simplification, more will be added eventually GFP_KERNEL);
* 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);
dai_map->dai_id = 0; if (!widgets)
dai_map->pin = pin; 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 */ list_for_each_entry(pin, &hdmi->pin_list, head) {
snd_hdac_codec_write(&edev->hdac, pin->nid, 0, sprintf(widget_name, "hif%d Output", pin->nid);
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); 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 */ /* DAPM widgets to represent the connection list to pin widget */
snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, list_for_each_entry(pin, &hdmi->pin_list, head) {
AC_VERB_SET_DIGI_CONVERT_1, 1); 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 */ /* For cvt to pin_mux mapping */
snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, num_routes += hdmi->num_cvt;
AC_VERB_SET_DIGI_CONVERT_2, 0);
/* For pin_mux to pin mapping */
num_routes++;
}
snd_hdac_codec_write(&edev->hdac, pin->nid, 0, route = devm_kzalloc(dapm->dev, (sizeof(*route) * num_routes),
AC_VERB_SET_CONNECT_SEL, 0); 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; return 0;
} }
...@@ -397,12 +993,15 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) ...@@ -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_priv *hdmi = edev->private_data;
struct hdac_hdmi_cvt *cvt; struct hdac_hdmi_cvt *cvt;
char name[NAME_SIZE];
cvt = kzalloc(sizeof(*cvt), GFP_KERNEL); cvt = kzalloc(sizeof(*cvt), GFP_KERNEL);
if (!cvt) if (!cvt)
return -ENOMEM; return -ENOMEM;
cvt->nid = nid; cvt->nid = nid;
sprintf(name, "cvt %d", cvt->nid);
cvt->name = kstrdup(name, GFP_KERNEL);
list_add_tail(&cvt->head, &hdmi->cvt_list); list_add_tail(&cvt->head, &hdmi->cvt_list);
hdmi->num_cvt++; hdmi->num_cvt++;
...@@ -410,6 +1009,106 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) ...@@ -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); 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) static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
{ {
struct hdac_hdmi_priv *hdmi = edev->private_data; 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) ...@@ -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); list_add_tail(&pin->head, &hdmi->pin_list);
hdmi->num_pin++; 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; return 0;
} }
...@@ -431,7 +1244,8 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) ...@@ -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 * Parse all nodes and store the cvt/pin nids in array
* Add one time initialization for pin and cvt widgets * 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; hda_nid_t nid;
int i, num_nodes; int i, num_nodes;
...@@ -439,6 +1253,9 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) ...@@ -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; struct hdac_hdmi_priv *hdmi = edev->private_data;
int ret; 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); num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid);
if (!nid || num_nodes <= 0) { if (!nid || num_nodes <= 0) {
dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n"); 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) ...@@ -479,19 +1296,107 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev)
if (!hdmi->num_pin || !hdmi->num_cvt) if (!hdmi->num_pin || !hdmi->num_cvt)
return -EIO; 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); 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) static int hdmi_codec_probe(struct snd_soc_codec *codec)
{ {
struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
struct hdac_hdmi_priv *hdmi = edev->private_data; struct hdac_hdmi_priv *hdmi = edev->private_data;
struct snd_soc_dapm_context *dapm = struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(&codec->component); snd_soc_component_get_dapm(&codec->component);
struct hdac_hdmi_pin *pin;
int ret;
edev->scodec = codec; 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 */ /* Imp: Store the card pointer in hda_codec */
edev->card = dapm->card->snd_card; edev->card = dapm->card->snd_card;
...@@ -515,44 +1420,73 @@ static int hdmi_codec_remove(struct snd_soc_codec *codec) ...@@ -515,44 +1420,73 @@ static int hdmi_codec_remove(struct snd_soc_codec *codec)
return 0; 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 = { static struct snd_soc_codec_driver hdmi_hda_codec = {
.probe = hdmi_codec_probe, .probe = hdmi_codec_probe,
.remove = hdmi_codec_remove, .remove = hdmi_codec_remove,
.resume = hdmi_codec_resume,
.idle_bias_off = true, .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) static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
{ {
struct hdac_device *codec = &edev->hdac; struct hdac_device *codec = &edev->hdac;
struct hdac_hdmi_priv *hdmi_priv; struct hdac_hdmi_priv *hdmi_priv;
struct snd_soc_dai_driver *hdmi_dais = NULL;
int num_dais = 0;
int ret = 0; int ret = 0;
hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); 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) ...@@ -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->pin_list);
INIT_LIST_HEAD(&hdmi_priv->cvt_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; 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 */ /* ASoC specific initialization */
return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, 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) 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) ...@@ -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_priv *hdmi = edev->private_data;
struct hdac_hdmi_pin *pin, *pin_next; struct hdac_hdmi_pin *pin, *pin_next;
struct hdac_hdmi_cvt *cvt, *cvt_next; struct hdac_hdmi_cvt *cvt, *cvt_next;
struct hdac_hdmi_pcm *pcm, *pcm_next;
snd_soc_unregister_codec(&edev->hdac.dev); 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_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) {
list_del(&cvt->head); list_del(&cvt->head);
kfree(cvt->name);
kfree(cvt); kfree(cvt);
} }
...@@ -602,6 +1562,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) ...@@ -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_ext_device *edev = to_hda_ext_device(dev);
struct hdac_device *hdac = &edev->hdac; struct hdac_device *hdac = &edev->hdac;
struct hdac_bus *bus = hdac->bus; struct hdac_bus *bus = hdac->bus;
unsigned long timeout;
int err; int err;
dev_dbg(dev, "Enter: %s\n", __func__); dev_dbg(dev, "Enter: %s\n", __func__);
...@@ -611,10 +1572,19 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) ...@@ -611,10 +1572,19 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
return 0; return 0;
/* Power down afg */ /* 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, snd_hdac_codec_write(hdac, hdac->afg, 0,
AC_VERB_SET_POWER_STATE, AC_PWRST_D3); 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); err = snd_hdac_display_power(bus, false);
if (err < 0) { if (err < 0) {
dev_err(bus->dev, "Cannot turn on display power on i915\n"); 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) ...@@ -643,6 +1613,9 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
return err; return err;
} }
hdac_hdmi_skl_enable_all_pins(&edev->hdac);
hdac_hdmi_skl_enable_dp12(&edev->hdac);
/* Power up afg */ /* Power up afg */
if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)) if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0))
snd_hdac_codec_write(hdac, hdac->afg, 0, snd_hdac_codec_write(hdac, hdac->afg, 0,
...@@ -661,6 +1634,7 @@ static const struct dev_pm_ops hdac_hdmi_pm = { ...@@ -661,6 +1634,7 @@ static const struct dev_pm_ops hdac_hdmi_pm = {
static const struct hda_device_id hdmi_list[] = { static const struct hda_device_id hdmi_list[] = {
HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0),
{} {}
}; };
......
#ifndef __HDAC_HDMI_H__
#define __HDAC_HDMI_H__
int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm);
#endif /* __HDAC_HDMI_H__ */
...@@ -163,6 +163,7 @@ config SND_SOC_INTEL_SKYLAKE ...@@ -163,6 +163,7 @@ config SND_SOC_INTEL_SKYLAKE
tristate tristate
select SND_HDA_EXT_CORE select SND_HDA_EXT_CORE
select SND_SOC_TOPOLOGY select SND_SOC_TOPOLOGY
select SND_HDA_I915
select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST
config SND_SOC_INTEL_SKL_RT286_MACH config SND_SOC_INTEL_SKL_RT286_MACH
...@@ -172,6 +173,7 @@ 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_INTEL_SKYLAKE
select SND_SOC_RT286 select SND_SOC_RT286
select SND_SOC_DMIC select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI
help help
This adds support for ASoC machine driver for Skylake platforms This adds support for ASoC machine driver for Skylake platforms
with RT286 I2S audio codec. with RT286 I2S audio codec.
...@@ -186,6 +188,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH ...@@ -186,6 +188,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH
select SND_SOC_NAU8825 select SND_SOC_NAU8825
select SND_SOC_SSM4567 select SND_SOC_SSM4567
select SND_SOC_DMIC select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI
help help
This adds support for ASoC Onboard Codec I2S machine driver. This will This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for NAU88L25 + SSM4567. create an alsa sound card for NAU88L25 + SSM4567.
...@@ -200,6 +203,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH ...@@ -200,6 +203,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH
select SND_SOC_NAU8825 select SND_SOC_NAU8825
select SND_SOC_MAX98357A select SND_SOC_MAX98357A
select SND_SOC_DMIC select SND_SOC_DMIC
select SND_SOC_HDAC_HDMI
help help
This adds support for ASoC Onboard Codec I2S machine driver. This will This adds support for ASoC Onboard Codec I2S machine driver. This will
create an alsa sound card for NAU88L25 + MAX98357A. create an alsa sound card for NAU88L25 + MAX98357A.
......
...@@ -342,6 +342,10 @@ static struct sst_acpi_mach sst_acpi_chv[] = { ...@@ -342,6 +342,10 @@ static struct sst_acpi_mach sst_acpi_chv[] = {
&chv_platform_data }, &chv_platform_data },
{"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL,
&chv_platform_data }, &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 },
{}, {},
}; };
......
...@@ -318,7 +318,6 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx, ...@@ -318,7 +318,6 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx,
union ipc_header_high msg_high; union ipc_header_high msg_high;
u32 msg_low; u32 msg_low;
struct ipc_dsp_hdr *dsp_hdr; struct ipc_dsp_hdr *dsp_hdr;
unsigned int cmd_id;
msg_high = msg->mrfld_header.p.header_high; msg_high = msg->mrfld_header.p.header_high;
msg_low = msg->mrfld_header.p.header_low_payload; 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, ...@@ -357,7 +356,6 @@ void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx,
return; return;
/* Copy command id so that we can use to put sst to reset */ /* Copy command id so that we can use to put sst to reset */
dsp_hdr = (struct ipc_dsp_hdr *)data; 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); 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, if (sst_wake_up_block(sst_drv_ctx, msg_high.part.result,
msg_high.part.drv_id, msg_high.part.drv_id,
......
...@@ -32,6 +32,18 @@ ...@@ -32,6 +32,18 @@
#include "../atom/sst-atom-controls.h" #include "../atom/sst-atom-controls.h"
#include "../common/sst-acpi.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[] = { static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL),
...@@ -70,18 +82,6 @@ static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { ...@@ -70,18 +82,6 @@ static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
{"IN1P", NULL, "Internal Mic"}, {"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[] = { static const struct snd_kcontrol_new byt_rt5640_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headphone"),
SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Headset Mic"),
...@@ -174,7 +174,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) ...@@ -174,7 +174,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
return ret; return ret;
} }
dmi_check_system(byt_rt5640_quirk_table);
switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { switch (BYT_RT5640_MAP(byt_rt5640_quirk)) {
case BYT_RT5640_IN1_MAP: case BYT_RT5640_IN1_MAP:
custom_map = byt_rt5640_intmic_in1_map; custom_map = byt_rt5640_intmic_in1_map;
...@@ -341,15 +340,34 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) ...@@ -341,15 +340,34 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
{ {
int ret_val = 0; int ret_val = 0;
struct sst_acpi_mach *mach; struct sst_acpi_mach *mach;
const char *i2c_name = NULL;
int i;
int dai_index;
/* register the soc card */ /* register the soc card */
byt_rt5640_card.dev = &pdev->dev; byt_rt5640_card.dev = &pdev->dev;
mach = byt_rt5640_card.dev->platform_data; 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 */ /* fixup codec name based on HID */
snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name), i2c_name = sst_acpi_find_name_from_hid(mach->id);
"%s%s%s", "i2c-", mach->id, ":00"); if (i2c_name != NULL) {
byt_rt5640_dais[MERR_DPCM_COMPR+1].codec_name = byt_rt5640_codec_name; 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); ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
......
...@@ -287,33 +287,20 @@ static struct snd_soc_card snd_soc_card_cht = { ...@@ -287,33 +287,20 @@ static struct snd_soc_card snd_soc_card_cht = {
.num_controls = ARRAY_SIZE(cht_mc_controls), .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) static int snd_cht_mc_probe(struct platform_device *pdev)
{ {
int ret_val = 0; int ret_val = 0;
bool found = false;
struct cht_mc_private *drv; struct cht_mc_private *drv;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
if (!drv) if (!drv)
return -ENOMEM; return -ENOMEM;
if (ACPI_SUCCESS(acpi_get_devices( drv->ts3a227e_present = acpi_dev_present("104C227E");
"104C227E", if (!drv->ts3a227e_present) {
snd_acpi_codec_match,
&found, NULL)) && found) {
drv->ts3a227e_present = true;
} else {
/* no need probe TI jack detection chip */ /* no need probe TI jack detection chip */
snd_soc_card_cht.aux_dev = NULL; snd_soc_card_cht.aux_dev = NULL;
snd_soc_card_cht.num_aux_devs = 0; snd_soc_card_cht.num_aux_devs = 0;
drv->ts3a227e_present = false;
} }
/* register the soc card */ /* register the soc card */
......
...@@ -147,6 +147,17 @@ static const struct snd_kcontrol_new cht_mc_controls[] = { ...@@ -147,6 +147,17 @@ static const struct snd_kcontrol_new cht_mc_controls[] = {
SOC_DAPM_PIN_SWITCH("Ext Spk"), 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, static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
...@@ -202,9 +213,9 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) ...@@ -202,9 +213,9 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
else else
jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE; 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, jack_type, &ctx->jack,
NULL, 0); cht_bsw_jack_pins, ARRAY_SIZE(cht_bsw_jack_pins));
if (ret) { if (ret) {
dev_err(runtime->dev, "Headset jack creation failed %d\n", ret); dev_err(runtime->dev, "Headset jack creation failed %d\n", ret);
return ret; return ret;
...@@ -333,20 +344,12 @@ static struct cht_acpi_card snd_soc_cards[] = { ...@@ -333,20 +344,12 @@ static struct cht_acpi_card snd_soc_cards[] = {
{"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650}, {"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) static int snd_cht_mc_probe(struct platform_device *pdev)
{ {
int ret_val = 0; int ret_val = 0;
int i; int i;
struct cht_mc_private *drv; struct cht_mc_private *drv;
struct snd_soc_card *card = snd_soc_cards[0].soc_card; struct snd_soc_card *card = snd_soc_cards[0].soc_card;
bool found = false;
char codec_name[16]; char codec_name[16];
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC);
...@@ -354,10 +357,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) ...@@ -354,10 +357,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(snd_soc_cards); i++) { for (i = 0; i < ARRAY_SIZE(snd_soc_cards); i++) {
if (ACPI_SUCCESS(acpi_get_devices( if (acpi_dev_present(snd_soc_cards[i].codec_id)) {
snd_soc_cards[i].codec_id,
snd_acpi_codec_match,
&found, NULL)) && found) {
dev_dbg(&pdev->dev, dev_dbg(&pdev->dev,
"found codec %s\n", snd_soc_cards[i].codec_id); "found codec %s\n", snd_soc_cards[i].codec_id);
card = snd_soc_cards[i].soc_card; card = snd_soc_cards[i].soc_card;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include <sound/soc.h> #include <sound/soc.h>
#include "../../codecs/nau8825.h" #include "../../codecs/nau8825.h"
#include "../../codecs/hdac_hdmi.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
#define SKL_MAXIM_CODEC_DAI "HiFi" #define SKL_MAXIM_CODEC_DAI "HiFi"
...@@ -29,6 +30,16 @@ ...@@ -29,6 +30,16 @@
static struct snd_soc_jack skylake_headset; static struct snd_soc_jack skylake_headset;
static struct snd_soc_card skylake_audio_card; 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) static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card)
{ {
struct snd_soc_pcm_runtime *rtd; struct snd_soc_pcm_runtime *rtd;
...@@ -87,7 +98,6 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { ...@@ -87,7 +98,6 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_SPK("Spk", NULL), SND_SOC_DAPM_SPK("Spk", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL),
SND_SOC_DAPM_SINK("WoV Sink"),
SND_SOC_DAPM_SPK("DP", NULL), SND_SOC_DAPM_SPK("DP", NULL),
SND_SOC_DAPM_SPK("HDMI", NULL), SND_SOC_DAPM_SPK("HDMI", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
...@@ -107,7 +117,6 @@ static const struct snd_soc_dapm_route skylake_map[] = { ...@@ -107,7 +117,6 @@ static const struct snd_soc_dapm_route skylake_map[] = {
{ "MIC", NULL, "Headset Mic" }, { "MIC", NULL, "Headset Mic" },
{ "DMic", NULL, "SoC DMIC" }, { "DMic", NULL, "SoC DMIC" },
{"WoV Sink", NULL, "hwd_in sink"},
{"HDMI", NULL, "hif5 Output"}, {"HDMI", NULL, "hif5 Output"},
{"DP", NULL, "hif6 Output"}, {"DP", NULL, "hif6 Output"},
...@@ -124,8 +133,14 @@ static const struct snd_soc_dapm_route skylake_map[] = { ...@@ -124,8 +133,14 @@ static const struct snd_soc_dapm_route skylake_map[] = {
/* DMIC */ /* DMIC */
{ "dmic01_hifi", NULL, "DMIC01 Rx" }, { "dmic01_hifi", NULL, "DMIC01 Rx" },
{ "DMIC01 Rx", NULL, "DMIC AIF" }, { "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" }, { "Headphone Jack", NULL, "Platform Clock" },
{ "Headset Mic", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" },
}; };
...@@ -171,11 +186,31 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) ...@@ -171,11 +186,31 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
nau8825_enable_jack_detect(codec, &skylake_headset); 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, "SoC DMIC");
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
return ret; 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) static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_soc_dapm_context *dapm; struct snd_soc_dapm_context *dapm;
...@@ -318,7 +353,7 @@ static struct snd_soc_ops skylaye_refcap_ops = { ...@@ -318,7 +353,7 @@ static struct snd_soc_ops skylaye_refcap_ops = {
/* skylake digital audio interface glue - connects codec <--> CPU */ /* skylake digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link skylake_dais[] = { static struct snd_soc_dai_link skylake_dais[] = {
/* Front End DAI links */ /* Front End DAI links */
{ [SKL_DPCM_AUDIO_PB] = {
.name = "Skl Audio Port", .name = "Skl Audio Port",
.stream_name = "Audio", .stream_name = "Audio",
.cpu_dai_name = "System Pin", .cpu_dai_name = "System Pin",
...@@ -333,7 +368,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -333,7 +368,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dpcm_playback = 1, .dpcm_playback = 1,
.ops = &skylake_nau8825_fe_ops, .ops = &skylake_nau8825_fe_ops,
}, },
{ [SKL_DPCM_AUDIO_CP] = {
.name = "Skl Audio Capture Port", .name = "Skl Audio Capture Port",
.stream_name = "Audio Record", .stream_name = "Audio Record",
.cpu_dai_name = "System Pin", .cpu_dai_name = "System Pin",
...@@ -347,7 +382,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -347,7 +382,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dpcm_capture = 1, .dpcm_capture = 1,
.ops = &skylake_nau8825_fe_ops, .ops = &skylake_nau8825_fe_ops,
}, },
{ [SKL_DPCM_AUDIO_REF_CP] = {
.name = "Skl Audio Reference cap", .name = "Skl Audio Reference cap",
.stream_name = "Wake on Voice", .stream_name = "Wake on Voice",
.cpu_dai_name = "Reference Pin", .cpu_dai_name = "Reference Pin",
...@@ -361,7 +396,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -361,7 +396,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dynamic = 1, .dynamic = 1,
.ops = &skylaye_refcap_ops, .ops = &skylaye_refcap_ops,
}, },
{ [SKL_DPCM_AUDIO_DMIC_CP] = {
.name = "Skl Audio DMIC cap", .name = "Skl Audio DMIC cap",
.stream_name = "dmiccap", .stream_name = "dmiccap",
.cpu_dai_name = "DMIC Pin", .cpu_dai_name = "DMIC Pin",
...@@ -374,15 +409,45 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -374,15 +409,45 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dynamic = 1, .dynamic = 1,
.ops = &skylake_dmic_ops, .ops = &skylake_dmic_ops,
}, },
{ [SKL_DPCM_AUDIO_HDMI1_PB] = {
.name = "Skl HDMI Port", .name = "Skl HDMI Port1",
.stream_name = "Hdmi", .stream_name = "Hdmi1",
.cpu_dai_name = "HDMI Pin", .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_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai", .codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3", .platform_name = "0000:00:1f.3",
.dpcm_playback = 1, .dpcm_playback = 1,
.init = NULL, .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, .nonatomic = 1,
.dynamic = 1, .dynamic = 1,
}, },
...@@ -407,7 +472,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -407,7 +472,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
{ {
/* SSP1 - Codec */ /* SSP1 - Codec */
.name = "SSP1-Codec", .name = "SSP1-Codec",
.be_id = 0, .be_id = 1,
.cpu_dai_name = "SSP1 Pin", .cpu_dai_name = "SSP1 Pin",
.platform_name = "0000:00:1f.3", .platform_name = "0000:00:1f.3",
.no_pcm = 1, .no_pcm = 1,
...@@ -424,7 +489,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -424,7 +489,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
}, },
{ {
.name = "dmic01", .name = "dmic01",
.be_id = 1, .be_id = 2,
.cpu_dai_name = "DMIC01 Pin", .cpu_dai_name = "DMIC01 Pin",
.codec_name = "dmic-codec", .codec_name = "dmic-codec",
.codec_dai_name = "dmic-hifi", .codec_dai_name = "dmic-hifi",
...@@ -435,13 +500,36 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -435,13 +500,36 @@ static struct snd_soc_dai_link skylake_dais[] = {
.no_pcm = 1, .no_pcm = 1,
}, },
{ {
.name = "iDisp", .name = "iDisp1",
.be_id = 3, .be_id = 3,
.cpu_dai_name = "iDisp Pin", .cpu_dai_name = "iDisp1 Pin",
.codec_name = "ehdaudio0D2", .codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi1", .codec_dai_name = "intel-hdmi-hifi1",
.platform_name = "0000:00:1f.3", .platform_name = "0000:00:1f.3",
.dpcm_playback = 1, .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, .no_pcm = 1,
}, },
}; };
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <sound/jack.h> #include <sound/jack.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include "../../codecs/nau8825.h" #include "../../codecs/nau8825.h"
#include "../../codecs/hdac_hdmi.h"
#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi"
#define SKL_SSM_CODEC_DAI "ssm4567-hifi" #define SKL_SSM_CODEC_DAI "ssm4567-hifi"
...@@ -33,6 +34,16 @@ ...@@ -33,6 +34,16 @@
static struct snd_soc_jack skylake_headset; static struct snd_soc_jack skylake_headset;
static struct snd_soc_card skylake_audio_card; 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) static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card)
{ {
struct snd_soc_pcm_runtime *rtd; struct snd_soc_pcm_runtime *rtd;
...@@ -92,7 +103,6 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { ...@@ -92,7 +103,6 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
SND_SOC_DAPM_SPK("Left Speaker", NULL), SND_SOC_DAPM_SPK("Left Speaker", NULL),
SND_SOC_DAPM_SPK("Right Speaker", NULL), SND_SOC_DAPM_SPK("Right Speaker", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL),
SND_SOC_DAPM_SINK("WoV Sink"),
SND_SOC_DAPM_SPK("DP", NULL), SND_SOC_DAPM_SPK("DP", NULL),
SND_SOC_DAPM_SPK("HDMI", NULL), SND_SOC_DAPM_SPK("HDMI", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
...@@ -113,8 +123,6 @@ static const struct snd_soc_dapm_route skylake_map[] = { ...@@ -113,8 +123,6 @@ static const struct snd_soc_dapm_route skylake_map[] = {
{"MIC", NULL, "Headset Mic"}, {"MIC", NULL, "Headset Mic"},
{"DMic", NULL, "SoC DMIC"}, {"DMic", NULL, "SoC DMIC"},
{"WoV Sink", NULL, "hwd_in sink"},
{"HDMI", NULL, "hif5 Output"}, {"HDMI", NULL, "hif5 Output"},
{"DP", NULL, "hif6 Output"}, {"DP", NULL, "hif6 Output"},
/* CODEC BE connections */ /* CODEC BE connections */
...@@ -122,6 +130,11 @@ static const struct snd_soc_dapm_route skylake_map[] = { ...@@ -122,6 +130,11 @@ static const struct snd_soc_dapm_route skylake_map[] = {
{ "Right Playback", NULL, "ssp0 Tx"}, { "Right Playback", NULL, "ssp0 Tx"},
{ "ssp0 Tx", NULL, "codec0_out"}, { "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"}, { "Playback", NULL, "ssp1 Tx"},
{ "ssp1 Tx", NULL, "codec1_out"}, { "ssp1 Tx", NULL, "codec1_out"},
...@@ -131,8 +144,14 @@ static const struct snd_soc_dapm_route skylake_map[] = { ...@@ -131,8 +144,14 @@ static const struct snd_soc_dapm_route skylake_map[] = {
/* DMIC */ /* DMIC */
{ "dmic01_hifi", NULL, "DMIC01 Rx" }, { "dmic01_hifi", NULL, "DMIC01 Rx" },
{ "DMIC01 Rx", NULL, "DMIC AIF" }, { "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" }, { "Headphone Jack", NULL, "Platform Clock" },
{ "Headset Mic", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" },
}; };
...@@ -197,11 +216,32 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) ...@@ -197,11 +216,32 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd)
nau8825_enable_jack_detect(codec, &skylake_headset); 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, "SoC DMIC");
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
return ret; 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) static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_soc_dapm_context *dapm; struct snd_soc_dapm_context *dapm;
...@@ -362,7 +402,7 @@ static struct snd_soc_ops skylaye_refcap_ops = { ...@@ -362,7 +402,7 @@ static struct snd_soc_ops skylaye_refcap_ops = {
/* skylake digital audio interface glue - connects codec <--> CPU */ /* skylake digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link skylake_dais[] = { static struct snd_soc_dai_link skylake_dais[] = {
/* Front End DAI links */ /* Front End DAI links */
{ [SKL_DPCM_AUDIO_PB] = {
.name = "Skl Audio Port", .name = "Skl Audio Port",
.stream_name = "Audio", .stream_name = "Audio",
.cpu_dai_name = "System Pin", .cpu_dai_name = "System Pin",
...@@ -377,7 +417,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -377,7 +417,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dpcm_playback = 1, .dpcm_playback = 1,
.ops = &skylake_nau8825_fe_ops, .ops = &skylake_nau8825_fe_ops,
}, },
{ [SKL_DPCM_AUDIO_CP] = {
.name = "Skl Audio Capture Port", .name = "Skl Audio Capture Port",
.stream_name = "Audio Record", .stream_name = "Audio Record",
.cpu_dai_name = "System Pin", .cpu_dai_name = "System Pin",
...@@ -391,7 +431,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -391,7 +431,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dpcm_capture = 1, .dpcm_capture = 1,
.ops = &skylake_nau8825_fe_ops, .ops = &skylake_nau8825_fe_ops,
}, },
{ [SKL_DPCM_AUDIO_REF_CP] = {
.name = "Skl Audio Reference cap", .name = "Skl Audio Reference cap",
.stream_name = "Wake on Voice", .stream_name = "Wake on Voice",
.cpu_dai_name = "Reference Pin", .cpu_dai_name = "Reference Pin",
...@@ -405,7 +445,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -405,7 +445,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dynamic = 1, .dynamic = 1,
.ops = &skylaye_refcap_ops, .ops = &skylaye_refcap_ops,
}, },
{ [SKL_DPCM_AUDIO_DMIC_CP] = {
.name = "Skl Audio DMIC cap", .name = "Skl Audio DMIC cap",
.stream_name = "dmiccap", .stream_name = "dmiccap",
.cpu_dai_name = "DMIC Pin", .cpu_dai_name = "DMIC Pin",
...@@ -418,13 +458,43 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -418,13 +458,43 @@ static struct snd_soc_dai_link skylake_dais[] = {
.dynamic = 1, .dynamic = 1,
.ops = &skylake_dmic_ops, .ops = &skylake_dmic_ops,
}, },
{ [SKL_DPCM_AUDIO_HDMI1_PB] = {
.name = "Skl HDMI Port", .name = "Skl HDMI Port1",
.stream_name = "Hdmi", .stream_name = "Hdmi1",
.cpu_dai_name = "HDMI Pin", .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_name = "snd-soc-dummy",
.codec_dai_name = "snd-soc-dummy-dai", .codec_dai_name = "snd-soc-dummy-dai",
.platform_name = "0000:00:1f.3", .platform_name = "0000:00:1f.3",
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_playback = 1, .dpcm_playback = 1,
.init = NULL, .init = NULL,
.nonatomic = 1, .nonatomic = 1,
...@@ -448,11 +518,12 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -448,11 +518,12 @@ static struct snd_soc_dai_link skylake_dais[] = {
.ignore_pmdown_time = 1, .ignore_pmdown_time = 1,
.be_hw_params_fixup = skylake_ssp_fixup, .be_hw_params_fixup = skylake_ssp_fixup,
.dpcm_playback = 1, .dpcm_playback = 1,
.dpcm_capture = 1,
}, },
{ {
/* SSP1 - Codec */ /* SSP1 - Codec */
.name = "SSP1-Codec", .name = "SSP1-Codec",
.be_id = 0, .be_id = 1,
.cpu_dai_name = "SSP1 Pin", .cpu_dai_name = "SSP1 Pin",
.platform_name = "0000:00:1f.3", .platform_name = "0000:00:1f.3",
.no_pcm = 1, .no_pcm = 1,
...@@ -469,7 +540,7 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -469,7 +540,7 @@ static struct snd_soc_dai_link skylake_dais[] = {
}, },
{ {
.name = "dmic01", .name = "dmic01",
.be_id = 1, .be_id = 2,
.cpu_dai_name = "DMIC01 Pin", .cpu_dai_name = "DMIC01 Pin",
.codec_name = "dmic-codec", .codec_name = "dmic-codec",
.codec_dai_name = "dmic-hifi", .codec_dai_name = "dmic-hifi",
...@@ -480,13 +551,36 @@ static struct snd_soc_dai_link skylake_dais[] = { ...@@ -480,13 +551,36 @@ static struct snd_soc_dai_link skylake_dais[] = {
.no_pcm = 1, .no_pcm = 1,
}, },
{ {
.name = "iDisp", .name = "iDisp1",
.be_id = 3, .be_id = 3,
.cpu_dai_name = "iDisp Pin", .cpu_dai_name = "iDisp1 Pin",
.codec_name = "ehdaudio0D2", .codec_name = "ehdaudio0D2",
.codec_dai_name = "intel-hdmi-hifi1", .codec_dai_name = "intel-hdmi-hifi1",
.platform_name = "0000:00:1f.3", .platform_name = "0000:00:1f.3",
.dpcm_playback = 1, .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, .no_pcm = 1,
}, },
}; };
......
...@@ -26,8 +26,20 @@ ...@@ -26,8 +26,20 @@
#include <sound/jack.h> #include <sound/jack.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include "../../codecs/rt286.h" #include "../../codecs/rt286.h"
#include "../../codecs/hdac_hdmi.h"
static struct snd_soc_jack skylake_headset; 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 */ /* Headset jack detection DAPM pins */
static struct snd_soc_jack_pin skylake_headset_pins[] = { static struct snd_soc_jack_pin skylake_headset_pins[] = {
{ {
...@@ -52,7 +64,9 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { ...@@ -52,7 +64,9 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = {
SND_SOC_DAPM_MIC("Mic Jack", NULL), SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_MIC("DMIC2", NULL), SND_SOC_DAPM_MIC("DMIC2", NULL),
SND_SOC_DAPM_MIC("SoC DMIC", 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[] = { static const struct snd_soc_dapm_route skylake_rt286_map[] = {
...@@ -70,7 +84,9 @@ 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"}, {"DMIC1 Pin", NULL, "DMIC2"},
{"DMic", NULL, "SoC DMIC"}, {"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 */ /* CODEC BE connections */
{ "AIF1 Playback", NULL, "ssp0 Tx"}, { "AIF1 Playback", NULL, "ssp0 Tx"},
...@@ -84,8 +100,12 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { ...@@ -84,8 +100,12 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = {
{ "dmic01_hifi", NULL, "DMIC01 Rx" }, { "dmic01_hifi", NULL, "DMIC01 Rx" },
{ "DMIC01 Rx", NULL, "DMIC AIF" }, { "DMIC01 Rx", NULL, "DMIC AIF" },
{ "hif1", NULL, "iDisp Tx"}, { "hifi3", NULL, "iDisp3 Tx"},
{ "iDisp Tx", NULL, "iDisp_out"}, { "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) ...@@ -116,11 +136,17 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
rt286_mic_detect(codec, &skylake_headset); rt286_mic_detect(codec, &skylake_headset);
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC");
snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink");
return 0; 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[] = { static unsigned int rates[] = {
48000, 48000,
}; };
...@@ -249,7 +275,7 @@ static struct snd_soc_ops skylake_dmic_ops = { ...@@ -249,7 +275,7 @@ static struct snd_soc_ops skylake_dmic_ops = {
/* skylake digital audio interface glue - connects codec <--> CPU */ /* skylake digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link skylake_rt286_dais[] = { static struct snd_soc_dai_link skylake_rt286_dais[] = {
/* Front End DAI links */ /* Front End DAI links */
{ [SKL_DPCM_AUDIO_PB] = {
.name = "Skl Audio Port", .name = "Skl Audio Port",
.stream_name = "Audio", .stream_name = "Audio",
.cpu_dai_name = "System Pin", .cpu_dai_name = "System Pin",
...@@ -266,7 +292,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { ...@@ -266,7 +292,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.dpcm_playback = 1, .dpcm_playback = 1,
.ops = &skylake_rt286_fe_ops, .ops = &skylake_rt286_fe_ops,
}, },
{ [SKL_DPCM_AUDIO_CP] = {
.name = "Skl Audio Capture Port", .name = "Skl Audio Capture Port",
.stream_name = "Audio Record", .stream_name = "Audio Record",
.cpu_dai_name = "System Pin", .cpu_dai_name = "System Pin",
...@@ -282,7 +308,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { ...@@ -282,7 +308,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.dpcm_capture = 1, .dpcm_capture = 1,
.ops = &skylake_rt286_fe_ops, .ops = &skylake_rt286_fe_ops,
}, },
{ [SKL_DPCM_AUDIO_REF_CP] = {
.name = "Skl Audio Reference cap", .name = "Skl Audio Reference cap",
.stream_name = "refcap", .stream_name = "refcap",
.cpu_dai_name = "Reference Pin", .cpu_dai_name = "Reference Pin",
...@@ -295,7 +321,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { ...@@ -295,7 +321,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.nonatomic = 1, .nonatomic = 1,
.dynamic = 1, .dynamic = 1,
}, },
{ [SKL_DPCM_AUDIO_DMIC_CP] = {
.name = "Skl Audio DMIC cap", .name = "Skl Audio DMIC cap",
.stream_name = "dmiccap", .stream_name = "dmiccap",
.cpu_dai_name = "DMIC Pin", .cpu_dai_name = "DMIC Pin",
...@@ -308,6 +334,42 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { ...@@ -308,6 +334,42 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.dynamic = 1, .dynamic = 1,
.ops = &skylake_dmic_ops, .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 */ /* Back End DAI links */
{ {
...@@ -341,6 +403,39 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { ...@@ -341,6 +403,39 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = {
.dpcm_capture = 1, .dpcm_capture = 1,
.no_pcm = 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 */ /* skylake audio machine driver for SPT + RT286S */
......
...@@ -14,6 +14,9 @@ ...@@ -14,6 +14,9 @@
#include <linux/acpi.h> #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 */ /* acpi match */
struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines); struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines);
......
...@@ -317,6 +317,7 @@ struct sst_dsp { ...@@ -317,6 +317,7 @@ struct sst_dsp {
struct skl_cl_dev cl_dev; struct skl_cl_dev cl_dev;
u32 intr_status; u32 intr_status;
const struct firmware *fw; const struct firmware *fw;
struct snd_dma_buffer dmab;
}; };
/* Size optimised DRAM/IRAM memcpy */ /* Size optimised DRAM/IRAM memcpy */
......
...@@ -13,17 +13,53 @@ ...@@ -13,17 +13,53 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details. * more details.
*/ */
#include <linux/acpi.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include "sst-acpi.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, static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
void *context, void **ret) void *context, void **ret)
{ {
unsigned long long sta;
acpi_status status;
*(bool *)context = true; *(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; return AE_OK;
} }
...@@ -37,7 +73,6 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines) ...@@ -37,7 +73,6 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines)
sst_acpi_mach_match, sst_acpi_mach_match,
&found, NULL)) && found) &found, NULL)) && found)
return mach; return mach;
return NULL; return NULL;
} }
EXPORT_SYMBOL_GPL(sst_acpi_find_machine); EXPORT_SYMBOL_GPL(sst_acpi_find_machine);
......
...@@ -72,17 +72,47 @@ static void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable) ...@@ -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); 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) int skl_init_dsp(struct skl *skl)
{ {
void __iomem *mmio_base; void __iomem *mmio_base;
struct hdac_ext_bus *ebus = &skl->ebus; struct hdac_ext_bus *ebus = &skl->ebus;
struct hdac_bus *bus = ebus_to_hbus(ebus); struct hdac_bus *bus = ebus_to_hbus(ebus);
int irq = bus->irq;
struct skl_dsp_loader_ops loader_ops; struct skl_dsp_loader_ops loader_ops;
int ret; int irq = bus->irq;
int ret, index;
loader_ops.alloc_dma_buf = skl_alloc_dma_buf;
loader_ops.free_dma_buf = skl_free_dma_buf;
/* enable ppcap interrupt */ /* enable ppcap interrupt */
snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true); snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true);
...@@ -95,8 +125,14 @@ int skl_init_dsp(struct skl *skl) ...@@ -95,8 +125,14 @@ int skl_init_dsp(struct skl *skl)
return -ENXIO; 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); skl->fw_name, loader_ops, &skl->skl_sst);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -106,18 +142,26 @@ int skl_init_dsp(struct skl *skl) ...@@ -106,18 +142,26 @@ int skl_init_dsp(struct skl *skl)
return ret; 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_ext_bus *ebus = &skl->ebus;
struct hdac_bus *bus = ebus_to_hbus(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 */ /* disable ppcap interrupt */
snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false); 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) if (ctx->dsp->addr.lpe)
iounmap(ctx->dsp->addr.lpe); iounmap(ctx->dsp->addr.lpe);
return 0;
} }
int skl_suspend_dsp(struct skl *skl) int skl_suspend_dsp(struct skl *skl)
...@@ -238,9 +282,8 @@ static void skl_copy_copier_caps(struct skl_module_cfg *mconfig, ...@@ -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 * Calculate the gatewat settings required for copier module, type of
* gateway and index of gateway to use * gateway and index of gateway to use
*/ */
static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, static u32 skl_get_node_id(struct skl_sst *ctx,
struct skl_module_cfg *mconfig, struct skl_module_cfg *mconfig)
struct skl_cpr_cfg *cpr_mconfig)
{ {
union skl_connector_node_id node_id = {0}; union skl_connector_node_id node_id = {0};
union skl_ssp_dma_node ssp_node = {0}; union skl_ssp_dma_node ssp_node = {0};
...@@ -289,13 +332,24 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, ...@@ -289,13 +332,24 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
break; break;
default: 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; cpr_mconfig->cpr_feature_mask = 0;
return; return;
} }
cpr_mconfig->gtw_cfg.node_id = node_id.val;
if (SKL_CONN_SOURCE == mconfig->hw_conn_type) if (SKL_CONN_SOURCE == mconfig->hw_conn_type)
cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->obs; cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * mconfig->obs;
else else
...@@ -307,6 +361,46 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, ...@@ -307,6 +361,46 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx,
skl_copy_copier_caps(mconfig, cpr_mconfig); 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, static void skl_setup_out_format(struct skl_sst *ctx,
struct skl_module_cfg *mconfig, struct skl_module_cfg *mconfig,
struct skl_audio_data_format *out_fmt) struct skl_audio_data_format *out_fmt)
......
...@@ -145,3 +145,37 @@ struct nhlt_specific_cfg ...@@ -145,3 +145,37 @@ struct nhlt_specific_cfg
return NULL; 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;
}
...@@ -206,6 +206,23 @@ static int skl_get_format(struct snd_pcm_substream *substream, ...@@ -206,6 +206,23 @@ static int skl_get_format(struct snd_pcm_substream *substream,
return format_val; 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, static int skl_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
...@@ -458,7 +475,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, ...@@ -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_bus *ebus = dev_get_drvdata(dai->dev);
struct hdac_ext_stream *link_dev; struct hdac_ext_stream *link_dev;
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 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 snd_soc_dai *codec_dai = rtd->codec_dai;
struct skl_pipe_params p_params = {0}; struct skl_pipe_params p_params = {0};
...@@ -470,11 +487,9 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, ...@@ -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); snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
/* set the stream tag in the codec dai dma params */ /* set the stream tag in the codec dai dma params */
dma_params = (struct skl_dma_params *) dma_params = snd_soc_dai_get_dma_data(codec_dai, substream);
snd_soc_dai_get_dma_data(codec_dai, substream);
if (dma_params) if (dma_params)
dma_params->stream_tag = hdac_stream(link_dev)->stream_tag; 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.s_fmt = snd_pcm_format_width(params_format(params));
p_params.ch = params_channels(params); p_params.ch = params_channels(params);
...@@ -588,6 +603,7 @@ static struct snd_soc_dai_ops skl_dmic_dai_ops = { ...@@ -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 = { static struct snd_soc_dai_ops skl_be_ssp_dai_ops = {
.hw_params = skl_be_hw_params, .hw_params = skl_be_hw_params,
.prepare = skl_be_prepare,
}; };
static struct snd_soc_dai_ops skl_link_dai_ops = { static struct snd_soc_dai_ops skl_link_dai_ops = {
...@@ -660,6 +676,51 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { ...@@ -660,6 +676,51 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, .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 */ /* BE CPU Dais */
{ {
...@@ -699,14 +760,41 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { ...@@ -699,14 +760,41 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
}, },
}, },
{ {
.name = "iDisp Pin", .name = "iDisp1 Pin",
.ops = &skl_link_dai_ops, .ops = &skl_link_dai_ops,
.playback = { .playback = {
.stream_name = "iDisp Tx", .stream_name = "iDisp1 Tx",
.channels_min = HDA_STEREO, .channels_min = HDA_STEREO,
.channels_max = HDA_STEREO, .channels_max = HDA_STEREO,
.rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, .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, ...@@ -863,7 +951,9 @@ static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus,
else else
delay += hstream->bufsize; delay += hstream->bufsize;
} }
delay = (hstream->bufsize == delay) ? 0 : delay;
if (hstream->bufsize == delay)
delay = 0;
if (delay >= hstream->period_bytes) { if (delay >= hstream->period_bytes) {
dev_info(bus->dev, dev_info(bus->dev,
......
...@@ -34,7 +34,7 @@ void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state) ...@@ -34,7 +34,7 @@ void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state)
mutex_unlock(&ctx->mutex); 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; int ret;
...@@ -60,7 +60,7 @@ static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx) ...@@ -60,7 +60,7 @@ static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx)
return ret; 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; int ret;
...@@ -87,7 +87,7 @@ static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx) ...@@ -87,7 +87,7 @@ static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx)
return ret; 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; int val;
bool is_enable; bool is_enable;
...@@ -140,7 +140,7 @@ static int skl_dsp_start_core(struct sst_dsp *ctx) ...@@ -140,7 +140,7 @@ static int skl_dsp_start_core(struct sst_dsp *ctx)
return ret; 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; int ret;
...@@ -166,7 +166,7 @@ static int skl_dsp_core_power_up(struct sst_dsp *ctx) ...@@ -166,7 +166,7 @@ static int skl_dsp_core_power_up(struct sst_dsp *ctx)
return ret; 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 */ /* update bits */
sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, 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) ...@@ -181,7 +181,7 @@ static int skl_dsp_core_power_down(struct sst_dsp *ctx)
"Power down"); "Power down");
} }
static int skl_dsp_enable_core(struct sst_dsp *ctx) int skl_dsp_enable_core(struct sst_dsp *ctx)
{ {
int ret; int ret;
...@@ -195,7 +195,7 @@ static int skl_dsp_enable_core(struct sst_dsp *ctx) ...@@ -195,7 +195,7 @@ static int skl_dsp_enable_core(struct sst_dsp *ctx)
return skl_dsp_start_core(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; int ret;
......
...@@ -53,6 +53,10 @@ struct sst_dsp_device; ...@@ -53,6 +53,10 @@ struct sst_dsp_device;
/* HIPCT */ /* HIPCT */
#define SKL_ADSP_REG_HIPCT_BUSY BIT(31) #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 */ /* Intel HD Audio SRAM Window 1 */
#define SKL_ADSP_SRAM1_BASE 0xA000 #define SKL_ADSP_SRAM1_BASE 0xA000
...@@ -144,7 +148,8 @@ int skl_cldma_prepare(struct sst_dsp *ctx); ...@@ -144,7 +148,8 @@ int skl_cldma_prepare(struct sst_dsp *ctx);
void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); 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 *skl_dsp_ctx_init(struct device *dev,
struct sst_dsp_device *sst_dev, int irq); 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); bool is_skl_dsp_running(struct sst_dsp *ctx);
irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id); irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id);
int skl_dsp_wake(struct sst_dsp *ctx); int skl_dsp_wake(struct sst_dsp *ctx);
......
...@@ -35,9 +35,6 @@ ...@@ -35,9 +35,6 @@
#define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE #define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE
#define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4) #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 #define SKL_NUM_MODULES 1
static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status) static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status)
......
...@@ -260,6 +260,65 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx, ...@@ -260,6 +260,65 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx,
multiplier; 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, static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w,
struct skl_sst *ctx) struct skl_sst *ctx)
{ {
...@@ -433,6 +492,9 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) ...@@ -433,6 +492,9 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
return ret; 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 * apply fix/conversion to module params based on
* FE/BE params * FE/BE params
...@@ -545,6 +607,66 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, ...@@ -545,6 +607,66 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
return 0; 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, static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
struct skl *skl, struct skl *skl,
struct snd_soc_dapm_widget *src_w, struct snd_soc_dapm_widget *src_w,
...@@ -579,11 +701,19 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, ...@@ -579,11 +701,19 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
sink = p->sink; sink = p->sink;
sink_mconfig = sink->priv; 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 */ /* Bind source to sink, mixin is always source */
ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig); ret = skl_bind_modules(ctx, src_mconfig, sink_mconfig);
if (ret) if (ret)
return 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 */ /* Start sinks pipe first */
if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) {
if (sink_mconfig->pipe->conn_type != 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, ...@@ -714,6 +844,10 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w,
if (ret) if (ret)
return 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) if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE)
ret = skl_run_pipe(ctx, sink_mconfig->pipe); 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) ...@@ -1091,6 +1225,66 @@ skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream)
return NULL; 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) static u8 skl_tplg_be_link_type(int dev_type)
{ {
int ret; int ret;
...@@ -1464,8 +1658,7 @@ static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, ...@@ -1464,8 +1658,7 @@ static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be,
if (!ac->params) if (!ac->params)
return -ENOMEM; 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; be->dobj.private = ac;
...@@ -1523,11 +1716,16 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) ...@@ -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 hdac_bus *bus = ebus_to_hbus(ebus);
struct skl *skl = ebus_to_skl(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) { if (ret < 0) {
dev_err(bus->dev, "tplg fw %s load failed with %d\n", dev_err(bus->dev, "tplg fw %s load failed with %d\n",
"dfw_sst.bin", ret); skl->tplg_name, ret);
return 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;
}
} }
/* /*
......
...@@ -113,6 +113,29 @@ struct skl_cpr_gtw_cfg { ...@@ -113,6 +113,29 @@ struct skl_cpr_gtw_cfg {
u32 config_data[1]; u32 config_data[1];
} __packed; } __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_cpr_cfg {
struct skl_base_cfg base_cfg; struct skl_base_cfg base_cfg;
struct skl_audio_data_format out_fmt; struct skl_audio_data_format out_fmt;
...@@ -313,6 +336,8 @@ static inline struct skl *get_skl_ctx(struct device *dev) ...@@ -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, int skl_tplg_be_update_params(struct snd_soc_dai *dai,
struct skl_pipe_params *params); 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, void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai,
struct skl_pipe_params *params, int stream); struct skl_pipe_params *params, int stream);
int skl_tplg_init(struct snd_soc_platform *platform, 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, ...@@ -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, int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size,
u32 param_id, struct skl_module_cfg *mcfg); 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); enum skl_bitdepth skl_get_bit_depth(int params);
#endif #endif
...@@ -144,7 +144,8 @@ enum module_pin_type { ...@@ -144,7 +144,8 @@ enum module_pin_type {
enum skl_module_param_type { enum skl_module_param_type {
SKL_PARAM_DEFAULT = 0, SKL_PARAM_DEFAULT = 0,
SKL_PARAM_INIT, SKL_PARAM_INIT,
SKL_PARAM_SET SKL_PARAM_SET,
SKL_PARAM_BIND
}; };
struct skl_dfw_module_pin { struct skl_dfw_module_pin {
......
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
#include <linux/firmware.h> #include <linux/firmware.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include "../common/sst-acpi.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.h"
#include "skl-sst-dsp.h" #include "skl-sst-dsp.h"
#include "skl-sst-ipc.h" #include "skl-sst-ipc.h"
...@@ -243,6 +246,16 @@ static int skl_resume(struct device *dev) ...@@ -243,6 +246,16 @@ static int skl_resume(struct device *dev)
struct hdac_bus *bus = ebus_to_hbus(ebus); struct hdac_bus *bus = ebus_to_hbus(ebus);
int ret; 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 * resume only when we are not in suspend active, otherwise need to
* restore the device * restore the device
...@@ -481,6 +494,27 @@ static int skl_create(struct pci_dev *pci, ...@@ -481,6 +494,27 @@ static int skl_create(struct pci_dev *pci,
return 0; 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) static int skl_first_init(struct hdac_ext_bus *ebus)
{ {
struct skl *skl = ebus_to_skl(ebus); struct skl *skl = ebus_to_skl(ebus);
...@@ -543,6 +577,12 @@ static int skl_first_init(struct hdac_ext_bus *ebus) ...@@ -543,6 +577,12 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
/* initialize chip */ /* initialize chip */
skl_init_pci(skl); 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); skl_init_chip(bus, true);
/* codec detection */ /* codec detection */
...@@ -573,11 +613,15 @@ static int skl_probe(struct pci_dev *pci, ...@@ -573,11 +613,15 @@ static int skl_probe(struct pci_dev *pci,
if (err < 0) if (err < 0)
goto out_free; goto out_free;
skl->pci_id = pci->device;
skl->nhlt = skl_nhlt_init(bus->dev); skl->nhlt = skl_nhlt_init(bus->dev);
if (skl->nhlt == NULL) if (skl->nhlt == NULL)
goto out_free; goto out_free;
skl_nhlt_update_topology_bin(skl);
pci_set_drvdata(skl->pci, ebus); pci_set_drvdata(skl->pci, ebus);
/* check if dsp is there */ /* check if dsp is there */
...@@ -613,6 +657,14 @@ static int skl_probe(struct pci_dev *pci, ...@@ -613,6 +657,14 @@ static int skl_probe(struct pci_dev *pci,
if (err < 0) if (err < 0)
goto out_unregister; 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 */ /*configure PM */
pm_runtime_put_noidle(bus->dev); pm_runtime_put_noidle(bus->dev);
pm_runtime_allow(bus->dev); pm_runtime_allow(bus->dev);
...@@ -634,6 +686,31 @@ static int skl_probe(struct pci_dev *pci, ...@@ -634,6 +686,31 @@ static int skl_probe(struct pci_dev *pci,
return err; 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) static void skl_remove(struct pci_dev *pci)
{ {
struct hdac_ext_bus *ebus = pci_get_drvdata(pci); struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
...@@ -642,6 +719,9 @@ static void skl_remove(struct pci_dev *pci) ...@@ -642,6 +719,9 @@ static void skl_remove(struct pci_dev *pci)
if (skl->tplg) if (skl->tplg)
release_firmware(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)) if (pci_dev_run_wake(pci))
pm_runtime_get_noresume(&pci->dev); pm_runtime_get_noresume(&pci->dev);
pci_dev_put(pci); pci_dev_put(pci);
...@@ -662,11 +742,18 @@ static struct sst_acpi_mach sst_skl_devdata[] = { ...@@ -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 */ /* PCI IDs */
static const struct pci_device_id skl_ids[] = { static const struct pci_device_id skl_ids[] = {
/* Sunrise Point-LP */ /* Sunrise Point-LP */
{ PCI_DEVICE(0x8086, 0x9d70), { PCI_DEVICE(0x8086, 0x9d70),
.driver_data = (unsigned long)&sst_skl_devdata}, .driver_data = (unsigned long)&sst_skl_devdata},
/* BXT-P */
{ PCI_DEVICE(0x8086, 0x5a98),
.driver_data = (unsigned long)&sst_bxtp_devdata},
{ 0, } { 0, }
}; };
MODULE_DEVICE_TABLE(pci, skl_ids); MODULE_DEVICE_TABLE(pci, skl_ids);
...@@ -677,6 +764,7 @@ static struct pci_driver skl_driver = { ...@@ -677,6 +764,7 @@ static struct pci_driver skl_driver = {
.id_table = skl_ids, .id_table = skl_ids,
.probe = skl_probe, .probe = skl_probe,
.remove = skl_remove, .remove = skl_remove,
.shutdown = skl_shutdown,
.driver = { .driver = {
.pm = &skl_pm, .pm = &skl_pm,
}, },
......
...@@ -73,6 +73,8 @@ struct skl { ...@@ -73,6 +73,8 @@ struct skl {
struct list_head ppl_list; struct list_head ppl_list;
const char *fw_name; const char *fw_name;
char tplg_name[64];
unsigned short pci_id;
const struct firmware *tplg; const struct firmware *tplg;
int supend_active; int supend_active;
...@@ -88,6 +90,16 @@ struct skl_dma_params { ...@@ -88,6 +90,16 @@ struct skl_dma_params {
u8 stream_tag; 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_unregister(struct device *dev);
int skl_platform_register(struct device *dev); int skl_platform_register(struct device *dev);
...@@ -96,8 +108,9 @@ void skl_nhlt_free(void *addr); ...@@ -96,8 +108,9 @@ void skl_nhlt_free(void *addr);
struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, 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); 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); 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_suspend_dsp(struct skl *skl);
int skl_resume_dsp(struct skl *skl); int skl_resume_dsp(struct skl *skl);
#endif /* __SOUND_SOC_SKL_H */ #endif /* __SOUND_SOC_SKL_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment