1a40e693cSJeeja KP /* 2a40e693cSJeeja KP * skl-pcm.c -ASoC HDA Platform driver file implementing PCM functionality 3a40e693cSJeeja KP * 4a40e693cSJeeja KP * Copyright (C) 2014-2015 Intel Corp 5a40e693cSJeeja KP * Author: Jeeja KP <jeeja.kp@intel.com> 6a40e693cSJeeja KP * 7a40e693cSJeeja KP * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8a40e693cSJeeja KP * 9a40e693cSJeeja KP * This program is free software; you can redistribute it and/or modify 10a40e693cSJeeja KP * it under the terms of the GNU General Public License as published by 11a40e693cSJeeja KP * the Free Software Foundation; version 2 of the License. 12a40e693cSJeeja KP * 13a40e693cSJeeja KP * This program is distributed in the hope that it will be useful, but 14a40e693cSJeeja KP * WITHOUT ANY WARRANTY; without even the implied warranty of 15a40e693cSJeeja KP * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16a40e693cSJeeja KP * General Public License for more details. 17a40e693cSJeeja KP * 18a40e693cSJeeja KP * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19a40e693cSJeeja KP * 20a40e693cSJeeja KP */ 21a40e693cSJeeja KP 22a40e693cSJeeja KP #include <linux/pci.h> 23a40e693cSJeeja KP #include <linux/pm_runtime.h> 24a40e693cSJeeja KP #include <sound/pcm_params.h> 25a40e693cSJeeja KP #include <sound/soc.h> 26a40e693cSJeeja KP #include "skl.h" 27b663a8c5SJeeja KP #include "skl-topology.h" 28721c3e36SDharageswari.R #include "skl-sst-dsp.h" 29721c3e36SDharageswari.R #include "skl-sst-ipc.h" 30a40e693cSJeeja KP 31a40e693cSJeeja KP #define HDA_MONO 1 32a40e693cSJeeja KP #define HDA_STEREO 2 338f35bf3fSJeeja KP #define HDA_QUAD 4 34a40e693cSJeeja KP 35a40e693cSJeeja KP static struct snd_pcm_hardware azx_pcm_hw = { 36a40e693cSJeeja KP .info = (SNDRV_PCM_INFO_MMAP | 37a40e693cSJeeja KP SNDRV_PCM_INFO_INTERLEAVED | 38a40e693cSJeeja KP SNDRV_PCM_INFO_BLOCK_TRANSFER | 39a40e693cSJeeja KP SNDRV_PCM_INFO_MMAP_VALID | 40a40e693cSJeeja KP SNDRV_PCM_INFO_PAUSE | 413637976bSJeeja KP SNDRV_PCM_INFO_RESUME | 42a40e693cSJeeja KP SNDRV_PCM_INFO_SYNC_START | 43a40e693cSJeeja KP SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ 44a40e693cSJeeja KP SNDRV_PCM_INFO_HAS_LINK_ATIME | 45a40e693cSJeeja KP SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), 4606b23d93SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | 4706b23d93SJeeja KP SNDRV_PCM_FMTBIT_S32_LE | 4806b23d93SJeeja KP SNDRV_PCM_FMTBIT_S24_LE, 4906b23d93SJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | 5006b23d93SJeeja KP SNDRV_PCM_RATE_8000, 5106b23d93SJeeja KP .rate_min = 8000, 52a40e693cSJeeja KP .rate_max = 48000, 538f35bf3fSJeeja KP .channels_min = 1, 547e12dc87SSubhransu S. Prusty .channels_max = 8, 55a40e693cSJeeja KP .buffer_bytes_max = AZX_MAX_BUF_SIZE, 56a40e693cSJeeja KP .period_bytes_min = 128, 57a40e693cSJeeja KP .period_bytes_max = AZX_MAX_BUF_SIZE / 2, 58a40e693cSJeeja KP .periods_min = 2, 59a40e693cSJeeja KP .periods_max = AZX_MAX_FRAG, 60a40e693cSJeeja KP .fifo_size = 0, 61a40e693cSJeeja KP }; 62a40e693cSJeeja KP 63a40e693cSJeeja KP static inline 64a40e693cSJeeja KP struct hdac_ext_stream *get_hdac_ext_stream(struct snd_pcm_substream *substream) 65a40e693cSJeeja KP { 66a40e693cSJeeja KP return substream->runtime->private_data; 67a40e693cSJeeja KP } 68a40e693cSJeeja KP 69a40e693cSJeeja KP static struct hdac_ext_bus *get_bus_ctx(struct snd_pcm_substream *substream) 70a40e693cSJeeja KP { 71a40e693cSJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 72a40e693cSJeeja KP struct hdac_stream *hstream = hdac_stream(stream); 73a40e693cSJeeja KP struct hdac_bus *bus = hstream->bus; 74a40e693cSJeeja KP 75a40e693cSJeeja KP return hbus_to_ebus(bus); 76a40e693cSJeeja KP } 77a40e693cSJeeja KP 78a40e693cSJeeja KP static int skl_substream_alloc_pages(struct hdac_ext_bus *ebus, 79a40e693cSJeeja KP struct snd_pcm_substream *substream, 80a40e693cSJeeja KP size_t size) 81a40e693cSJeeja KP { 82a40e693cSJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 83a40e693cSJeeja KP 84a40e693cSJeeja KP hdac_stream(stream)->bufsize = 0; 85a40e693cSJeeja KP hdac_stream(stream)->period_bytes = 0; 86a40e693cSJeeja KP hdac_stream(stream)->format_val = 0; 87a40e693cSJeeja KP 88a40e693cSJeeja KP return snd_pcm_lib_malloc_pages(substream, size); 89a40e693cSJeeja KP } 90a40e693cSJeeja KP 91a40e693cSJeeja KP static int skl_substream_free_pages(struct hdac_bus *bus, 92a40e693cSJeeja KP struct snd_pcm_substream *substream) 93a40e693cSJeeja KP { 94a40e693cSJeeja KP return snd_pcm_lib_free_pages(substream); 95a40e693cSJeeja KP } 96a40e693cSJeeja KP 97a40e693cSJeeja KP static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus, 98a40e693cSJeeja KP struct snd_pcm_runtime *runtime) 99a40e693cSJeeja KP { 100a40e693cSJeeja KP snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 101a40e693cSJeeja KP 102a40e693cSJeeja KP /* avoid wrap-around with wall-clock */ 103a40e693cSJeeja KP snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 104a40e693cSJeeja KP 20, 178000000); 105a40e693cSJeeja KP } 106a40e693cSJeeja KP 10705057001SJeeja KP static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *ebus) 10805057001SJeeja KP { 109ec8ae570SVinod Koul if ((ebus_to_hbus(ebus))->ppcap) 11005057001SJeeja KP return HDAC_EXT_STREAM_TYPE_HOST; 11105057001SJeeja KP else 11205057001SJeeja KP return HDAC_EXT_STREAM_TYPE_COUPLED; 11305057001SJeeja KP } 11405057001SJeeja KP 1154557c305SJeeja KP /* 1164557c305SJeeja KP * check if the stream opened is marked as ignore_suspend by machine, if so 1174557c305SJeeja KP * then enable suspend_active refcount 1184557c305SJeeja KP * 1194557c305SJeeja KP * The count supend_active does not need lock as it is used in open/close 1204557c305SJeeja KP * and suspend context 1214557c305SJeeja KP */ 1224557c305SJeeja KP static void skl_set_suspend_active(struct snd_pcm_substream *substream, 1234557c305SJeeja KP struct snd_soc_dai *dai, bool enable) 1244557c305SJeeja KP { 1254557c305SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 1264557c305SJeeja KP struct snd_soc_dapm_widget *w; 1274557c305SJeeja KP struct skl *skl = ebus_to_skl(ebus); 1284557c305SJeeja KP 1294557c305SJeeja KP if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 1304557c305SJeeja KP w = dai->playback_widget; 1314557c305SJeeja KP else 1324557c305SJeeja KP w = dai->capture_widget; 1334557c305SJeeja KP 1344557c305SJeeja KP if (w->ignore_suspend && enable) 1354557c305SJeeja KP skl->supend_active++; 1364557c305SJeeja KP else if (w->ignore_suspend && !enable) 1374557c305SJeeja KP skl->supend_active--; 1384557c305SJeeja KP } 1394557c305SJeeja KP 140ad036bdeSJeeja KP int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) 141ad036bdeSJeeja KP { 142ad036bdeSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dev); 143ad036bdeSJeeja KP struct hdac_bus *bus = ebus_to_hbus(ebus); 144ad036bdeSJeeja KP unsigned int format_val; 145ad036bdeSJeeja KP struct hdac_stream *hstream; 146ad036bdeSJeeja KP struct hdac_ext_stream *stream; 147ad036bdeSJeeja KP int err; 148ad036bdeSJeeja KP 149ad036bdeSJeeja KP hstream = snd_hdac_get_stream(bus, params->stream, 150ad036bdeSJeeja KP params->host_dma_id + 1); 151ad036bdeSJeeja KP if (!hstream) 152ad036bdeSJeeja KP return -EINVAL; 153ad036bdeSJeeja KP 154ad036bdeSJeeja KP stream = stream_to_hdac_ext_stream(hstream); 155ad036bdeSJeeja KP snd_hdac_ext_stream_decouple(ebus, stream, true); 156ad036bdeSJeeja KP 157ad036bdeSJeeja KP format_val = snd_hdac_calc_stream_format(params->s_freq, 158ad036bdeSJeeja KP params->ch, params->format, 32, 0); 159ad036bdeSJeeja KP 160ad036bdeSJeeja KP dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", 161ad036bdeSJeeja KP format_val, params->s_freq, params->ch, params->format); 162ad036bdeSJeeja KP 163ad036bdeSJeeja KP snd_hdac_stream_reset(hdac_stream(stream)); 164ad036bdeSJeeja KP err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); 165ad036bdeSJeeja KP if (err < 0) 166ad036bdeSJeeja KP return err; 167ad036bdeSJeeja KP 168ad036bdeSJeeja KP err = snd_hdac_stream_setup(hdac_stream(stream)); 169ad036bdeSJeeja KP if (err < 0) 170ad036bdeSJeeja KP return err; 171ad036bdeSJeeja KP 172ad036bdeSJeeja KP hdac_stream(stream)->prepared = 1; 173ad036bdeSJeeja KP 174ad036bdeSJeeja KP return 0; 175ad036bdeSJeeja KP } 176ad036bdeSJeeja KP 177ad036bdeSJeeja KP int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) 178ad036bdeSJeeja KP { 179ad036bdeSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dev); 180ad036bdeSJeeja KP struct hdac_bus *bus = ebus_to_hbus(ebus); 181ad036bdeSJeeja KP unsigned int format_val; 182ad036bdeSJeeja KP struct hdac_stream *hstream; 183ad036bdeSJeeja KP struct hdac_ext_stream *stream; 184ad036bdeSJeeja KP struct hdac_ext_link *link; 185ad036bdeSJeeja KP 186ad036bdeSJeeja KP hstream = snd_hdac_get_stream(bus, params->stream, 187ad036bdeSJeeja KP params->link_dma_id + 1); 188ad036bdeSJeeja KP if (!hstream) 189ad036bdeSJeeja KP return -EINVAL; 190ad036bdeSJeeja KP 191ad036bdeSJeeja KP stream = stream_to_hdac_ext_stream(hstream); 192ad036bdeSJeeja KP snd_hdac_ext_stream_decouple(ebus, stream, true); 193ad036bdeSJeeja KP format_val = snd_hdac_calc_stream_format(params->s_freq, 194ad036bdeSJeeja KP params->ch, params->format, 24, 0); 195ad036bdeSJeeja KP 196ad036bdeSJeeja KP dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", 197ad036bdeSJeeja KP format_val, params->s_freq, params->ch, params->format); 198ad036bdeSJeeja KP 199ad036bdeSJeeja KP snd_hdac_ext_link_stream_reset(stream); 200ad036bdeSJeeja KP 201ad036bdeSJeeja KP snd_hdac_ext_link_stream_setup(stream, format_val); 202ad036bdeSJeeja KP 203ad036bdeSJeeja KP list_for_each_entry(link, &ebus->hlink_list, list) { 204ad036bdeSJeeja KP if (link->index == params->link_index) 205ad036bdeSJeeja KP snd_hdac_ext_link_set_stream_id(link, 206ad036bdeSJeeja KP hstream->stream_tag); 207ad036bdeSJeeja KP } 208ad036bdeSJeeja KP 209ad036bdeSJeeja KP stream->link_prepared = 1; 210ad036bdeSJeeja KP 211ad036bdeSJeeja KP return 0; 212ad036bdeSJeeja KP } 213ad036bdeSJeeja KP 214a40e693cSJeeja KP static int skl_pcm_open(struct snd_pcm_substream *substream, 215a40e693cSJeeja KP struct snd_soc_dai *dai) 216a40e693cSJeeja KP { 217a40e693cSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 218a40e693cSJeeja KP struct hdac_ext_stream *stream; 219a40e693cSJeeja KP struct snd_pcm_runtime *runtime = substream->runtime; 220a40e693cSJeeja KP struct skl_dma_params *dma_params; 221a83e3b4cSVinod Koul struct skl *skl = get_skl_ctx(dai->dev); 222a83e3b4cSVinod Koul struct skl_module_cfg *mconfig; 223a40e693cSJeeja KP 224a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 225a40e693cSJeeja KP 226a40e693cSJeeja KP stream = snd_hdac_ext_stream_assign(ebus, substream, 22705057001SJeeja KP skl_get_host_stream_type(ebus)); 228a40e693cSJeeja KP if (stream == NULL) 229a40e693cSJeeja KP return -EBUSY; 230a40e693cSJeeja KP 231a40e693cSJeeja KP skl_set_pcm_constrains(ebus, runtime); 232a40e693cSJeeja KP 233a40e693cSJeeja KP /* 234a40e693cSJeeja KP * disable WALLCLOCK timestamps for capture streams 235a40e693cSJeeja KP * until we figure out how to handle digital inputs 236a40e693cSJeeja KP */ 237a40e693cSJeeja KP if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 238a40e693cSJeeja KP runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */ 239a40e693cSJeeja KP runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME; 240a40e693cSJeeja KP } 241a40e693cSJeeja KP 242a40e693cSJeeja KP runtime->private_data = stream; 243a40e693cSJeeja KP 244a40e693cSJeeja KP dma_params = kzalloc(sizeof(*dma_params), GFP_KERNEL); 245a40e693cSJeeja KP if (!dma_params) 246a40e693cSJeeja KP return -ENOMEM; 247a40e693cSJeeja KP 248a40e693cSJeeja KP dma_params->stream_tag = hdac_stream(stream)->stream_tag; 249a40e693cSJeeja KP snd_soc_dai_set_dma_data(dai, substream, dma_params); 250a40e693cSJeeja KP 251a40e693cSJeeja KP dev_dbg(dai->dev, "stream tag set in dma params=%d\n", 252a40e693cSJeeja KP dma_params->stream_tag); 2534557c305SJeeja KP skl_set_suspend_active(substream, dai, true); 254a40e693cSJeeja KP snd_pcm_set_sync(substream); 255a40e693cSJeeja KP 256a83e3b4cSVinod Koul mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 257a83e3b4cSVinod Koul skl_tplg_d0i3_get(skl, mconfig->d0i3_caps); 258a83e3b4cSVinod Koul 259a40e693cSJeeja KP return 0; 260a40e693cSJeeja KP } 261a40e693cSJeeja KP 262c115fa5eSDharageswari.R static int skl_be_prepare(struct snd_pcm_substream *substream, 263c115fa5eSDharageswari.R struct snd_soc_dai *dai) 264c115fa5eSDharageswari.R { 265c115fa5eSDharageswari.R struct skl *skl = get_skl_ctx(dai->dev); 266c115fa5eSDharageswari.R struct skl_sst *ctx = skl->skl_sst; 267c115fa5eSDharageswari.R struct skl_module_cfg *mconfig; 268c115fa5eSDharageswari.R 2691a13b1faSDharageswari.R if (dai->playback_widget->power || dai->capture_widget->power) 270c115fa5eSDharageswari.R return 0; 271c115fa5eSDharageswari.R 272c115fa5eSDharageswari.R mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); 273c115fa5eSDharageswari.R if (mconfig == NULL) 274c115fa5eSDharageswari.R return -EINVAL; 275c115fa5eSDharageswari.R 276c115fa5eSDharageswari.R return skl_dsp_set_dma_control(ctx, mconfig); 277c115fa5eSDharageswari.R } 278c115fa5eSDharageswari.R 279a40e693cSJeeja KP static int skl_pcm_prepare(struct snd_pcm_substream *substream, 280a40e693cSJeeja KP struct snd_soc_dai *dai) 281a40e693cSJeeja KP { 2822004432fSJeeja KP struct skl *skl = get_skl_ctx(dai->dev); 2832004432fSJeeja KP struct skl_module_cfg *mconfig; 284a40e693cSJeeja KP 285a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 286a40e693cSJeeja KP 2872004432fSJeeja KP mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 2882004432fSJeeja KP 2892004432fSJeeja KP /* In case of XRUN recovery, reset the FW pipe to clean state */ 2902004432fSJeeja KP if (mconfig && (substream->runtime->status->state == 2912004432fSJeeja KP SNDRV_PCM_STATE_XRUN)) 2922004432fSJeeja KP skl_reset_pipe(skl->skl_sst, mconfig->pipe); 2932004432fSJeeja KP 294bb704a73SJeeja KP return 0; 295a40e693cSJeeja KP } 296a40e693cSJeeja KP 297a40e693cSJeeja KP static int skl_pcm_hw_params(struct snd_pcm_substream *substream, 298a40e693cSJeeja KP struct snd_pcm_hw_params *params, 299a40e693cSJeeja KP struct snd_soc_dai *dai) 300a40e693cSJeeja KP { 301a40e693cSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 30205057001SJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 303a40e693cSJeeja KP struct snd_pcm_runtime *runtime = substream->runtime; 304b663a8c5SJeeja KP struct skl_pipe_params p_params = {0}; 305b663a8c5SJeeja KP struct skl_module_cfg *m_cfg; 30605057001SJeeja KP int ret, dma_id; 307a40e693cSJeeja KP 308a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 309a40e693cSJeeja KP ret = skl_substream_alloc_pages(ebus, substream, 310a40e693cSJeeja KP params_buffer_bytes(params)); 311a40e693cSJeeja KP if (ret < 0) 312a40e693cSJeeja KP return ret; 313a40e693cSJeeja KP 314a40e693cSJeeja KP dev_dbg(dai->dev, "format_val, rate=%d, ch=%d, format=%d\n", 315a40e693cSJeeja KP runtime->rate, runtime->channels, runtime->format); 316a40e693cSJeeja KP 31705057001SJeeja KP dma_id = hdac_stream(stream)->stream_tag - 1; 31805057001SJeeja KP dev_dbg(dai->dev, "dma_id=%d\n", dma_id); 31905057001SJeeja KP 320b663a8c5SJeeja KP p_params.s_fmt = snd_pcm_format_width(params_format(params)); 321b663a8c5SJeeja KP p_params.ch = params_channels(params); 322b663a8c5SJeeja KP p_params.s_freq = params_rate(params); 323b663a8c5SJeeja KP p_params.host_dma_id = dma_id; 324b663a8c5SJeeja KP p_params.stream = substream->stream; 32512c3be0eSJeeja KP p_params.format = params_format(params); 326b663a8c5SJeeja KP 327b663a8c5SJeeja KP m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream); 328b663a8c5SJeeja KP if (m_cfg) 329b663a8c5SJeeja KP skl_tplg_update_pipe_params(dai->dev, m_cfg, &p_params); 330b663a8c5SJeeja KP 331a40e693cSJeeja KP return 0; 332a40e693cSJeeja KP } 333a40e693cSJeeja KP 334a40e693cSJeeja KP static void skl_pcm_close(struct snd_pcm_substream *substream, 335a40e693cSJeeja KP struct snd_soc_dai *dai) 336a40e693cSJeeja KP { 337a40e693cSJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 33805057001SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 339a40e693cSJeeja KP struct skl_dma_params *dma_params = NULL; 340721c3e36SDharageswari.R struct skl *skl = ebus_to_skl(ebus); 341a83e3b4cSVinod Koul struct skl_module_cfg *mconfig; 342a40e693cSJeeja KP 343a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 34405057001SJeeja KP 34505057001SJeeja KP snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(ebus)); 346a40e693cSJeeja KP 347a40e693cSJeeja KP dma_params = snd_soc_dai_get_dma_data(dai, substream); 348a40e693cSJeeja KP /* 349a40e693cSJeeja KP * now we should set this to NULL as we are freeing by the 350a40e693cSJeeja KP * dma_params 351a40e693cSJeeja KP */ 352a40e693cSJeeja KP snd_soc_dai_set_dma_data(dai, substream, NULL); 3534557c305SJeeja KP skl_set_suspend_active(substream, dai, false); 354a40e693cSJeeja KP 355721c3e36SDharageswari.R /* 356721c3e36SDharageswari.R * check if close is for "Reference Pin" and set back the 357721c3e36SDharageswari.R * CGCTL.MISCBDCGE if disabled by driver 358721c3e36SDharageswari.R */ 359721c3e36SDharageswari.R if (!strncmp(dai->name, "Reference Pin", 13) && 360721c3e36SDharageswari.R skl->skl_sst->miscbdcg_disabled) { 361721c3e36SDharageswari.R skl->skl_sst->enable_miscbdcge(dai->dev, true); 362721c3e36SDharageswari.R skl->skl_sst->miscbdcg_disabled = false; 363721c3e36SDharageswari.R } 364721c3e36SDharageswari.R 365a83e3b4cSVinod Koul mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 366a83e3b4cSVinod Koul skl_tplg_d0i3_put(skl, mconfig->d0i3_caps); 367a83e3b4cSVinod Koul 368a40e693cSJeeja KP kfree(dma_params); 369a40e693cSJeeja KP } 370a40e693cSJeeja KP 371a40e693cSJeeja KP static int skl_pcm_hw_free(struct snd_pcm_substream *substream, 372a40e693cSJeeja KP struct snd_soc_dai *dai) 373a40e693cSJeeja KP { 374a40e693cSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 375a40e693cSJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 376a40e693cSJeeja KP 377a40e693cSJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 378a40e693cSJeeja KP 379a40e693cSJeeja KP snd_hdac_stream_cleanup(hdac_stream(stream)); 380a40e693cSJeeja KP hdac_stream(stream)->prepared = 0; 381a40e693cSJeeja KP 382a40e693cSJeeja KP return skl_substream_free_pages(ebus_to_hbus(ebus), substream); 383a40e693cSJeeja KP } 384a40e693cSJeeja KP 385b663a8c5SJeeja KP static int skl_be_hw_params(struct snd_pcm_substream *substream, 386b663a8c5SJeeja KP struct snd_pcm_hw_params *params, 387b663a8c5SJeeja KP struct snd_soc_dai *dai) 388b663a8c5SJeeja KP { 389b663a8c5SJeeja KP struct skl_pipe_params p_params = {0}; 390b663a8c5SJeeja KP 391b663a8c5SJeeja KP p_params.s_fmt = snd_pcm_format_width(params_format(params)); 392b663a8c5SJeeja KP p_params.ch = params_channels(params); 393b663a8c5SJeeja KP p_params.s_freq = params_rate(params); 394b663a8c5SJeeja KP p_params.stream = substream->stream; 395b663a8c5SJeeja KP 3964bd073f9SJeeja KP return skl_tplg_be_update_params(dai, &p_params); 397b663a8c5SJeeja KP } 398b663a8c5SJeeja KP 399d1730c3dSJeeja KP static int skl_decoupled_trigger(struct snd_pcm_substream *substream, 400d1730c3dSJeeja KP int cmd) 401d1730c3dSJeeja KP { 402d1730c3dSJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 403d1730c3dSJeeja KP struct hdac_bus *bus = ebus_to_hbus(ebus); 404d1730c3dSJeeja KP struct hdac_ext_stream *stream; 405d1730c3dSJeeja KP int start; 406d1730c3dSJeeja KP unsigned long cookie; 407d1730c3dSJeeja KP struct hdac_stream *hstr; 408d1730c3dSJeeja KP 409d1730c3dSJeeja KP stream = get_hdac_ext_stream(substream); 410d1730c3dSJeeja KP hstr = hdac_stream(stream); 411d1730c3dSJeeja KP 412d1730c3dSJeeja KP if (!hstr->prepared) 413d1730c3dSJeeja KP return -EPIPE; 414d1730c3dSJeeja KP 415d1730c3dSJeeja KP switch (cmd) { 416d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_START: 417d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 418d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_RESUME: 419d1730c3dSJeeja KP start = 1; 420d1730c3dSJeeja KP break; 421d1730c3dSJeeja KP 422d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 423d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_SUSPEND: 424d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_STOP: 425d1730c3dSJeeja KP start = 0; 426d1730c3dSJeeja KP break; 427d1730c3dSJeeja KP 428d1730c3dSJeeja KP default: 429d1730c3dSJeeja KP return -EINVAL; 430d1730c3dSJeeja KP } 431d1730c3dSJeeja KP 432d1730c3dSJeeja KP spin_lock_irqsave(&bus->reg_lock, cookie); 433d1730c3dSJeeja KP 434d1730c3dSJeeja KP if (start) { 435d1730c3dSJeeja KP snd_hdac_stream_start(hdac_stream(stream), true); 436d1730c3dSJeeja KP snd_hdac_stream_timecounter_init(hstr, 0); 437d1730c3dSJeeja KP } else { 438d1730c3dSJeeja KP snd_hdac_stream_stop(hdac_stream(stream)); 439d1730c3dSJeeja KP } 440d1730c3dSJeeja KP 441d1730c3dSJeeja KP spin_unlock_irqrestore(&bus->reg_lock, cookie); 442d1730c3dSJeeja KP 443d1730c3dSJeeja KP return 0; 444d1730c3dSJeeja KP } 445d1730c3dSJeeja KP 446b663a8c5SJeeja KP static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, 447b663a8c5SJeeja KP struct snd_soc_dai *dai) 448b663a8c5SJeeja KP { 449b663a8c5SJeeja KP struct skl *skl = get_skl_ctx(dai->dev); 450b663a8c5SJeeja KP struct skl_sst *ctx = skl->skl_sst; 451b663a8c5SJeeja KP struct skl_module_cfg *mconfig; 4527e3a17d3SJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 4537e3a17d3SJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 4549a655db0SJeeja KP struct snd_soc_dapm_widget *w; 455d1730c3dSJeeja KP int ret; 456b663a8c5SJeeja KP 457b663a8c5SJeeja KP mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); 458b663a8c5SJeeja KP if (!mconfig) 459b663a8c5SJeeja KP return -EIO; 460b663a8c5SJeeja KP 4619a655db0SJeeja KP if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 4629a655db0SJeeja KP w = dai->playback_widget; 4639a655db0SJeeja KP else 4649a655db0SJeeja KP w = dai->capture_widget; 4659a655db0SJeeja KP 466b663a8c5SJeeja KP switch (cmd) { 4677e3a17d3SJeeja KP case SNDRV_PCM_TRIGGER_RESUME: 4689a655db0SJeeja KP if (!w->ignore_suspend) { 469748a1d5aSJeeja KP /* 4709a655db0SJeeja KP * enable DMA Resume enable bit for the stream, set the 4719a655db0SJeeja KP * dpib & lpib position to resume before starting the 4729a655db0SJeeja KP * DMA 473748a1d5aSJeeja KP */ 474748a1d5aSJeeja KP snd_hdac_ext_stream_drsm_enable(ebus, true, 475748a1d5aSJeeja KP hdac_stream(stream)->index); 4769a655db0SJeeja KP snd_hdac_ext_stream_set_dpibr(ebus, stream, 477a700a1e6SJeeja KP stream->lpib); 478748a1d5aSJeeja KP snd_hdac_ext_stream_set_lpib(stream, stream->lpib); 4799a655db0SJeeja KP } 480748a1d5aSJeeja KP 481d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_START: 482b663a8c5SJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 483d1730c3dSJeeja KP /* 484d1730c3dSJeeja KP * Start HOST DMA and Start FE Pipe.This is to make sure that 485d1730c3dSJeeja KP * there are no underrun/overrun in the case when the FE 486d1730c3dSJeeja KP * pipeline is started but there is a delay in starting the 487d1730c3dSJeeja KP * DMA channel on the host. 488d1730c3dSJeeja KP */ 489d1730c3dSJeeja KP ret = skl_decoupled_trigger(substream, cmd); 490d1730c3dSJeeja KP if (ret < 0) 491d1730c3dSJeeja KP return ret; 492b663a8c5SJeeja KP return skl_run_pipe(ctx, mconfig->pipe); 493d1730c3dSJeeja KP break; 494b663a8c5SJeeja KP 495b663a8c5SJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 496b663a8c5SJeeja KP case SNDRV_PCM_TRIGGER_SUSPEND: 497d1730c3dSJeeja KP case SNDRV_PCM_TRIGGER_STOP: 498d1730c3dSJeeja KP /* 499d1730c3dSJeeja KP * Stop FE Pipe first and stop DMA. This is to make sure that 500d1730c3dSJeeja KP * there are no underrun/overrun in the case if there is a delay 501d1730c3dSJeeja KP * between the two operations. 502d1730c3dSJeeja KP */ 503d1730c3dSJeeja KP ret = skl_stop_pipe(ctx, mconfig->pipe); 504d1730c3dSJeeja KP if (ret < 0) 505d1730c3dSJeeja KP return ret; 506d1730c3dSJeeja KP 507d1730c3dSJeeja KP ret = skl_decoupled_trigger(substream, cmd); 5089a655db0SJeeja KP if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) { 509748a1d5aSJeeja KP /* save the dpib and lpib positions */ 510748a1d5aSJeeja KP stream->dpib = readl(ebus->bus.remap_addr + 511748a1d5aSJeeja KP AZX_REG_VS_SDXDPIB_XBASE + 512748a1d5aSJeeja KP (AZX_REG_VS_SDXDPIB_XINTERVAL * 513748a1d5aSJeeja KP hdac_stream(stream)->index)); 514748a1d5aSJeeja KP 515748a1d5aSJeeja KP stream->lpib = snd_hdac_stream_get_pos_lpib( 516748a1d5aSJeeja KP hdac_stream(stream)); 5177e3a17d3SJeeja KP snd_hdac_ext_stream_decouple(ebus, stream, false); 518748a1d5aSJeeja KP } 519d1730c3dSJeeja KP break; 520b663a8c5SJeeja KP 521b663a8c5SJeeja KP default: 522d1730c3dSJeeja KP return -EINVAL; 523b663a8c5SJeeja KP } 524d1730c3dSJeeja KP 525d1730c3dSJeeja KP return 0; 526b663a8c5SJeeja KP } 527b663a8c5SJeeja KP 52805057001SJeeja KP static int skl_link_hw_params(struct snd_pcm_substream *substream, 52905057001SJeeja KP struct snd_pcm_hw_params *params, 53005057001SJeeja KP struct snd_soc_dai *dai) 53105057001SJeeja KP { 53205057001SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 53305057001SJeeja KP struct hdac_ext_stream *link_dev; 53405057001SJeeja KP struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 535aceb5d20SSubhransu S. Prusty struct hdac_ext_dma_params *dma_params; 53605057001SJeeja KP struct snd_soc_dai *codec_dai = rtd->codec_dai; 537b663a8c5SJeeja KP struct skl_pipe_params p_params = {0}; 53812c3be0eSJeeja KP struct hdac_ext_link *link; 53905057001SJeeja KP 54005057001SJeeja KP link_dev = snd_hdac_ext_stream_assign(ebus, substream, 54105057001SJeeja KP HDAC_EXT_STREAM_TYPE_LINK); 54205057001SJeeja KP if (!link_dev) 54305057001SJeeja KP return -EBUSY; 54405057001SJeeja KP 54505057001SJeeja KP snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); 54605057001SJeeja KP 54712c3be0eSJeeja KP link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); 54812c3be0eSJeeja KP if (!link) 54912c3be0eSJeeja KP return -EINVAL; 55012c3be0eSJeeja KP 55105057001SJeeja KP /* set the stream tag in the codec dai dma params */ 552aceb5d20SSubhransu S. Prusty dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); 55305057001SJeeja KP if (dma_params) 55405057001SJeeja KP dma_params->stream_tag = hdac_stream(link_dev)->stream_tag; 555b663a8c5SJeeja KP 556b663a8c5SJeeja KP p_params.s_fmt = snd_pcm_format_width(params_format(params)); 557b663a8c5SJeeja KP p_params.ch = params_channels(params); 558b663a8c5SJeeja KP p_params.s_freq = params_rate(params); 559b663a8c5SJeeja KP p_params.stream = substream->stream; 560b663a8c5SJeeja KP p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1; 56112c3be0eSJeeja KP p_params.link_index = link->index; 56212c3be0eSJeeja KP p_params.format = params_format(params); 563b663a8c5SJeeja KP 5644bd073f9SJeeja KP return skl_tplg_be_update_params(dai, &p_params); 56505057001SJeeja KP } 56605057001SJeeja KP 56705057001SJeeja KP static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, 56805057001SJeeja KP struct snd_soc_dai *dai) 56905057001SJeeja KP { 5702004432fSJeeja KP struct skl *skl = get_skl_ctx(dai->dev); 5712004432fSJeeja KP struct skl_module_cfg *mconfig = NULL; 57205057001SJeeja KP 5732004432fSJeeja KP /* In case of XRUN recovery, reset the FW pipe to clean state */ 5742004432fSJeeja KP mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); 5757cbfdf87SJeeja KP if (mconfig && !mconfig->pipe->passthru && 5767cbfdf87SJeeja KP (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) 5772004432fSJeeja KP skl_reset_pipe(skl->skl_sst, mconfig->pipe); 5782004432fSJeeja KP 57905057001SJeeja KP return 0; 58005057001SJeeja KP } 58105057001SJeeja KP 58205057001SJeeja KP static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, 58305057001SJeeja KP int cmd, struct snd_soc_dai *dai) 58405057001SJeeja KP { 58505057001SJeeja KP struct hdac_ext_stream *link_dev = 58605057001SJeeja KP snd_soc_dai_get_dma_data(dai, substream); 587920982c9SJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 588920982c9SJeeja KP struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); 58905057001SJeeja KP 59005057001SJeeja KP dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); 59105057001SJeeja KP switch (cmd) { 592920982c9SJeeja KP case SNDRV_PCM_TRIGGER_RESUME: 59305057001SJeeja KP case SNDRV_PCM_TRIGGER_START: 59405057001SJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 59505057001SJeeja KP snd_hdac_ext_link_stream_start(link_dev); 59605057001SJeeja KP break; 59705057001SJeeja KP 59805057001SJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 59905057001SJeeja KP case SNDRV_PCM_TRIGGER_SUSPEND: 60005057001SJeeja KP case SNDRV_PCM_TRIGGER_STOP: 60105057001SJeeja KP snd_hdac_ext_link_stream_clear(link_dev); 602920982c9SJeeja KP if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) 603920982c9SJeeja KP snd_hdac_ext_stream_decouple(ebus, stream, false); 60405057001SJeeja KP break; 60505057001SJeeja KP 60605057001SJeeja KP default: 60705057001SJeeja KP return -EINVAL; 60805057001SJeeja KP } 60905057001SJeeja KP return 0; 61005057001SJeeja KP } 61105057001SJeeja KP 61205057001SJeeja KP static int skl_link_hw_free(struct snd_pcm_substream *substream, 61305057001SJeeja KP struct snd_soc_dai *dai) 61405057001SJeeja KP { 61505057001SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 61605057001SJeeja KP struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 61705057001SJeeja KP struct hdac_ext_stream *link_dev = 61805057001SJeeja KP snd_soc_dai_get_dma_data(dai, substream); 61905057001SJeeja KP struct hdac_ext_link *link; 62005057001SJeeja KP 62105057001SJeeja KP dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); 62205057001SJeeja KP 62305057001SJeeja KP link_dev->link_prepared = 0; 62405057001SJeeja KP 62505057001SJeeja KP link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); 62605057001SJeeja KP if (!link) 62705057001SJeeja KP return -EINVAL; 62805057001SJeeja KP 62905057001SJeeja KP snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_dev)->stream_tag); 63005057001SJeeja KP snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); 63105057001SJeeja KP return 0; 63205057001SJeeja KP } 63305057001SJeeja KP 634a40e693cSJeeja KP static struct snd_soc_dai_ops skl_pcm_dai_ops = { 635a40e693cSJeeja KP .startup = skl_pcm_open, 636a40e693cSJeeja KP .shutdown = skl_pcm_close, 637a40e693cSJeeja KP .prepare = skl_pcm_prepare, 638a40e693cSJeeja KP .hw_params = skl_pcm_hw_params, 639a40e693cSJeeja KP .hw_free = skl_pcm_hw_free, 640b663a8c5SJeeja KP .trigger = skl_pcm_trigger, 641a40e693cSJeeja KP }; 642a40e693cSJeeja KP 64305057001SJeeja KP static struct snd_soc_dai_ops skl_dmic_dai_ops = { 644b663a8c5SJeeja KP .hw_params = skl_be_hw_params, 645b663a8c5SJeeja KP }; 646b663a8c5SJeeja KP 647b663a8c5SJeeja KP static struct snd_soc_dai_ops skl_be_ssp_dai_ops = { 648b663a8c5SJeeja KP .hw_params = skl_be_hw_params, 649c115fa5eSDharageswari.R .prepare = skl_be_prepare, 65005057001SJeeja KP }; 65105057001SJeeja KP 65205057001SJeeja KP static struct snd_soc_dai_ops skl_link_dai_ops = { 65305057001SJeeja KP .prepare = skl_link_pcm_prepare, 65405057001SJeeja KP .hw_params = skl_link_hw_params, 65505057001SJeeja KP .hw_free = skl_link_hw_free, 65605057001SJeeja KP .trigger = skl_link_pcm_trigger, 65705057001SJeeja KP }; 65805057001SJeeja KP 659a40e693cSJeeja KP static struct snd_soc_dai_driver skl_platform_dai[] = { 660a40e693cSJeeja KP { 661a40e693cSJeeja KP .name = "System Pin", 662a40e693cSJeeja KP .ops = &skl_pcm_dai_ops, 663a40e693cSJeeja KP .playback = { 664a40e693cSJeeja KP .stream_name = "System Playback", 665a40e693cSJeeja KP .channels_min = HDA_MONO, 666a40e693cSJeeja KP .channels_max = HDA_STEREO, 667a40e693cSJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, 668dde53bccSSamaga Krishna .formats = SNDRV_PCM_FMTBIT_S16_LE | 669dde53bccSSamaga Krishna SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, 670a40e693cSJeeja KP }, 671a40e693cSJeeja KP .capture = { 672a40e693cSJeeja KP .stream_name = "System Capture", 673a40e693cSJeeja KP .channels_min = HDA_MONO, 674a40e693cSJeeja KP .channels_max = HDA_STEREO, 675a40e693cSJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 676a40e693cSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 677a40e693cSJeeja KP }, 678a40e693cSJeeja KP }, 679a40e693cSJeeja KP { 68005057001SJeeja KP .name = "Reference Pin", 68105057001SJeeja KP .ops = &skl_pcm_dai_ops, 68205057001SJeeja KP .capture = { 68305057001SJeeja KP .stream_name = "Reference Capture", 68405057001SJeeja KP .channels_min = HDA_MONO, 6858f35bf3fSJeeja KP .channels_max = HDA_QUAD, 68605057001SJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 68705057001SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 68805057001SJeeja KP }, 68905057001SJeeja KP }, 69005057001SJeeja KP { 691a40e693cSJeeja KP .name = "Deepbuffer Pin", 692a40e693cSJeeja KP .ops = &skl_pcm_dai_ops, 693a40e693cSJeeja KP .playback = { 694a40e693cSJeeja KP .stream_name = "Deepbuffer Playback", 695a40e693cSJeeja KP .channels_min = HDA_STEREO, 696a40e693cSJeeja KP .channels_max = HDA_STEREO, 697a40e693cSJeeja KP .rates = SNDRV_PCM_RATE_48000, 698a40e693cSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 699a40e693cSJeeja KP }, 700a40e693cSJeeja KP }, 701a40e693cSJeeja KP { 702a40e693cSJeeja KP .name = "LowLatency Pin", 703a40e693cSJeeja KP .ops = &skl_pcm_dai_ops, 704a40e693cSJeeja KP .playback = { 705a40e693cSJeeja KP .stream_name = "Low Latency Playback", 706a40e693cSJeeja KP .channels_min = HDA_STEREO, 707a40e693cSJeeja KP .channels_max = HDA_STEREO, 708a40e693cSJeeja KP .rates = SNDRV_PCM_RATE_48000, 709a40e693cSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 710a40e693cSJeeja KP }, 711a40e693cSJeeja KP }, 7128f35bf3fSJeeja KP { 7138f35bf3fSJeeja KP .name = "DMIC Pin", 7148f35bf3fSJeeja KP .ops = &skl_pcm_dai_ops, 7158f35bf3fSJeeja KP .capture = { 7168f35bf3fSJeeja KP .stream_name = "DMIC Capture", 7178f35bf3fSJeeja KP .channels_min = HDA_MONO, 7188f35bf3fSJeeja KP .channels_max = HDA_QUAD, 7198f35bf3fSJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 7208f35bf3fSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 7218f35bf3fSJeeja KP }, 7228f35bf3fSJeeja KP }, 7238cca87c0SSubhransu S. Prusty { 7248cca87c0SSubhransu S. Prusty .name = "HDMI1 Pin", 7258cca87c0SSubhransu S. Prusty .ops = &skl_pcm_dai_ops, 7268cca87c0SSubhransu S. Prusty .playback = { 7278cca87c0SSubhransu S. Prusty .stream_name = "HDMI1 Playback", 7288cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 7297e12dc87SSubhransu S. Prusty .channels_max = 8, 7308cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | 7318cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | 7328cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | 7338cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_192000, 7348cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 7358cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S32_LE, 7368cca87c0SSubhransu S. Prusty }, 7378cca87c0SSubhransu S. Prusty }, 7388cca87c0SSubhransu S. Prusty { 7398cca87c0SSubhransu S. Prusty .name = "HDMI2 Pin", 7408cca87c0SSubhransu S. Prusty .ops = &skl_pcm_dai_ops, 7418cca87c0SSubhransu S. Prusty .playback = { 7428cca87c0SSubhransu S. Prusty .stream_name = "HDMI2 Playback", 7438cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 7447e12dc87SSubhransu S. Prusty .channels_max = 8, 7458cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | 7468cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | 7478cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | 7488cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_192000, 7498cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 7508cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S32_LE, 7518cca87c0SSubhransu S. Prusty }, 7528cca87c0SSubhransu S. Prusty }, 7538cca87c0SSubhransu S. Prusty { 7548cca87c0SSubhransu S. Prusty .name = "HDMI3 Pin", 7558cca87c0SSubhransu S. Prusty .ops = &skl_pcm_dai_ops, 7568cca87c0SSubhransu S. Prusty .playback = { 7578cca87c0SSubhransu S. Prusty .stream_name = "HDMI3 Playback", 7588cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 7597e12dc87SSubhransu S. Prusty .channels_max = 8, 7608cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | 7618cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | 7628cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | 7638cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_192000, 7648cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 7658cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S32_LE, 7668cca87c0SSubhransu S. Prusty }, 7678cca87c0SSubhransu S. Prusty }, 7688f35bf3fSJeeja KP 76905057001SJeeja KP /* BE CPU Dais */ 77005057001SJeeja KP { 771b663a8c5SJeeja KP .name = "SSP0 Pin", 772b663a8c5SJeeja KP .ops = &skl_be_ssp_dai_ops, 773b663a8c5SJeeja KP .playback = { 774b663a8c5SJeeja KP .stream_name = "ssp0 Tx", 775b663a8c5SJeeja KP .channels_min = HDA_STEREO, 776b663a8c5SJeeja KP .channels_max = HDA_STEREO, 777b663a8c5SJeeja KP .rates = SNDRV_PCM_RATE_48000, 778b663a8c5SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 779b663a8c5SJeeja KP }, 780b663a8c5SJeeja KP .capture = { 781b663a8c5SJeeja KP .stream_name = "ssp0 Rx", 782b663a8c5SJeeja KP .channels_min = HDA_STEREO, 783b663a8c5SJeeja KP .channels_max = HDA_STEREO, 784b663a8c5SJeeja KP .rates = SNDRV_PCM_RATE_48000, 785b663a8c5SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 786b663a8c5SJeeja KP }, 787b663a8c5SJeeja KP }, 788b663a8c5SJeeja KP { 789c80fd4daSJeeja KP .name = "SSP1 Pin", 790c80fd4daSJeeja KP .ops = &skl_be_ssp_dai_ops, 791c80fd4daSJeeja KP .playback = { 792c80fd4daSJeeja KP .stream_name = "ssp1 Tx", 793c80fd4daSJeeja KP .channels_min = HDA_STEREO, 794c80fd4daSJeeja KP .channels_max = HDA_STEREO, 795c80fd4daSJeeja KP .rates = SNDRV_PCM_RATE_48000, 796c80fd4daSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 797c80fd4daSJeeja KP }, 798c80fd4daSJeeja KP .capture = { 799c80fd4daSJeeja KP .stream_name = "ssp1 Rx", 800c80fd4daSJeeja KP .channels_min = HDA_STEREO, 801c80fd4daSJeeja KP .channels_max = HDA_STEREO, 802c80fd4daSJeeja KP .rates = SNDRV_PCM_RATE_48000, 803c80fd4daSJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 804c80fd4daSJeeja KP }, 805c80fd4daSJeeja KP }, 806c80fd4daSJeeja KP { 807fcc494afSPardha Saradhi K .name = "SSP2 Pin", 808fcc494afSPardha Saradhi K .ops = &skl_be_ssp_dai_ops, 809fcc494afSPardha Saradhi K .playback = { 810fcc494afSPardha Saradhi K .stream_name = "ssp2 Tx", 811fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 812fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 813fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 814fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 815fcc494afSPardha Saradhi K }, 816fcc494afSPardha Saradhi K .capture = { 817fcc494afSPardha Saradhi K .stream_name = "ssp2 Rx", 818fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 819fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 820fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 821fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 822fcc494afSPardha Saradhi K }, 823fcc494afSPardha Saradhi K }, 824fcc494afSPardha Saradhi K { 825fcc494afSPardha Saradhi K .name = "SSP3 Pin", 826fcc494afSPardha Saradhi K .ops = &skl_be_ssp_dai_ops, 827fcc494afSPardha Saradhi K .playback = { 828fcc494afSPardha Saradhi K .stream_name = "ssp3 Tx", 829fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 830fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 831fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 832fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 833fcc494afSPardha Saradhi K }, 834fcc494afSPardha Saradhi K .capture = { 835fcc494afSPardha Saradhi K .stream_name = "ssp3 Rx", 836fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 837fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 838fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 839fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 840fcc494afSPardha Saradhi K }, 841fcc494afSPardha Saradhi K }, 842fcc494afSPardha Saradhi K { 843fcc494afSPardha Saradhi K .name = "SSP4 Pin", 844fcc494afSPardha Saradhi K .ops = &skl_be_ssp_dai_ops, 845fcc494afSPardha Saradhi K .playback = { 846fcc494afSPardha Saradhi K .stream_name = "ssp4 Tx", 847fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 848fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 849fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 850fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 851fcc494afSPardha Saradhi K }, 852fcc494afSPardha Saradhi K .capture = { 853fcc494afSPardha Saradhi K .stream_name = "ssp4 Rx", 854fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 855fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 856fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 857fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 858fcc494afSPardha Saradhi K }, 859fcc494afSPardha Saradhi K }, 860fcc494afSPardha Saradhi K { 861fcc494afSPardha Saradhi K .name = "SSP5 Pin", 862fcc494afSPardha Saradhi K .ops = &skl_be_ssp_dai_ops, 863fcc494afSPardha Saradhi K .playback = { 864fcc494afSPardha Saradhi K .stream_name = "ssp5 Tx", 865fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 866fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 867fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 868fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 869fcc494afSPardha Saradhi K }, 870fcc494afSPardha Saradhi K .capture = { 871fcc494afSPardha Saradhi K .stream_name = "ssp5 Rx", 872fcc494afSPardha Saradhi K .channels_min = HDA_STEREO, 873fcc494afSPardha Saradhi K .channels_max = HDA_STEREO, 874fcc494afSPardha Saradhi K .rates = SNDRV_PCM_RATE_48000, 875fcc494afSPardha Saradhi K .formats = SNDRV_PCM_FMTBIT_S16_LE, 876fcc494afSPardha Saradhi K }, 877fcc494afSPardha Saradhi K }, 878fcc494afSPardha Saradhi K { 8798cca87c0SSubhransu S. Prusty .name = "iDisp1 Pin", 88005057001SJeeja KP .ops = &skl_link_dai_ops, 88105057001SJeeja KP .playback = { 8828cca87c0SSubhransu S. Prusty .stream_name = "iDisp1 Tx", 88305057001SJeeja KP .channels_min = HDA_STEREO, 8847e12dc87SSubhransu S. Prusty .channels_max = 8, 88505057001SJeeja KP .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, 8868cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | 8878cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S24_LE, 8888cca87c0SSubhransu S. Prusty }, 8898cca87c0SSubhransu S. Prusty }, 8908cca87c0SSubhransu S. Prusty { 8918cca87c0SSubhransu S. Prusty .name = "iDisp2 Pin", 8928cca87c0SSubhransu S. Prusty .ops = &skl_link_dai_ops, 8938cca87c0SSubhransu S. Prusty .playback = { 8948cca87c0SSubhransu S. Prusty .stream_name = "iDisp2 Tx", 8958cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 8967e12dc87SSubhransu S. Prusty .channels_max = 8, 8978cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| 8988cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000, 8998cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | 9008cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S24_LE, 9018cca87c0SSubhransu S. Prusty }, 9028cca87c0SSubhransu S. Prusty }, 9038cca87c0SSubhransu S. Prusty { 9048cca87c0SSubhransu S. Prusty .name = "iDisp3 Pin", 9058cca87c0SSubhransu S. Prusty .ops = &skl_link_dai_ops, 9068cca87c0SSubhransu S. Prusty .playback = { 9078cca87c0SSubhransu S. Prusty .stream_name = "iDisp3 Tx", 9088cca87c0SSubhransu S. Prusty .channels_min = HDA_STEREO, 9097e12dc87SSubhransu S. Prusty .channels_max = 8, 9108cca87c0SSubhransu S. Prusty .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| 9118cca87c0SSubhransu S. Prusty SNDRV_PCM_RATE_48000, 9128cca87c0SSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | 9138cca87c0SSubhransu S. Prusty SNDRV_PCM_FMTBIT_S24_LE, 91405057001SJeeja KP }, 91505057001SJeeja KP }, 91605057001SJeeja KP { 91705057001SJeeja KP .name = "DMIC01 Pin", 91805057001SJeeja KP .ops = &skl_dmic_dai_ops, 91905057001SJeeja KP .capture = { 92005057001SJeeja KP .stream_name = "DMIC01 Rx", 9218f35bf3fSJeeja KP .channels_min = HDA_MONO, 9228f35bf3fSJeeja KP .channels_max = HDA_QUAD, 92305057001SJeeja KP .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, 92405057001SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 92505057001SJeeja KP }, 92605057001SJeeja KP }, 92705057001SJeeja KP { 92805057001SJeeja KP .name = "HD-Codec Pin", 92905057001SJeeja KP .ops = &skl_link_dai_ops, 93005057001SJeeja KP .playback = { 93105057001SJeeja KP .stream_name = "HD-Codec Tx", 93205057001SJeeja KP .channels_min = HDA_STEREO, 93305057001SJeeja KP .channels_max = HDA_STEREO, 93405057001SJeeja KP .rates = SNDRV_PCM_RATE_48000, 93505057001SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 93605057001SJeeja KP }, 93705057001SJeeja KP .capture = { 93805057001SJeeja KP .stream_name = "HD-Codec Rx", 93905057001SJeeja KP .channels_min = HDA_STEREO, 94005057001SJeeja KP .channels_max = HDA_STEREO, 94105057001SJeeja KP .rates = SNDRV_PCM_RATE_48000, 94205057001SJeeja KP .formats = SNDRV_PCM_FMTBIT_S16_LE, 94305057001SJeeja KP }, 94405057001SJeeja KP }, 945a40e693cSJeeja KP }; 946a40e693cSJeeja KP 947a40e693cSJeeja KP static int skl_platform_open(struct snd_pcm_substream *substream) 948a40e693cSJeeja KP { 949a40e693cSJeeja KP struct snd_pcm_runtime *runtime; 950a40e693cSJeeja KP struct snd_soc_pcm_runtime *rtd = substream->private_data; 951a40e693cSJeeja KP struct snd_soc_dai_link *dai_link = rtd->dai_link; 952a40e693cSJeeja KP 953a40e693cSJeeja KP dev_dbg(rtd->cpu_dai->dev, "In %s:%s\n", __func__, 954a40e693cSJeeja KP dai_link->cpu_dai_name); 955a40e693cSJeeja KP 956a40e693cSJeeja KP runtime = substream->runtime; 957a40e693cSJeeja KP snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw); 958a40e693cSJeeja KP 959a40e693cSJeeja KP return 0; 960a40e693cSJeeja KP } 961a40e693cSJeeja KP 962b663a8c5SJeeja KP static int skl_coupled_trigger(struct snd_pcm_substream *substream, 963a40e693cSJeeja KP int cmd) 964a40e693cSJeeja KP { 965a40e693cSJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 966a40e693cSJeeja KP struct hdac_bus *bus = ebus_to_hbus(ebus); 967a40e693cSJeeja KP struct hdac_ext_stream *stream; 968a40e693cSJeeja KP struct snd_pcm_substream *s; 969a40e693cSJeeja KP bool start; 970a40e693cSJeeja KP int sbits = 0; 971a40e693cSJeeja KP unsigned long cookie; 972a40e693cSJeeja KP struct hdac_stream *hstr; 973a40e693cSJeeja KP 974a40e693cSJeeja KP stream = get_hdac_ext_stream(substream); 975a40e693cSJeeja KP hstr = hdac_stream(stream); 976a40e693cSJeeja KP 977a40e693cSJeeja KP dev_dbg(bus->dev, "In %s cmd=%d\n", __func__, cmd); 978a40e693cSJeeja KP 979a40e693cSJeeja KP if (!hstr->prepared) 980a40e693cSJeeja KP return -EPIPE; 981a40e693cSJeeja KP 982a40e693cSJeeja KP switch (cmd) { 983a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_START: 984a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 985a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_RESUME: 986a40e693cSJeeja KP start = true; 987a40e693cSJeeja KP break; 988a40e693cSJeeja KP 989a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 990a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_SUSPEND: 991a40e693cSJeeja KP case SNDRV_PCM_TRIGGER_STOP: 992a40e693cSJeeja KP start = false; 993a40e693cSJeeja KP break; 994a40e693cSJeeja KP 995a40e693cSJeeja KP default: 996a40e693cSJeeja KP return -EINVAL; 997a40e693cSJeeja KP } 998a40e693cSJeeja KP 999a40e693cSJeeja KP snd_pcm_group_for_each_entry(s, substream) { 1000a40e693cSJeeja KP if (s->pcm->card != substream->pcm->card) 1001a40e693cSJeeja KP continue; 1002a40e693cSJeeja KP stream = get_hdac_ext_stream(s); 1003a40e693cSJeeja KP sbits |= 1 << hdac_stream(stream)->index; 1004a40e693cSJeeja KP snd_pcm_trigger_done(s, substream); 1005a40e693cSJeeja KP } 1006a40e693cSJeeja KP 1007a40e693cSJeeja KP spin_lock_irqsave(&bus->reg_lock, cookie); 1008a40e693cSJeeja KP 1009a40e693cSJeeja KP /* first, set SYNC bits of corresponding streams */ 1010a40e693cSJeeja KP snd_hdac_stream_sync_trigger(hstr, true, sbits, AZX_REG_SSYNC); 1011a40e693cSJeeja KP 1012a40e693cSJeeja KP snd_pcm_group_for_each_entry(s, substream) { 1013a40e693cSJeeja KP if (s->pcm->card != substream->pcm->card) 1014a40e693cSJeeja KP continue; 1015a40e693cSJeeja KP stream = get_hdac_ext_stream(s); 1016a40e693cSJeeja KP if (start) 1017a40e693cSJeeja KP snd_hdac_stream_start(hdac_stream(stream), true); 1018a40e693cSJeeja KP else 1019a40e693cSJeeja KP snd_hdac_stream_stop(hdac_stream(stream)); 1020a40e693cSJeeja KP } 1021a40e693cSJeeja KP spin_unlock_irqrestore(&bus->reg_lock, cookie); 1022a40e693cSJeeja KP 1023a40e693cSJeeja KP snd_hdac_stream_sync(hstr, start, sbits); 1024a40e693cSJeeja KP 1025a40e693cSJeeja KP spin_lock_irqsave(&bus->reg_lock, cookie); 1026a40e693cSJeeja KP 1027a40e693cSJeeja KP /* reset SYNC bits */ 1028a40e693cSJeeja KP snd_hdac_stream_sync_trigger(hstr, false, sbits, AZX_REG_SSYNC); 1029a40e693cSJeeja KP if (start) 1030a40e693cSJeeja KP snd_hdac_stream_timecounter_init(hstr, sbits); 1031a40e693cSJeeja KP spin_unlock_irqrestore(&bus->reg_lock, cookie); 1032a40e693cSJeeja KP 1033a40e693cSJeeja KP return 0; 1034a40e693cSJeeja KP } 1035a40e693cSJeeja KP 103605057001SJeeja KP static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, 103705057001SJeeja KP int cmd) 103805057001SJeeja KP { 103905057001SJeeja KP struct hdac_ext_bus *ebus = get_bus_ctx(substream); 104005057001SJeeja KP 1041fc94733eSVinod Koul if (!(ebus_to_hbus(ebus))->ppcap) 1042b663a8c5SJeeja KP return skl_coupled_trigger(substream, cmd); 1043d1730c3dSJeeja KP 1044d1730c3dSJeeja KP return 0; 104505057001SJeeja KP } 104605057001SJeeja KP 10477b96144dSJeeja KP static snd_pcm_uframes_t skl_platform_pcm_pointer 10487b96144dSJeeja KP (struct snd_pcm_substream *substream) 1049a40e693cSJeeja KP { 10507b96144dSJeeja KP struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); 1051ca590c1cSDharageswari R struct hdac_ext_bus *ebus = get_bus_ctx(substream); 1052a40e693cSJeeja KP unsigned int pos; 1053a40e693cSJeeja KP 1054ca590c1cSDharageswari R /* 1055ca590c1cSDharageswari R * Use DPIB for Playback stream as the periodic DMA Position-in- 1056ca590c1cSDharageswari R * Buffer Writes may be scheduled at the same time or later than 1057ca590c1cSDharageswari R * the MSI and does not guarantee to reflect the Position of the 1058ca590c1cSDharageswari R * last buffer that was transferred. Whereas DPIB register in 1059ca590c1cSDharageswari R * HAD space reflects the actual data that is transferred. 1060ca590c1cSDharageswari R * Use the position buffer for capture, as DPIB write gets 1061ca590c1cSDharageswari R * completed earlier than the actual data written to the DDR. 1062ca590c1cSDharageswari R */ 1063ca590c1cSDharageswari R if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 1064ca590c1cSDharageswari R pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE + 1065ca590c1cSDharageswari R (AZX_REG_VS_SDXDPIB_XINTERVAL * 1066ca590c1cSDharageswari R hdac_stream(hstream)->index)); 1067ca590c1cSDharageswari R else 1068a40e693cSJeeja KP pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); 1069a40e693cSJeeja KP 1070a40e693cSJeeja KP if (pos >= hdac_stream(hstream)->bufsize) 1071a40e693cSJeeja KP pos = 0; 1072a40e693cSJeeja KP 10737b96144dSJeeja KP return bytes_to_frames(substream->runtime, pos); 1074a40e693cSJeeja KP } 1075a40e693cSJeeja KP 1076a40e693cSJeeja KP static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, 1077a40e693cSJeeja KP u64 nsec) 1078a40e693cSJeeja KP { 1079a40e693cSJeeja KP struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 1080a40e693cSJeeja KP struct snd_soc_dai *codec_dai = rtd->codec_dai; 1081a40e693cSJeeja KP u64 codec_frames, codec_nsecs; 1082a40e693cSJeeja KP 1083a40e693cSJeeja KP if (!codec_dai->driver->ops->delay) 1084a40e693cSJeeja KP return nsec; 1085a40e693cSJeeja KP 1086a40e693cSJeeja KP codec_frames = codec_dai->driver->ops->delay(substream, codec_dai); 1087a40e693cSJeeja KP codec_nsecs = div_u64(codec_frames * 1000000000LL, 1088a40e693cSJeeja KP substream->runtime->rate); 1089a40e693cSJeeja KP 1090a40e693cSJeeja KP if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 1091a40e693cSJeeja KP return nsec + codec_nsecs; 1092a40e693cSJeeja KP 1093a40e693cSJeeja KP return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0; 1094a40e693cSJeeja KP } 1095a40e693cSJeeja KP 1096a40e693cSJeeja KP static int skl_get_time_info(struct snd_pcm_substream *substream, 1097a40e693cSJeeja KP struct timespec *system_ts, struct timespec *audio_ts, 1098a40e693cSJeeja KP struct snd_pcm_audio_tstamp_config *audio_tstamp_config, 1099a40e693cSJeeja KP struct snd_pcm_audio_tstamp_report *audio_tstamp_report) 1100a40e693cSJeeja KP { 1101a40e693cSJeeja KP struct hdac_ext_stream *sstream = get_hdac_ext_stream(substream); 1102a40e693cSJeeja KP struct hdac_stream *hstr = hdac_stream(sstream); 1103a40e693cSJeeja KP u64 nsec; 1104a40e693cSJeeja KP 1105a40e693cSJeeja KP if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) && 1106a40e693cSJeeja KP (audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) { 1107a40e693cSJeeja KP 1108a40e693cSJeeja KP snd_pcm_gettime(substream->runtime, system_ts); 1109a40e693cSJeeja KP 1110a40e693cSJeeja KP nsec = timecounter_read(&hstr->tc); 1111a40e693cSJeeja KP nsec = div_u64(nsec, 3); /* can be optimized */ 1112a40e693cSJeeja KP if (audio_tstamp_config->report_delay) 1113a40e693cSJeeja KP nsec = skl_adjust_codec_delay(substream, nsec); 1114a40e693cSJeeja KP 1115a40e693cSJeeja KP *audio_ts = ns_to_timespec(nsec); 1116a40e693cSJeeja KP 1117a40e693cSJeeja KP audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; 1118a40e693cSJeeja KP audio_tstamp_report->accuracy_report = 1; /* rest of struct is valid */ 1119a40e693cSJeeja KP audio_tstamp_report->accuracy = 42; /* 24MHzWallClk == 42ns resolution */ 1120a40e693cSJeeja KP 1121a40e693cSJeeja KP } else { 1122a40e693cSJeeja KP audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; 1123a40e693cSJeeja KP } 1124a40e693cSJeeja KP 1125a40e693cSJeeja KP return 0; 1126a40e693cSJeeja KP } 1127a40e693cSJeeja KP 1128115c7254SJulia Lawall static const struct snd_pcm_ops skl_platform_ops = { 1129a40e693cSJeeja KP .open = skl_platform_open, 1130a40e693cSJeeja KP .ioctl = snd_pcm_lib_ioctl, 1131a40e693cSJeeja KP .trigger = skl_platform_pcm_trigger, 1132a40e693cSJeeja KP .pointer = skl_platform_pcm_pointer, 1133a40e693cSJeeja KP .get_time_info = skl_get_time_info, 1134a40e693cSJeeja KP .mmap = snd_pcm_lib_default_mmap, 1135a40e693cSJeeja KP .page = snd_pcm_sgbuf_ops_page, 1136a40e693cSJeeja KP }; 1137a40e693cSJeeja KP 1138a40e693cSJeeja KP static void skl_pcm_free(struct snd_pcm *pcm) 1139a40e693cSJeeja KP { 1140a40e693cSJeeja KP snd_pcm_lib_preallocate_free_for_all(pcm); 1141a40e693cSJeeja KP } 1142a40e693cSJeeja KP 1143a40e693cSJeeja KP #define MAX_PREALLOC_SIZE (32 * 1024 * 1024) 1144a40e693cSJeeja KP 1145a40e693cSJeeja KP static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) 1146a40e693cSJeeja KP { 1147a40e693cSJeeja KP struct snd_soc_dai *dai = rtd->cpu_dai; 1148a40e693cSJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); 1149a40e693cSJeeja KP struct snd_pcm *pcm = rtd->pcm; 1150a40e693cSJeeja KP unsigned int size; 1151a40e693cSJeeja KP int retval = 0; 1152a40e693cSJeeja KP struct skl *skl = ebus_to_skl(ebus); 1153a40e693cSJeeja KP 1154a40e693cSJeeja KP if (dai->driver->playback.channels_min || 1155a40e693cSJeeja KP dai->driver->capture.channels_min) { 1156a40e693cSJeeja KP /* buffer pre-allocation */ 1157a40e693cSJeeja KP size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; 1158a40e693cSJeeja KP if (size > MAX_PREALLOC_SIZE) 1159a40e693cSJeeja KP size = MAX_PREALLOC_SIZE; 1160a40e693cSJeeja KP retval = snd_pcm_lib_preallocate_pages_for_all(pcm, 1161a40e693cSJeeja KP SNDRV_DMA_TYPE_DEV_SG, 1162a40e693cSJeeja KP snd_dma_pci_data(skl->pci), 1163a40e693cSJeeja KP size, MAX_PREALLOC_SIZE); 1164a40e693cSJeeja KP if (retval) { 1165a40e693cSJeeja KP dev_err(dai->dev, "dma buffer allocationf fail\n"); 1166a40e693cSJeeja KP return retval; 1167a40e693cSJeeja KP } 1168a40e693cSJeeja KP } 1169a40e693cSJeeja KP 1170a40e693cSJeeja KP return retval; 1171a40e693cSJeeja KP } 1172a40e693cSJeeja KP 117364cb1d0aSVinod Koul static int skl_populate_modules(struct skl *skl) 117464cb1d0aSVinod Koul { 117564cb1d0aSVinod Koul struct skl_pipeline *p; 117664cb1d0aSVinod Koul struct skl_pipe_module *m; 117764cb1d0aSVinod Koul struct snd_soc_dapm_widget *w; 117864cb1d0aSVinod Koul struct skl_module_cfg *mconfig; 117964cb1d0aSVinod Koul int ret; 118064cb1d0aSVinod Koul 118164cb1d0aSVinod Koul list_for_each_entry(p, &skl->ppl_list, node) { 118264cb1d0aSVinod Koul list_for_each_entry(m, &p->pipe->w_list, node) { 118364cb1d0aSVinod Koul 118464cb1d0aSVinod Koul w = m->w; 118564cb1d0aSVinod Koul mconfig = w->priv; 118664cb1d0aSVinod Koul 118764cb1d0aSVinod Koul ret = snd_skl_get_module_info(skl->skl_sst, mconfig); 118864cb1d0aSVinod Koul if (ret < 0) { 118964cb1d0aSVinod Koul dev_err(skl->skl_sst->dev, 119064cb1d0aSVinod Koul "query module info failed:%d\n", ret); 119164cb1d0aSVinod Koul goto err; 119264cb1d0aSVinod Koul } 119364cb1d0aSVinod Koul } 119464cb1d0aSVinod Koul } 119564cb1d0aSVinod Koul err: 119664cb1d0aSVinod Koul return ret; 119764cb1d0aSVinod Koul } 119864cb1d0aSVinod Koul 1199b663a8c5SJeeja KP static int skl_platform_soc_probe(struct snd_soc_platform *platform) 1200b663a8c5SJeeja KP { 1201b663a8c5SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(platform->dev); 1202fe3f4442SDharageswari R struct skl *skl = ebus_to_skl(ebus); 120378cdbbdaSVinod Koul const struct skl_dsp_ops *ops; 1204fe3f4442SDharageswari R int ret; 1205b663a8c5SJeeja KP 120678cdbbdaSVinod Koul pm_runtime_get_sync(platform->dev); 1207ec8ae570SVinod Koul if ((ebus_to_hbus(ebus))->ppcap) { 1208fe3f4442SDharageswari R ret = skl_tplg_init(platform, ebus); 1209fe3f4442SDharageswari R if (ret < 0) { 1210fe3f4442SDharageswari R dev_err(platform->dev, "Failed to init topology!\n"); 1211fe3f4442SDharageswari R return ret; 1212fe3f4442SDharageswari R } 1213fe3f4442SDharageswari R skl->platform = platform; 121478cdbbdaSVinod Koul 121578cdbbdaSVinod Koul /* load the firmwares, since all is set */ 121678cdbbdaSVinod Koul ops = skl_get_dsp_ops(skl->pci->device); 121778cdbbdaSVinod Koul if (!ops) 121878cdbbdaSVinod Koul return -EIO; 121978cdbbdaSVinod Koul 122078cdbbdaSVinod Koul if (skl->skl_sst->is_first_boot == false) { 122178cdbbdaSVinod Koul dev_err(platform->dev, "DSP reports first boot done!!!\n"); 122278cdbbdaSVinod Koul return -EIO; 1223fe3f4442SDharageswari R } 1224b663a8c5SJeeja KP 122578cdbbdaSVinod Koul ret = ops->init_fw(platform->dev, skl->skl_sst); 122678cdbbdaSVinod Koul if (ret < 0) { 122778cdbbdaSVinod Koul dev_err(platform->dev, "Failed to boot first fw: %d\n", ret); 122878cdbbdaSVinod Koul return ret; 122978cdbbdaSVinod Koul } 123064cb1d0aSVinod Koul skl_populate_modules(skl); 1231a26a3f53SPardha Saradhi K skl->skl_sst->update_d0i3c = skl_update_d0i3c; 123278cdbbdaSVinod Koul } 123378cdbbdaSVinod Koul pm_runtime_mark_last_busy(platform->dev); 123478cdbbdaSVinod Koul pm_runtime_put_autosuspend(platform->dev); 123578cdbbdaSVinod Koul 1236b663a8c5SJeeja KP return 0; 1237b663a8c5SJeeja KP } 1238a40e693cSJeeja KP static struct snd_soc_platform_driver skl_platform_drv = { 1239b663a8c5SJeeja KP .probe = skl_platform_soc_probe, 1240a40e693cSJeeja KP .ops = &skl_platform_ops, 1241a40e693cSJeeja KP .pcm_new = skl_pcm_new, 1242a40e693cSJeeja KP .pcm_free = skl_pcm_free, 1243a40e693cSJeeja KP }; 1244a40e693cSJeeja KP 1245a40e693cSJeeja KP static const struct snd_soc_component_driver skl_component = { 1246a40e693cSJeeja KP .name = "pcm", 1247a40e693cSJeeja KP }; 1248a40e693cSJeeja KP 1249a40e693cSJeeja KP int skl_platform_register(struct device *dev) 1250a40e693cSJeeja KP { 1251a40e693cSJeeja KP int ret; 1252b663a8c5SJeeja KP struct hdac_ext_bus *ebus = dev_get_drvdata(dev); 1253b663a8c5SJeeja KP struct skl *skl = ebus_to_skl(ebus); 1254b663a8c5SJeeja KP 1255b663a8c5SJeeja KP INIT_LIST_HEAD(&skl->ppl_list); 1256a40e693cSJeeja KP 1257a40e693cSJeeja KP ret = snd_soc_register_platform(dev, &skl_platform_drv); 1258a40e693cSJeeja KP if (ret) { 1259a40e693cSJeeja KP dev_err(dev, "soc platform registration failed %d\n", ret); 1260a40e693cSJeeja KP return ret; 1261a40e693cSJeeja KP } 1262a40e693cSJeeja KP ret = snd_soc_register_component(dev, &skl_component, 1263a40e693cSJeeja KP skl_platform_dai, 1264a40e693cSJeeja KP ARRAY_SIZE(skl_platform_dai)); 1265a40e693cSJeeja KP if (ret) { 1266a40e693cSJeeja KP dev_err(dev, "soc component registration failed %d\n", ret); 1267a40e693cSJeeja KP snd_soc_unregister_platform(dev); 1268a40e693cSJeeja KP } 1269a40e693cSJeeja KP 1270a40e693cSJeeja KP return ret; 1271a40e693cSJeeja KP 1272a40e693cSJeeja KP } 1273a40e693cSJeeja KP 1274a40e693cSJeeja KP int skl_platform_unregister(struct device *dev) 1275a40e693cSJeeja KP { 1276a40e693cSJeeja KP snd_soc_unregister_component(dev); 1277a40e693cSJeeja KP snd_soc_unregister_platform(dev); 1278a40e693cSJeeja KP return 0; 1279a40e693cSJeeja KP } 1280