static int skl_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct skl *skl = get_skl_ctx(dai->dev); unsigned int format_val; int err; struct skl_module_cfg *mconfig; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); format_val = skl_get_format(substream, dai); dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n", hdac_stream(stream)->stream_tag, format_val); snd_hdac_stream_reset(hdac_stream(stream)); /* In case of XRUN recovery, reset the FW pipe to clean state */ if (mconfig && (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) skl_reset_pipe(skl->skl_sst, mconfig->pipe); err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); if (err < 0) return err; err = snd_hdac_stream_setup(hdac_stream(stream)); if (err < 0) return err; hdac_stream(stream)->prepared = 1; return err; }
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_widget->power || dai->capture_widget->power) 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_link_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct hdac_ext_stream *link_dev = snd_soc_dai_get_dma_data(dai, substream); unsigned int format_val = 0; struct skl_dma_params *dma_params; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct hdac_ext_link *link; struct skl *skl = get_skl_ctx(dai->dev); struct skl_module_cfg *mconfig = NULL; dma_params = (struct skl_dma_params *) snd_soc_dai_get_dma_data(codec_dai, substream); if (dma_params) format_val = dma_params->format; dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n", hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name); link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); if (!link) return -EINVAL; snd_hdac_ext_link_stream_reset(link_dev); /* In case of XRUN recovery, reset the FW pipe to clean state */ mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); if (mconfig && (substream->runtime->status->state == SNDRV_PCM_STATE_XRUN)) skl_reset_pipe(skl->skl_sst, mconfig->pipe); snd_hdac_ext_link_stream_setup(link_dev, format_val); snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag); link_dev->link_prepared = 1; return 0; }
static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, struct skl_module_cfg *mconfig, struct skl_cpr_cfg *cpr_mconfig) { u32 dma_io_buf; struct skl_module_res *res; int res_idx = mconfig->res_idx; struct skl *skl = get_skl_ctx(ctx->dev); cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(ctx, mconfig); if (cpr_mconfig->gtw_cfg.node_id == SKL_NON_GATEWAY_CPR_NODE_ID) { cpr_mconfig->cpr_feature_mask = 0; return; } if (skl->nr_modules) { res = &mconfig->module->resources[mconfig->res_idx]; cpr_mconfig->gtw_cfg.dma_buffer_size = res->dma_buffer_size; goto skip_buf_size_calc; } else { res = &mconfig->module->resources[res_idx]; } switch (mconfig->hw_conn_type) { case SKL_CONN_SOURCE: if (mconfig->dev_type == SKL_DEVICE_HDAHOST) dma_io_buf = res->ibs; else dma_io_buf = res->obs; break; case SKL_CONN_SINK: if (mconfig->dev_type == SKL_DEVICE_HDAHOST) dma_io_buf = res->obs; else dma_io_buf = res->ibs; break; default: dev_warn(ctx->dev, "wrong connection type: %d\n", mconfig->hw_conn_type); return; } cpr_mconfig->gtw_cfg.dma_buffer_size = mconfig->dma_buffer_size * dma_io_buf; /* fallback to 2ms default value */ if (!cpr_mconfig->gtw_cfg.dma_buffer_size) { if (mconfig->hw_conn_type == SKL_CONN_SOURCE) cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->obs; else cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->ibs; } skip_buf_size_calc: cpr_mconfig->cpr_feature_mask = 0; cpr_mconfig->gtw_cfg.config_length = 0; skl_copy_copier_caps(mconfig, cpr_mconfig); }
static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, 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; struct hdac_ext_bus *ebus = get_bus_ctx(substream); struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct snd_soc_dapm_widget *w; int ret; mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); if (!mconfig) return -EIO; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) w = dai->playback_widget; else w = dai->capture_widget; switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: if (!w->ignore_suspend) { skl_pcm_prepare(substream, dai); /* * enable DMA Resume enable bit for the stream, set the * dpib & lpib position to resume before starting the * DMA */ snd_hdac_ext_stream_drsm_enable(ebus, true, hdac_stream(stream)->index); snd_hdac_ext_stream_set_dpibr(ebus, stream, stream->dpib); snd_hdac_ext_stream_set_lpib(stream, stream->lpib); } case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* * Start HOST DMA and Start FE Pipe.This is to make sure that * there are no underrun/overrun in the case when the FE * pipeline is started but there is a delay in starting the * DMA channel on the host. */ snd_hdac_ext_stream_decouple(ebus, stream, true); ret = skl_decoupled_trigger(substream, cmd); if (ret < 0) return ret; return skl_run_pipe(ctx, mconfig->pipe); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: /* * Stop FE Pipe first and stop DMA. This is to make sure that * there are no underrun/overrun in the case if there is a delay * between the two operations. */ ret = skl_stop_pipe(ctx, mconfig->pipe); if (ret < 0) return ret; ret = skl_decoupled_trigger(substream, cmd); if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) { /* save the dpib and lpib positions */ stream->dpib = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE + (AZX_REG_VS_SDXDPIB_XINTERVAL * hdac_stream(stream)->index)); stream->lpib = snd_hdac_stream_get_pos_lpib( hdac_stream(stream)); snd_hdac_ext_stream_decouple(ebus, stream, false); } break; default: return -EINVAL; } return 0; }