1f1b3b320SCezary Rojewski // SPDX-License-Identifier: GPL-2.0-only 2f1b3b320SCezary Rojewski // 3f1b3b320SCezary Rojewski // Copyright(c) 2021-2022 Intel Corporation. All rights reserved. 4f1b3b320SCezary Rojewski // 5f1b3b320SCezary Rojewski // Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6f1b3b320SCezary Rojewski // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7f1b3b320SCezary Rojewski // 8f1b3b320SCezary Rojewski 9f1b3b320SCezary Rojewski #include <linux/debugfs.h> 10f1b3b320SCezary Rojewski #include <linux/device.h> 11f1b3b320SCezary Rojewski #include <sound/hda_register.h> 12f1b3b320SCezary Rojewski #include <sound/hdaudio_ext.h> 13*9114700bSCezary Rojewski #include <sound/pcm_params.h> 14f1b3b320SCezary Rojewski #include <sound/soc-acpi.h> 15f1b3b320SCezary Rojewski #include <sound/soc-acpi-intel-match.h> 16f1b3b320SCezary Rojewski #include <sound/soc-component.h> 17f1b3b320SCezary Rojewski #include "avs.h" 18f1b3b320SCezary Rojewski #include "path.h" 19f1b3b320SCezary Rojewski #include "topology.h" 20f1b3b320SCezary Rojewski 21f1b3b320SCezary Rojewski struct avs_dma_data { 22f1b3b320SCezary Rojewski struct avs_tplg_path_template *template; 23f1b3b320SCezary Rojewski struct avs_path *path; 24f1b3b320SCezary Rojewski /* 25f1b3b320SCezary Rojewski * link stream is stored within substream's runtime 26f1b3b320SCezary Rojewski * private_data to fulfill the needs of codec BE path 27f1b3b320SCezary Rojewski * 28f1b3b320SCezary Rojewski * host stream assigned 29f1b3b320SCezary Rojewski */ 30f1b3b320SCezary Rojewski struct hdac_ext_stream *host_stream; 31f1b3b320SCezary Rojewski }; 32f1b3b320SCezary Rojewski 33*9114700bSCezary Rojewski static struct avs_tplg_path_template * 34*9114700bSCezary Rojewski avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction) 35*9114700bSCezary Rojewski { 36*9114700bSCezary Rojewski struct snd_soc_dapm_widget *dw; 37*9114700bSCezary Rojewski struct snd_soc_dapm_path *dp; 38*9114700bSCezary Rojewski enum snd_soc_dapm_direction dir; 39*9114700bSCezary Rojewski 40*9114700bSCezary Rojewski if (direction == SNDRV_PCM_STREAM_CAPTURE) { 41*9114700bSCezary Rojewski dw = dai->capture_widget; 42*9114700bSCezary Rojewski dir = is_fe ? SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN; 43*9114700bSCezary Rojewski } else { 44*9114700bSCezary Rojewski dw = dai->playback_widget; 45*9114700bSCezary Rojewski dir = is_fe ? SND_SOC_DAPM_DIR_IN : SND_SOC_DAPM_DIR_OUT; 46*9114700bSCezary Rojewski } 47*9114700bSCezary Rojewski 48*9114700bSCezary Rojewski dp = list_first_entry_or_null(&dw->edges[dir], typeof(*dp), list_node[dir]); 49*9114700bSCezary Rojewski if (!dp) 50*9114700bSCezary Rojewski return NULL; 51*9114700bSCezary Rojewski 52*9114700bSCezary Rojewski /* Get the other widget, with actual path template data */ 53*9114700bSCezary Rojewski dw = (dp->source == dw) ? dp->sink : dp->source; 54*9114700bSCezary Rojewski 55*9114700bSCezary Rojewski return dw->priv; 56*9114700bSCezary Rojewski } 57*9114700bSCezary Rojewski 58*9114700bSCezary Rojewski static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool is_fe) 59*9114700bSCezary Rojewski { 60*9114700bSCezary Rojewski struct avs_tplg_path_template *template; 61*9114700bSCezary Rojewski struct avs_dma_data *data; 62*9114700bSCezary Rojewski 63*9114700bSCezary Rojewski template = avs_dai_find_path_template(dai, is_fe, substream->stream); 64*9114700bSCezary Rojewski if (!template) { 65*9114700bSCezary Rojewski dev_err(dai->dev, "no %s path for dai %s, invalid tplg?\n", 66*9114700bSCezary Rojewski snd_pcm_stream_str(substream), dai->name); 67*9114700bSCezary Rojewski return -EINVAL; 68*9114700bSCezary Rojewski } 69*9114700bSCezary Rojewski 70*9114700bSCezary Rojewski data = kzalloc(sizeof(*data), GFP_KERNEL); 71*9114700bSCezary Rojewski if (!data) 72*9114700bSCezary Rojewski return -ENOMEM; 73*9114700bSCezary Rojewski 74*9114700bSCezary Rojewski data->template = template; 75*9114700bSCezary Rojewski snd_soc_dai_set_dma_data(dai, substream, data); 76*9114700bSCezary Rojewski 77*9114700bSCezary Rojewski return 0; 78*9114700bSCezary Rojewski } 79*9114700bSCezary Rojewski 80*9114700bSCezary Rojewski static int avs_dai_hw_params(struct snd_pcm_substream *substream, 81*9114700bSCezary Rojewski struct snd_pcm_hw_params *fe_hw_params, 82*9114700bSCezary Rojewski struct snd_pcm_hw_params *be_hw_params, struct snd_soc_dai *dai, 83*9114700bSCezary Rojewski int dma_id) 84*9114700bSCezary Rojewski { 85*9114700bSCezary Rojewski struct avs_dma_data *data; 86*9114700bSCezary Rojewski struct avs_path *path; 87*9114700bSCezary Rojewski struct avs_dev *adev = to_avs_dev(dai->dev); 88*9114700bSCezary Rojewski int ret; 89*9114700bSCezary Rojewski 90*9114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 91*9114700bSCezary Rojewski 92*9114700bSCezary Rojewski dev_dbg(dai->dev, "%s FE hw_params str %p rtd %p", 93*9114700bSCezary Rojewski __func__, substream, substream->runtime); 94*9114700bSCezary Rojewski dev_dbg(dai->dev, "rate %d chn %d vbd %d bd %d\n", 95*9114700bSCezary Rojewski params_rate(fe_hw_params), params_channels(fe_hw_params), 96*9114700bSCezary Rojewski params_width(fe_hw_params), params_physical_width(fe_hw_params)); 97*9114700bSCezary Rojewski 98*9114700bSCezary Rojewski dev_dbg(dai->dev, "%s BE hw_params str %p rtd %p", 99*9114700bSCezary Rojewski __func__, substream, substream->runtime); 100*9114700bSCezary Rojewski dev_dbg(dai->dev, "rate %d chn %d vbd %d bd %d\n", 101*9114700bSCezary Rojewski params_rate(be_hw_params), params_channels(be_hw_params), 102*9114700bSCezary Rojewski params_width(be_hw_params), params_physical_width(be_hw_params)); 103*9114700bSCezary Rojewski 104*9114700bSCezary Rojewski path = avs_path_create(adev, dma_id, data->template, fe_hw_params, be_hw_params); 105*9114700bSCezary Rojewski if (IS_ERR(path)) { 106*9114700bSCezary Rojewski ret = PTR_ERR(path); 107*9114700bSCezary Rojewski dev_err(dai->dev, "create path failed: %d\n", ret); 108*9114700bSCezary Rojewski return ret; 109*9114700bSCezary Rojewski } 110*9114700bSCezary Rojewski 111*9114700bSCezary Rojewski data->path = path; 112*9114700bSCezary Rojewski return 0; 113*9114700bSCezary Rojewski } 114*9114700bSCezary Rojewski 115*9114700bSCezary Rojewski static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *substream, 116*9114700bSCezary Rojewski struct snd_soc_dai *dai) 117*9114700bSCezary Rojewski { 118*9114700bSCezary Rojewski struct avs_dma_data *data; 119*9114700bSCezary Rojewski int ret; 120*9114700bSCezary Rojewski 121*9114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 122*9114700bSCezary Rojewski if (!data->path) 123*9114700bSCezary Rojewski return 0; 124*9114700bSCezary Rojewski 125*9114700bSCezary Rojewski ret = avs_path_reset(data->path); 126*9114700bSCezary Rojewski if (ret < 0) { 127*9114700bSCezary Rojewski dev_err(dai->dev, "reset path failed: %d\n", ret); 128*9114700bSCezary Rojewski return ret; 129*9114700bSCezary Rojewski } 130*9114700bSCezary Rojewski 131*9114700bSCezary Rojewski ret = avs_path_pause(data->path); 132*9114700bSCezary Rojewski if (ret < 0) 133*9114700bSCezary Rojewski dev_err(dai->dev, "pause path failed: %d\n", ret); 134*9114700bSCezary Rojewski return ret; 135*9114700bSCezary Rojewski } 136*9114700bSCezary Rojewski 137*9114700bSCezary Rojewski static const unsigned int rates[] = { 138*9114700bSCezary Rojewski 8000, 11025, 12000, 16000, 139*9114700bSCezary Rojewski 22050, 24000, 32000, 44100, 140*9114700bSCezary Rojewski 48000, 64000, 88200, 96000, 141*9114700bSCezary Rojewski 128000, 176400, 192000, 142*9114700bSCezary Rojewski }; 143*9114700bSCezary Rojewski 144*9114700bSCezary Rojewski static const struct snd_pcm_hw_constraint_list hw_rates = { 145*9114700bSCezary Rojewski .count = ARRAY_SIZE(rates), 146*9114700bSCezary Rojewski .list = rates, 147*9114700bSCezary Rojewski .mask = 0, 148*9114700bSCezary Rojewski }; 149*9114700bSCezary Rojewski 150*9114700bSCezary Rojewski static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 151*9114700bSCezary Rojewski { 152*9114700bSCezary Rojewski struct snd_pcm_runtime *runtime = substream->runtime; 153*9114700bSCezary Rojewski struct avs_dma_data *data; 154*9114700bSCezary Rojewski struct avs_dev *adev = to_avs_dev(dai->dev); 155*9114700bSCezary Rojewski struct hdac_bus *bus = &adev->base.core; 156*9114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 157*9114700bSCezary Rojewski int ret; 158*9114700bSCezary Rojewski 159*9114700bSCezary Rojewski ret = avs_dai_startup(substream, dai, true); 160*9114700bSCezary Rojewski if (ret) 161*9114700bSCezary Rojewski return ret; 162*9114700bSCezary Rojewski 163*9114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 164*9114700bSCezary Rojewski 165*9114700bSCezary Rojewski host_stream = snd_hdac_ext_stream_assign(bus, substream, HDAC_EXT_STREAM_TYPE_HOST); 166*9114700bSCezary Rojewski if (!host_stream) { 167*9114700bSCezary Rojewski kfree(data); 168*9114700bSCezary Rojewski return -EBUSY; 169*9114700bSCezary Rojewski } 170*9114700bSCezary Rojewski 171*9114700bSCezary Rojewski data->host_stream = host_stream; 172*9114700bSCezary Rojewski snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 173*9114700bSCezary Rojewski /* avoid wrap-around with wall-clock */ 174*9114700bSCezary Rojewski snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 20, 178000000); 175*9114700bSCezary Rojewski snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_rates); 176*9114700bSCezary Rojewski snd_pcm_set_sync(substream); 177*9114700bSCezary Rojewski 178*9114700bSCezary Rojewski dev_dbg(dai->dev, "%s fe STARTUP tag %d str %p", 179*9114700bSCezary Rojewski __func__, hdac_stream(host_stream)->stream_tag, substream); 180*9114700bSCezary Rojewski 181*9114700bSCezary Rojewski return 0; 182*9114700bSCezary Rojewski } 183*9114700bSCezary Rojewski 184*9114700bSCezary Rojewski static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 185*9114700bSCezary Rojewski { 186*9114700bSCezary Rojewski struct avs_dma_data *data; 187*9114700bSCezary Rojewski 188*9114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 189*9114700bSCezary Rojewski 190*9114700bSCezary Rojewski snd_soc_dai_set_dma_data(dai, substream, NULL); 191*9114700bSCezary Rojewski snd_hdac_ext_stream_release(data->host_stream, HDAC_EXT_STREAM_TYPE_HOST); 192*9114700bSCezary Rojewski kfree(data); 193*9114700bSCezary Rojewski } 194*9114700bSCezary Rojewski 195*9114700bSCezary Rojewski static int avs_dai_fe_hw_params(struct snd_pcm_substream *substream, 196*9114700bSCezary Rojewski struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) 197*9114700bSCezary Rojewski { 198*9114700bSCezary Rojewski struct snd_pcm_hw_params *be_hw_params = NULL; 199*9114700bSCezary Rojewski struct snd_soc_pcm_runtime *fe, *be; 200*9114700bSCezary Rojewski struct snd_soc_dpcm *dpcm; 201*9114700bSCezary Rojewski struct avs_dma_data *data; 202*9114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 203*9114700bSCezary Rojewski int ret; 204*9114700bSCezary Rojewski 205*9114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 206*9114700bSCezary Rojewski if (data->path) 207*9114700bSCezary Rojewski return 0; 208*9114700bSCezary Rojewski 209*9114700bSCezary Rojewski host_stream = data->host_stream; 210*9114700bSCezary Rojewski 211*9114700bSCezary Rojewski hdac_stream(host_stream)->bufsize = 0; 212*9114700bSCezary Rojewski hdac_stream(host_stream)->period_bytes = 0; 213*9114700bSCezary Rojewski hdac_stream(host_stream)->format_val = 0; 214*9114700bSCezary Rojewski 215*9114700bSCezary Rojewski fe = asoc_substream_to_rtd(substream); 216*9114700bSCezary Rojewski for_each_dpcm_be(fe, substream->stream, dpcm) { 217*9114700bSCezary Rojewski be = dpcm->be; 218*9114700bSCezary Rojewski be_hw_params = &be->dpcm[substream->stream].hw_params; 219*9114700bSCezary Rojewski } 220*9114700bSCezary Rojewski 221*9114700bSCezary Rojewski ret = avs_dai_hw_params(substream, hw_params, be_hw_params, dai, 222*9114700bSCezary Rojewski hdac_stream(host_stream)->stream_tag - 1); 223*9114700bSCezary Rojewski if (ret) 224*9114700bSCezary Rojewski goto create_err; 225*9114700bSCezary Rojewski 226*9114700bSCezary Rojewski ret = avs_path_bind(data->path); 227*9114700bSCezary Rojewski if (ret < 0) { 228*9114700bSCezary Rojewski dev_err(dai->dev, "bind FE <-> BE failed: %d\n", ret); 229*9114700bSCezary Rojewski goto bind_err; 230*9114700bSCezary Rojewski } 231*9114700bSCezary Rojewski 232*9114700bSCezary Rojewski return 0; 233*9114700bSCezary Rojewski 234*9114700bSCezary Rojewski bind_err: 235*9114700bSCezary Rojewski avs_path_free(data->path); 236*9114700bSCezary Rojewski data->path = NULL; 237*9114700bSCezary Rojewski create_err: 238*9114700bSCezary Rojewski snd_pcm_lib_free_pages(substream); 239*9114700bSCezary Rojewski return ret; 240*9114700bSCezary Rojewski } 241*9114700bSCezary Rojewski 242*9114700bSCezary Rojewski static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 243*9114700bSCezary Rojewski { 244*9114700bSCezary Rojewski struct avs_dma_data *data; 245*9114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 246*9114700bSCezary Rojewski int ret; 247*9114700bSCezary Rojewski 248*9114700bSCezary Rojewski dev_dbg(dai->dev, "%s fe HW_FREE str %p rtd %p", 249*9114700bSCezary Rojewski __func__, substream, substream->runtime); 250*9114700bSCezary Rojewski 251*9114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 252*9114700bSCezary Rojewski if (!data->path) 253*9114700bSCezary Rojewski return 0; 254*9114700bSCezary Rojewski 255*9114700bSCezary Rojewski host_stream = data->host_stream; 256*9114700bSCezary Rojewski 257*9114700bSCezary Rojewski ret = avs_path_unbind(data->path); 258*9114700bSCezary Rojewski if (ret < 0) 259*9114700bSCezary Rojewski dev_err(dai->dev, "unbind FE <-> BE failed: %d\n", ret); 260*9114700bSCezary Rojewski 261*9114700bSCezary Rojewski avs_path_free(data->path); 262*9114700bSCezary Rojewski data->path = NULL; 263*9114700bSCezary Rojewski snd_hdac_stream_cleanup(hdac_stream(host_stream)); 264*9114700bSCezary Rojewski hdac_stream(host_stream)->prepared = false; 265*9114700bSCezary Rojewski 266*9114700bSCezary Rojewski ret = snd_pcm_lib_free_pages(substream); 267*9114700bSCezary Rojewski if (ret < 0) 268*9114700bSCezary Rojewski dev_dbg(dai->dev, "Failed to free pages!\n"); 269*9114700bSCezary Rojewski 270*9114700bSCezary Rojewski return ret; 271*9114700bSCezary Rojewski } 272*9114700bSCezary Rojewski 273*9114700bSCezary Rojewski static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) 274*9114700bSCezary Rojewski { 275*9114700bSCezary Rojewski struct snd_pcm_runtime *runtime = substream->runtime; 276*9114700bSCezary Rojewski struct avs_dma_data *data; 277*9114700bSCezary Rojewski struct avs_dev *adev = to_avs_dev(dai->dev); 278*9114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 279*9114700bSCezary Rojewski struct hdac_bus *bus; 280*9114700bSCezary Rojewski unsigned int format_val; 281*9114700bSCezary Rojewski int ret; 282*9114700bSCezary Rojewski 283*9114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 284*9114700bSCezary Rojewski host_stream = data->host_stream; 285*9114700bSCezary Rojewski 286*9114700bSCezary Rojewski if (hdac_stream(host_stream)->prepared) 287*9114700bSCezary Rojewski return 0; 288*9114700bSCezary Rojewski 289*9114700bSCezary Rojewski bus = hdac_stream(host_stream)->bus; 290*9114700bSCezary Rojewski snd_hdac_ext_stream_decouple(bus, data->host_stream, true); 291*9114700bSCezary Rojewski snd_hdac_stream_reset(hdac_stream(host_stream)); 292*9114700bSCezary Rojewski 293*9114700bSCezary Rojewski format_val = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format, 294*9114700bSCezary Rojewski runtime->sample_bits, 0); 295*9114700bSCezary Rojewski 296*9114700bSCezary Rojewski ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val); 297*9114700bSCezary Rojewski if (ret < 0) 298*9114700bSCezary Rojewski return ret; 299*9114700bSCezary Rojewski 300*9114700bSCezary Rojewski ret = snd_hdac_stream_setup(hdac_stream(host_stream)); 301*9114700bSCezary Rojewski if (ret < 0) 302*9114700bSCezary Rojewski return ret; 303*9114700bSCezary Rojewski 304*9114700bSCezary Rojewski ret = avs_dai_prepare(adev, substream, dai); 305*9114700bSCezary Rojewski if (ret) 306*9114700bSCezary Rojewski return ret; 307*9114700bSCezary Rojewski 308*9114700bSCezary Rojewski hdac_stream(host_stream)->prepared = true; 309*9114700bSCezary Rojewski return 0; 310*9114700bSCezary Rojewski } 311*9114700bSCezary Rojewski 312*9114700bSCezary Rojewski static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) 313*9114700bSCezary Rojewski { 314*9114700bSCezary Rojewski struct avs_dma_data *data; 315*9114700bSCezary Rojewski struct hdac_ext_stream *host_stream; 316*9114700bSCezary Rojewski struct hdac_bus *bus; 317*9114700bSCezary Rojewski unsigned long flags; 318*9114700bSCezary Rojewski int ret = 0; 319*9114700bSCezary Rojewski 320*9114700bSCezary Rojewski data = snd_soc_dai_get_dma_data(dai, substream); 321*9114700bSCezary Rojewski host_stream = data->host_stream; 322*9114700bSCezary Rojewski bus = hdac_stream(host_stream)->bus; 323*9114700bSCezary Rojewski 324*9114700bSCezary Rojewski switch (cmd) { 325*9114700bSCezary Rojewski case SNDRV_PCM_TRIGGER_START: 326*9114700bSCezary Rojewski case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 327*9114700bSCezary Rojewski spin_lock_irqsave(&bus->reg_lock, flags); 328*9114700bSCezary Rojewski snd_hdac_stream_start(hdac_stream(host_stream), true); 329*9114700bSCezary Rojewski spin_unlock_irqrestore(&bus->reg_lock, flags); 330*9114700bSCezary Rojewski 331*9114700bSCezary Rojewski ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO); 332*9114700bSCezary Rojewski if (ret < 0) 333*9114700bSCezary Rojewski dev_err(dai->dev, "run FE path failed: %d\n", ret); 334*9114700bSCezary Rojewski break; 335*9114700bSCezary Rojewski 336*9114700bSCezary Rojewski case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 337*9114700bSCezary Rojewski case SNDRV_PCM_TRIGGER_STOP: 338*9114700bSCezary Rojewski ret = avs_path_pause(data->path); 339*9114700bSCezary Rojewski if (ret < 0) 340*9114700bSCezary Rojewski dev_err(dai->dev, "pause FE path failed: %d\n", ret); 341*9114700bSCezary Rojewski 342*9114700bSCezary Rojewski spin_lock_irqsave(&bus->reg_lock, flags); 343*9114700bSCezary Rojewski snd_hdac_stream_stop(hdac_stream(host_stream)); 344*9114700bSCezary Rojewski spin_unlock_irqrestore(&bus->reg_lock, flags); 345*9114700bSCezary Rojewski 346*9114700bSCezary Rojewski if (cmd == SNDRV_PCM_TRIGGER_STOP) { 347*9114700bSCezary Rojewski ret = avs_path_reset(data->path); 348*9114700bSCezary Rojewski if (ret < 0) 349*9114700bSCezary Rojewski dev_err(dai->dev, "reset FE path failed: %d\n", ret); 350*9114700bSCezary Rojewski } 351*9114700bSCezary Rojewski break; 352*9114700bSCezary Rojewski 353*9114700bSCezary Rojewski default: 354*9114700bSCezary Rojewski ret = -EINVAL; 355*9114700bSCezary Rojewski break; 356*9114700bSCezary Rojewski } 357*9114700bSCezary Rojewski 358*9114700bSCezary Rojewski return ret; 359*9114700bSCezary Rojewski } 360*9114700bSCezary Rojewski 361*9114700bSCezary Rojewski const struct snd_soc_dai_ops avs_dai_fe_ops = { 362*9114700bSCezary Rojewski .startup = avs_dai_fe_startup, 363*9114700bSCezary Rojewski .shutdown = avs_dai_fe_shutdown, 364*9114700bSCezary Rojewski .hw_params = avs_dai_fe_hw_params, 365*9114700bSCezary Rojewski .hw_free = avs_dai_fe_hw_free, 366*9114700bSCezary Rojewski .prepare = avs_dai_fe_prepare, 367*9114700bSCezary Rojewski .trigger = avs_dai_fe_trigger, 368*9114700bSCezary Rojewski }; 369*9114700bSCezary Rojewski 370f1b3b320SCezary Rojewski static ssize_t topology_name_read(struct file *file, char __user *user_buf, size_t count, 371f1b3b320SCezary Rojewski loff_t *ppos) 372f1b3b320SCezary Rojewski { 373f1b3b320SCezary Rojewski struct snd_soc_component *component = file->private_data; 374f1b3b320SCezary Rojewski struct snd_soc_card *card = component->card; 375f1b3b320SCezary Rojewski struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); 376f1b3b320SCezary Rojewski char buf[64]; 377f1b3b320SCezary Rojewski size_t len; 378f1b3b320SCezary Rojewski 379f1b3b320SCezary Rojewski len = snprintf(buf, sizeof(buf), "%s/%s\n", component->driver->topology_name_prefix, 380f1b3b320SCezary Rojewski mach->tplg_filename); 381f1b3b320SCezary Rojewski 382f1b3b320SCezary Rojewski return simple_read_from_buffer(user_buf, count, ppos, buf, len); 383f1b3b320SCezary Rojewski } 384f1b3b320SCezary Rojewski 385f1b3b320SCezary Rojewski static const struct file_operations topology_name_fops = { 386f1b3b320SCezary Rojewski .open = simple_open, 387f1b3b320SCezary Rojewski .read = topology_name_read, 388f1b3b320SCezary Rojewski .llseek = default_llseek, 389f1b3b320SCezary Rojewski }; 390f1b3b320SCezary Rojewski 391f1b3b320SCezary Rojewski static int avs_component_load_libraries(struct avs_soc_component *acomp) 392f1b3b320SCezary Rojewski { 393f1b3b320SCezary Rojewski struct avs_tplg *tplg = acomp->tplg; 394f1b3b320SCezary Rojewski struct avs_dev *adev = to_avs_dev(acomp->base.dev); 395f1b3b320SCezary Rojewski int ret; 396f1b3b320SCezary Rojewski 397f1b3b320SCezary Rojewski if (!tplg->num_libs) 398f1b3b320SCezary Rojewski return 0; 399f1b3b320SCezary Rojewski 400f1b3b320SCezary Rojewski /* Parent device may be asleep and library loading involves IPCs. */ 401f1b3b320SCezary Rojewski ret = pm_runtime_resume_and_get(adev->dev); 402f1b3b320SCezary Rojewski if (ret < 0) 403f1b3b320SCezary Rojewski return ret; 404f1b3b320SCezary Rojewski 405f1b3b320SCezary Rojewski avs_hda_clock_gating_enable(adev, false); 406f1b3b320SCezary Rojewski avs_hda_l1sen_enable(adev, false); 407f1b3b320SCezary Rojewski 408f1b3b320SCezary Rojewski ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs); 409f1b3b320SCezary Rojewski 410f1b3b320SCezary Rojewski avs_hda_l1sen_enable(adev, true); 411f1b3b320SCezary Rojewski avs_hda_clock_gating_enable(adev, true); 412f1b3b320SCezary Rojewski 413f1b3b320SCezary Rojewski if (!ret) 414f1b3b320SCezary Rojewski ret = avs_module_info_init(adev, false); 415f1b3b320SCezary Rojewski 416f1b3b320SCezary Rojewski pm_runtime_mark_last_busy(adev->dev); 417f1b3b320SCezary Rojewski pm_runtime_put_autosuspend(adev->dev); 418f1b3b320SCezary Rojewski 419f1b3b320SCezary Rojewski return ret; 420f1b3b320SCezary Rojewski } 421f1b3b320SCezary Rojewski 422f1b3b320SCezary Rojewski static int avs_component_probe(struct snd_soc_component *component) 423f1b3b320SCezary Rojewski { 424f1b3b320SCezary Rojewski struct snd_soc_card *card = component->card; 425f1b3b320SCezary Rojewski struct snd_soc_acpi_mach *mach; 426f1b3b320SCezary Rojewski struct avs_soc_component *acomp; 427f1b3b320SCezary Rojewski struct avs_dev *adev; 428f1b3b320SCezary Rojewski char *filename; 429f1b3b320SCezary Rojewski int ret; 430f1b3b320SCezary Rojewski 431f1b3b320SCezary Rojewski dev_dbg(card->dev, "probing %s card %s\n", component->name, card->name); 432f1b3b320SCezary Rojewski mach = dev_get_platdata(card->dev); 433f1b3b320SCezary Rojewski acomp = to_avs_soc_component(component); 434f1b3b320SCezary Rojewski adev = to_avs_dev(component->dev); 435f1b3b320SCezary Rojewski 436f1b3b320SCezary Rojewski acomp->tplg = avs_tplg_new(component); 437f1b3b320SCezary Rojewski if (!acomp->tplg) 438f1b3b320SCezary Rojewski return -ENOMEM; 439f1b3b320SCezary Rojewski 440f1b3b320SCezary Rojewski if (!mach->tplg_filename) 441f1b3b320SCezary Rojewski goto finalize; 442f1b3b320SCezary Rojewski 443f1b3b320SCezary Rojewski /* Load specified topology and create debugfs for it. */ 444f1b3b320SCezary Rojewski filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix, 445f1b3b320SCezary Rojewski mach->tplg_filename); 446f1b3b320SCezary Rojewski if (!filename) 447f1b3b320SCezary Rojewski return -ENOMEM; 448f1b3b320SCezary Rojewski 449f1b3b320SCezary Rojewski ret = avs_load_topology(component, filename); 450f1b3b320SCezary Rojewski kfree(filename); 451f1b3b320SCezary Rojewski if (ret < 0) 452f1b3b320SCezary Rojewski return ret; 453f1b3b320SCezary Rojewski 454f1b3b320SCezary Rojewski ret = avs_component_load_libraries(acomp); 455f1b3b320SCezary Rojewski if (ret < 0) { 456f1b3b320SCezary Rojewski dev_err(card->dev, "libraries loading failed: %d\n", ret); 457f1b3b320SCezary Rojewski goto err_load_libs; 458f1b3b320SCezary Rojewski } 459f1b3b320SCezary Rojewski 460f1b3b320SCezary Rojewski finalize: 461f1b3b320SCezary Rojewski debugfs_create_file("topology_name", 0444, component->debugfs_root, component, 462f1b3b320SCezary Rojewski &topology_name_fops); 463f1b3b320SCezary Rojewski 464f1b3b320SCezary Rojewski mutex_lock(&adev->comp_list_mutex); 465f1b3b320SCezary Rojewski list_add_tail(&acomp->node, &adev->comp_list); 466f1b3b320SCezary Rojewski mutex_unlock(&adev->comp_list_mutex); 467f1b3b320SCezary Rojewski 468f1b3b320SCezary Rojewski return 0; 469f1b3b320SCezary Rojewski 470f1b3b320SCezary Rojewski err_load_libs: 471f1b3b320SCezary Rojewski avs_remove_topology(component); 472f1b3b320SCezary Rojewski return ret; 473f1b3b320SCezary Rojewski } 474f1b3b320SCezary Rojewski 475f1b3b320SCezary Rojewski static void avs_component_remove(struct snd_soc_component *component) 476f1b3b320SCezary Rojewski { 477f1b3b320SCezary Rojewski struct avs_soc_component *acomp = to_avs_soc_component(component); 478f1b3b320SCezary Rojewski struct snd_soc_acpi_mach *mach; 479f1b3b320SCezary Rojewski struct avs_dev *adev = to_avs_dev(component->dev); 480f1b3b320SCezary Rojewski int ret; 481f1b3b320SCezary Rojewski 482f1b3b320SCezary Rojewski mach = dev_get_platdata(component->card->dev); 483f1b3b320SCezary Rojewski 484f1b3b320SCezary Rojewski mutex_lock(&adev->comp_list_mutex); 485f1b3b320SCezary Rojewski list_del(&acomp->node); 486f1b3b320SCezary Rojewski mutex_unlock(&adev->comp_list_mutex); 487f1b3b320SCezary Rojewski 488f1b3b320SCezary Rojewski if (mach->tplg_filename) { 489f1b3b320SCezary Rojewski ret = avs_remove_topology(component); 490f1b3b320SCezary Rojewski if (ret < 0) 491f1b3b320SCezary Rojewski dev_err(component->dev, "unload topology failed: %d\n", ret); 492f1b3b320SCezary Rojewski } 493f1b3b320SCezary Rojewski } 494f1b3b320SCezary Rojewski 495f1b3b320SCezary Rojewski static int avs_component_open(struct snd_soc_component *component, 496f1b3b320SCezary Rojewski struct snd_pcm_substream *substream) 497f1b3b320SCezary Rojewski { 498f1b3b320SCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 499f1b3b320SCezary Rojewski struct snd_pcm_hardware hwparams; 500f1b3b320SCezary Rojewski 501f1b3b320SCezary Rojewski /* only FE DAI links are handled here */ 502f1b3b320SCezary Rojewski if (rtd->dai_link->no_pcm) 503f1b3b320SCezary Rojewski return 0; 504f1b3b320SCezary Rojewski 505f1b3b320SCezary Rojewski hwparams.info = SNDRV_PCM_INFO_MMAP | 506f1b3b320SCezary Rojewski SNDRV_PCM_INFO_MMAP_VALID | 507f1b3b320SCezary Rojewski SNDRV_PCM_INFO_INTERLEAVED | 508f1b3b320SCezary Rojewski SNDRV_PCM_INFO_PAUSE | 509f1b3b320SCezary Rojewski SNDRV_PCM_INFO_NO_PERIOD_WAKEUP; 510f1b3b320SCezary Rojewski 511f1b3b320SCezary Rojewski hwparams.formats = SNDRV_PCM_FMTBIT_S16_LE | 512f1b3b320SCezary Rojewski SNDRV_PCM_FMTBIT_S24_LE | 513f1b3b320SCezary Rojewski SNDRV_PCM_FMTBIT_S32_LE; 514f1b3b320SCezary Rojewski hwparams.period_bytes_min = 128; 515f1b3b320SCezary Rojewski hwparams.period_bytes_max = AZX_MAX_BUF_SIZE / 2; 516f1b3b320SCezary Rojewski hwparams.periods_min = 2; 517f1b3b320SCezary Rojewski hwparams.periods_max = AZX_MAX_FRAG; 518f1b3b320SCezary Rojewski hwparams.buffer_bytes_max = AZX_MAX_BUF_SIZE; 519f1b3b320SCezary Rojewski hwparams.fifo_size = 0; 520f1b3b320SCezary Rojewski 521f1b3b320SCezary Rojewski return snd_soc_set_runtime_hwparams(substream, &hwparams); 522f1b3b320SCezary Rojewski } 523f1b3b320SCezary Rojewski 524f1b3b320SCezary Rojewski static unsigned int avs_hda_stream_dpib_read(struct hdac_ext_stream *stream) 525f1b3b320SCezary Rojewski { 526f1b3b320SCezary Rojewski return readl(hdac_stream(stream)->bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE + 527f1b3b320SCezary Rojewski (AZX_REG_VS_SDXDPIB_XINTERVAL * hdac_stream(stream)->index)); 528f1b3b320SCezary Rojewski } 529f1b3b320SCezary Rojewski 530f1b3b320SCezary Rojewski static snd_pcm_uframes_t 531f1b3b320SCezary Rojewski avs_component_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) 532f1b3b320SCezary Rojewski { 533f1b3b320SCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 534f1b3b320SCezary Rojewski struct avs_dma_data *data; 535f1b3b320SCezary Rojewski struct hdac_ext_stream *host_stream; 536f1b3b320SCezary Rojewski unsigned int pos; 537f1b3b320SCezary Rojewski 538f1b3b320SCezary Rojewski data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); 539f1b3b320SCezary Rojewski if (!data->host_stream) 540f1b3b320SCezary Rojewski return 0; 541f1b3b320SCezary Rojewski 542f1b3b320SCezary Rojewski host_stream = data->host_stream; 543f1b3b320SCezary Rojewski pos = avs_hda_stream_dpib_read(host_stream); 544f1b3b320SCezary Rojewski 545f1b3b320SCezary Rojewski if (pos >= hdac_stream(host_stream)->bufsize) 546f1b3b320SCezary Rojewski pos = 0; 547f1b3b320SCezary Rojewski 548f1b3b320SCezary Rojewski return bytes_to_frames(substream->runtime, pos); 549f1b3b320SCezary Rojewski } 550f1b3b320SCezary Rojewski 551f1b3b320SCezary Rojewski static int avs_component_mmap(struct snd_soc_component *component, 552f1b3b320SCezary Rojewski struct snd_pcm_substream *substream, 553f1b3b320SCezary Rojewski struct vm_area_struct *vma) 554f1b3b320SCezary Rojewski { 555f1b3b320SCezary Rojewski return snd_pcm_lib_default_mmap(substream, vma); 556f1b3b320SCezary Rojewski } 557f1b3b320SCezary Rojewski 558f1b3b320SCezary Rojewski #define MAX_PREALLOC_SIZE (32 * 1024 * 1024) 559f1b3b320SCezary Rojewski 560f1b3b320SCezary Rojewski static int avs_component_construct(struct snd_soc_component *component, 561f1b3b320SCezary Rojewski struct snd_soc_pcm_runtime *rtd) 562f1b3b320SCezary Rojewski { 563f1b3b320SCezary Rojewski struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0); 564f1b3b320SCezary Rojewski struct snd_pcm *pcm = rtd->pcm; 565f1b3b320SCezary Rojewski 566f1b3b320SCezary Rojewski if (dai->driver->playback.channels_min) 567f1b3b320SCezary Rojewski snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, 568f1b3b320SCezary Rojewski SNDRV_DMA_TYPE_DEV_SG, component->dev, 0, 569f1b3b320SCezary Rojewski MAX_PREALLOC_SIZE); 570f1b3b320SCezary Rojewski 571f1b3b320SCezary Rojewski if (dai->driver->capture.channels_min) 572f1b3b320SCezary Rojewski snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, 573f1b3b320SCezary Rojewski SNDRV_DMA_TYPE_DEV_SG, component->dev, 0, 574f1b3b320SCezary Rojewski MAX_PREALLOC_SIZE); 575f1b3b320SCezary Rojewski 576f1b3b320SCezary Rojewski return 0; 577f1b3b320SCezary Rojewski } 578f1b3b320SCezary Rojewski 579f1b3b320SCezary Rojewski static const struct snd_soc_component_driver avs_component_driver = { 580f1b3b320SCezary Rojewski .name = "avs-pcm", 581f1b3b320SCezary Rojewski .probe = avs_component_probe, 582f1b3b320SCezary Rojewski .remove = avs_component_remove, 583f1b3b320SCezary Rojewski .open = avs_component_open, 584f1b3b320SCezary Rojewski .pointer = avs_component_pointer, 585f1b3b320SCezary Rojewski .mmap = avs_component_mmap, 586f1b3b320SCezary Rojewski .pcm_construct = avs_component_construct, 587f1b3b320SCezary Rojewski .module_get_upon_open = 1, /* increment refcount when a pcm is opened */ 588f1b3b320SCezary Rojewski .topology_name_prefix = "intel/avs", 589f1b3b320SCezary Rojewski .non_legacy_dai_naming = true, 590f1b3b320SCezary Rojewski }; 591f1b3b320SCezary Rojewski 592f1b3b320SCezary Rojewski __maybe_unused 593f1b3b320SCezary Rojewski static int avs_soc_component_register(struct device *dev, const char *name, 594f1b3b320SCezary Rojewski const struct snd_soc_component_driver *drv, 595f1b3b320SCezary Rojewski struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais) 596f1b3b320SCezary Rojewski { 597f1b3b320SCezary Rojewski struct avs_soc_component *acomp; 598f1b3b320SCezary Rojewski int ret; 599f1b3b320SCezary Rojewski 600f1b3b320SCezary Rojewski acomp = devm_kzalloc(dev, sizeof(*acomp), GFP_KERNEL); 601f1b3b320SCezary Rojewski if (!acomp) 602f1b3b320SCezary Rojewski return -ENOMEM; 603f1b3b320SCezary Rojewski 604f1b3b320SCezary Rojewski ret = snd_soc_component_initialize(&acomp->base, drv, dev); 605f1b3b320SCezary Rojewski if (ret < 0) 606f1b3b320SCezary Rojewski return ret; 607f1b3b320SCezary Rojewski 608f1b3b320SCezary Rojewski /* force name change after ASoC is done with its init */ 609f1b3b320SCezary Rojewski acomp->base.name = name; 610f1b3b320SCezary Rojewski INIT_LIST_HEAD(&acomp->node); 611f1b3b320SCezary Rojewski 612f1b3b320SCezary Rojewski return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais); 613f1b3b320SCezary Rojewski } 614