1*f1b3b320SCezary Rojewski // SPDX-License-Identifier: GPL-2.0-only 2*f1b3b320SCezary Rojewski // 3*f1b3b320SCezary Rojewski // Copyright(c) 2021-2022 Intel Corporation. All rights reserved. 4*f1b3b320SCezary Rojewski // 5*f1b3b320SCezary Rojewski // Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6*f1b3b320SCezary Rojewski // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7*f1b3b320SCezary Rojewski // 8*f1b3b320SCezary Rojewski 9*f1b3b320SCezary Rojewski #include <linux/debugfs.h> 10*f1b3b320SCezary Rojewski #include <linux/device.h> 11*f1b3b320SCezary Rojewski #include <sound/hda_register.h> 12*f1b3b320SCezary Rojewski #include <sound/hdaudio_ext.h> 13*f1b3b320SCezary Rojewski #include <sound/soc-acpi.h> 14*f1b3b320SCezary Rojewski #include <sound/soc-acpi-intel-match.h> 15*f1b3b320SCezary Rojewski #include <sound/soc-component.h> 16*f1b3b320SCezary Rojewski #include "avs.h" 17*f1b3b320SCezary Rojewski #include "path.h" 18*f1b3b320SCezary Rojewski #include "topology.h" 19*f1b3b320SCezary Rojewski 20*f1b3b320SCezary Rojewski struct avs_dma_data { 21*f1b3b320SCezary Rojewski struct avs_tplg_path_template *template; 22*f1b3b320SCezary Rojewski struct avs_path *path; 23*f1b3b320SCezary Rojewski /* 24*f1b3b320SCezary Rojewski * link stream is stored within substream's runtime 25*f1b3b320SCezary Rojewski * private_data to fulfill the needs of codec BE path 26*f1b3b320SCezary Rojewski * 27*f1b3b320SCezary Rojewski * host stream assigned 28*f1b3b320SCezary Rojewski */ 29*f1b3b320SCezary Rojewski struct hdac_ext_stream *host_stream; 30*f1b3b320SCezary Rojewski }; 31*f1b3b320SCezary Rojewski 32*f1b3b320SCezary Rojewski static ssize_t topology_name_read(struct file *file, char __user *user_buf, size_t count, 33*f1b3b320SCezary Rojewski loff_t *ppos) 34*f1b3b320SCezary Rojewski { 35*f1b3b320SCezary Rojewski struct snd_soc_component *component = file->private_data; 36*f1b3b320SCezary Rojewski struct snd_soc_card *card = component->card; 37*f1b3b320SCezary Rojewski struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); 38*f1b3b320SCezary Rojewski char buf[64]; 39*f1b3b320SCezary Rojewski size_t len; 40*f1b3b320SCezary Rojewski 41*f1b3b320SCezary Rojewski len = snprintf(buf, sizeof(buf), "%s/%s\n", component->driver->topology_name_prefix, 42*f1b3b320SCezary Rojewski mach->tplg_filename); 43*f1b3b320SCezary Rojewski 44*f1b3b320SCezary Rojewski return simple_read_from_buffer(user_buf, count, ppos, buf, len); 45*f1b3b320SCezary Rojewski } 46*f1b3b320SCezary Rojewski 47*f1b3b320SCezary Rojewski static const struct file_operations topology_name_fops = { 48*f1b3b320SCezary Rojewski .open = simple_open, 49*f1b3b320SCezary Rojewski .read = topology_name_read, 50*f1b3b320SCezary Rojewski .llseek = default_llseek, 51*f1b3b320SCezary Rojewski }; 52*f1b3b320SCezary Rojewski 53*f1b3b320SCezary Rojewski static int avs_component_load_libraries(struct avs_soc_component *acomp) 54*f1b3b320SCezary Rojewski { 55*f1b3b320SCezary Rojewski struct avs_tplg *tplg = acomp->tplg; 56*f1b3b320SCezary Rojewski struct avs_dev *adev = to_avs_dev(acomp->base.dev); 57*f1b3b320SCezary Rojewski int ret; 58*f1b3b320SCezary Rojewski 59*f1b3b320SCezary Rojewski if (!tplg->num_libs) 60*f1b3b320SCezary Rojewski return 0; 61*f1b3b320SCezary Rojewski 62*f1b3b320SCezary Rojewski /* Parent device may be asleep and library loading involves IPCs. */ 63*f1b3b320SCezary Rojewski ret = pm_runtime_resume_and_get(adev->dev); 64*f1b3b320SCezary Rojewski if (ret < 0) 65*f1b3b320SCezary Rojewski return ret; 66*f1b3b320SCezary Rojewski 67*f1b3b320SCezary Rojewski avs_hda_clock_gating_enable(adev, false); 68*f1b3b320SCezary Rojewski avs_hda_l1sen_enable(adev, false); 69*f1b3b320SCezary Rojewski 70*f1b3b320SCezary Rojewski ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs); 71*f1b3b320SCezary Rojewski 72*f1b3b320SCezary Rojewski avs_hda_l1sen_enable(adev, true); 73*f1b3b320SCezary Rojewski avs_hda_clock_gating_enable(adev, true); 74*f1b3b320SCezary Rojewski 75*f1b3b320SCezary Rojewski if (!ret) 76*f1b3b320SCezary Rojewski ret = avs_module_info_init(adev, false); 77*f1b3b320SCezary Rojewski 78*f1b3b320SCezary Rojewski pm_runtime_mark_last_busy(adev->dev); 79*f1b3b320SCezary Rojewski pm_runtime_put_autosuspend(adev->dev); 80*f1b3b320SCezary Rojewski 81*f1b3b320SCezary Rojewski return ret; 82*f1b3b320SCezary Rojewski } 83*f1b3b320SCezary Rojewski 84*f1b3b320SCezary Rojewski static int avs_component_probe(struct snd_soc_component *component) 85*f1b3b320SCezary Rojewski { 86*f1b3b320SCezary Rojewski struct snd_soc_card *card = component->card; 87*f1b3b320SCezary Rojewski struct snd_soc_acpi_mach *mach; 88*f1b3b320SCezary Rojewski struct avs_soc_component *acomp; 89*f1b3b320SCezary Rojewski struct avs_dev *adev; 90*f1b3b320SCezary Rojewski char *filename; 91*f1b3b320SCezary Rojewski int ret; 92*f1b3b320SCezary Rojewski 93*f1b3b320SCezary Rojewski dev_dbg(card->dev, "probing %s card %s\n", component->name, card->name); 94*f1b3b320SCezary Rojewski mach = dev_get_platdata(card->dev); 95*f1b3b320SCezary Rojewski acomp = to_avs_soc_component(component); 96*f1b3b320SCezary Rojewski adev = to_avs_dev(component->dev); 97*f1b3b320SCezary Rojewski 98*f1b3b320SCezary Rojewski acomp->tplg = avs_tplg_new(component); 99*f1b3b320SCezary Rojewski if (!acomp->tplg) 100*f1b3b320SCezary Rojewski return -ENOMEM; 101*f1b3b320SCezary Rojewski 102*f1b3b320SCezary Rojewski if (!mach->tplg_filename) 103*f1b3b320SCezary Rojewski goto finalize; 104*f1b3b320SCezary Rojewski 105*f1b3b320SCezary Rojewski /* Load specified topology and create debugfs for it. */ 106*f1b3b320SCezary Rojewski filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix, 107*f1b3b320SCezary Rojewski mach->tplg_filename); 108*f1b3b320SCezary Rojewski if (!filename) 109*f1b3b320SCezary Rojewski return -ENOMEM; 110*f1b3b320SCezary Rojewski 111*f1b3b320SCezary Rojewski ret = avs_load_topology(component, filename); 112*f1b3b320SCezary Rojewski kfree(filename); 113*f1b3b320SCezary Rojewski if (ret < 0) 114*f1b3b320SCezary Rojewski return ret; 115*f1b3b320SCezary Rojewski 116*f1b3b320SCezary Rojewski ret = avs_component_load_libraries(acomp); 117*f1b3b320SCezary Rojewski if (ret < 0) { 118*f1b3b320SCezary Rojewski dev_err(card->dev, "libraries loading failed: %d\n", ret); 119*f1b3b320SCezary Rojewski goto err_load_libs; 120*f1b3b320SCezary Rojewski } 121*f1b3b320SCezary Rojewski 122*f1b3b320SCezary Rojewski finalize: 123*f1b3b320SCezary Rojewski debugfs_create_file("topology_name", 0444, component->debugfs_root, component, 124*f1b3b320SCezary Rojewski &topology_name_fops); 125*f1b3b320SCezary Rojewski 126*f1b3b320SCezary Rojewski mutex_lock(&adev->comp_list_mutex); 127*f1b3b320SCezary Rojewski list_add_tail(&acomp->node, &adev->comp_list); 128*f1b3b320SCezary Rojewski mutex_unlock(&adev->comp_list_mutex); 129*f1b3b320SCezary Rojewski 130*f1b3b320SCezary Rojewski return 0; 131*f1b3b320SCezary Rojewski 132*f1b3b320SCezary Rojewski err_load_libs: 133*f1b3b320SCezary Rojewski avs_remove_topology(component); 134*f1b3b320SCezary Rojewski return ret; 135*f1b3b320SCezary Rojewski } 136*f1b3b320SCezary Rojewski 137*f1b3b320SCezary Rojewski static void avs_component_remove(struct snd_soc_component *component) 138*f1b3b320SCezary Rojewski { 139*f1b3b320SCezary Rojewski struct avs_soc_component *acomp = to_avs_soc_component(component); 140*f1b3b320SCezary Rojewski struct snd_soc_acpi_mach *mach; 141*f1b3b320SCezary Rojewski struct avs_dev *adev = to_avs_dev(component->dev); 142*f1b3b320SCezary Rojewski int ret; 143*f1b3b320SCezary Rojewski 144*f1b3b320SCezary Rojewski mach = dev_get_platdata(component->card->dev); 145*f1b3b320SCezary Rojewski 146*f1b3b320SCezary Rojewski mutex_lock(&adev->comp_list_mutex); 147*f1b3b320SCezary Rojewski list_del(&acomp->node); 148*f1b3b320SCezary Rojewski mutex_unlock(&adev->comp_list_mutex); 149*f1b3b320SCezary Rojewski 150*f1b3b320SCezary Rojewski if (mach->tplg_filename) { 151*f1b3b320SCezary Rojewski ret = avs_remove_topology(component); 152*f1b3b320SCezary Rojewski if (ret < 0) 153*f1b3b320SCezary Rojewski dev_err(component->dev, "unload topology failed: %d\n", ret); 154*f1b3b320SCezary Rojewski } 155*f1b3b320SCezary Rojewski } 156*f1b3b320SCezary Rojewski 157*f1b3b320SCezary Rojewski static int avs_component_open(struct snd_soc_component *component, 158*f1b3b320SCezary Rojewski struct snd_pcm_substream *substream) 159*f1b3b320SCezary Rojewski { 160*f1b3b320SCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 161*f1b3b320SCezary Rojewski struct snd_pcm_hardware hwparams; 162*f1b3b320SCezary Rojewski 163*f1b3b320SCezary Rojewski /* only FE DAI links are handled here */ 164*f1b3b320SCezary Rojewski if (rtd->dai_link->no_pcm) 165*f1b3b320SCezary Rojewski return 0; 166*f1b3b320SCezary Rojewski 167*f1b3b320SCezary Rojewski hwparams.info = SNDRV_PCM_INFO_MMAP | 168*f1b3b320SCezary Rojewski SNDRV_PCM_INFO_MMAP_VALID | 169*f1b3b320SCezary Rojewski SNDRV_PCM_INFO_INTERLEAVED | 170*f1b3b320SCezary Rojewski SNDRV_PCM_INFO_PAUSE | 171*f1b3b320SCezary Rojewski SNDRV_PCM_INFO_NO_PERIOD_WAKEUP; 172*f1b3b320SCezary Rojewski 173*f1b3b320SCezary Rojewski hwparams.formats = SNDRV_PCM_FMTBIT_S16_LE | 174*f1b3b320SCezary Rojewski SNDRV_PCM_FMTBIT_S24_LE | 175*f1b3b320SCezary Rojewski SNDRV_PCM_FMTBIT_S32_LE; 176*f1b3b320SCezary Rojewski hwparams.period_bytes_min = 128; 177*f1b3b320SCezary Rojewski hwparams.period_bytes_max = AZX_MAX_BUF_SIZE / 2; 178*f1b3b320SCezary Rojewski hwparams.periods_min = 2; 179*f1b3b320SCezary Rojewski hwparams.periods_max = AZX_MAX_FRAG; 180*f1b3b320SCezary Rojewski hwparams.buffer_bytes_max = AZX_MAX_BUF_SIZE; 181*f1b3b320SCezary Rojewski hwparams.fifo_size = 0; 182*f1b3b320SCezary Rojewski 183*f1b3b320SCezary Rojewski return snd_soc_set_runtime_hwparams(substream, &hwparams); 184*f1b3b320SCezary Rojewski } 185*f1b3b320SCezary Rojewski 186*f1b3b320SCezary Rojewski static unsigned int avs_hda_stream_dpib_read(struct hdac_ext_stream *stream) 187*f1b3b320SCezary Rojewski { 188*f1b3b320SCezary Rojewski return readl(hdac_stream(stream)->bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE + 189*f1b3b320SCezary Rojewski (AZX_REG_VS_SDXDPIB_XINTERVAL * hdac_stream(stream)->index)); 190*f1b3b320SCezary Rojewski } 191*f1b3b320SCezary Rojewski 192*f1b3b320SCezary Rojewski static snd_pcm_uframes_t 193*f1b3b320SCezary Rojewski avs_component_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) 194*f1b3b320SCezary Rojewski { 195*f1b3b320SCezary Rojewski struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); 196*f1b3b320SCezary Rojewski struct avs_dma_data *data; 197*f1b3b320SCezary Rojewski struct hdac_ext_stream *host_stream; 198*f1b3b320SCezary Rojewski unsigned int pos; 199*f1b3b320SCezary Rojewski 200*f1b3b320SCezary Rojewski data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); 201*f1b3b320SCezary Rojewski if (!data->host_stream) 202*f1b3b320SCezary Rojewski return 0; 203*f1b3b320SCezary Rojewski 204*f1b3b320SCezary Rojewski host_stream = data->host_stream; 205*f1b3b320SCezary Rojewski pos = avs_hda_stream_dpib_read(host_stream); 206*f1b3b320SCezary Rojewski 207*f1b3b320SCezary Rojewski if (pos >= hdac_stream(host_stream)->bufsize) 208*f1b3b320SCezary Rojewski pos = 0; 209*f1b3b320SCezary Rojewski 210*f1b3b320SCezary Rojewski return bytes_to_frames(substream->runtime, pos); 211*f1b3b320SCezary Rojewski } 212*f1b3b320SCezary Rojewski 213*f1b3b320SCezary Rojewski static int avs_component_mmap(struct snd_soc_component *component, 214*f1b3b320SCezary Rojewski struct snd_pcm_substream *substream, 215*f1b3b320SCezary Rojewski struct vm_area_struct *vma) 216*f1b3b320SCezary Rojewski { 217*f1b3b320SCezary Rojewski return snd_pcm_lib_default_mmap(substream, vma); 218*f1b3b320SCezary Rojewski } 219*f1b3b320SCezary Rojewski 220*f1b3b320SCezary Rojewski #define MAX_PREALLOC_SIZE (32 * 1024 * 1024) 221*f1b3b320SCezary Rojewski 222*f1b3b320SCezary Rojewski static int avs_component_construct(struct snd_soc_component *component, 223*f1b3b320SCezary Rojewski struct snd_soc_pcm_runtime *rtd) 224*f1b3b320SCezary Rojewski { 225*f1b3b320SCezary Rojewski struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0); 226*f1b3b320SCezary Rojewski struct snd_pcm *pcm = rtd->pcm; 227*f1b3b320SCezary Rojewski 228*f1b3b320SCezary Rojewski if (dai->driver->playback.channels_min) 229*f1b3b320SCezary Rojewski snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, 230*f1b3b320SCezary Rojewski SNDRV_DMA_TYPE_DEV_SG, component->dev, 0, 231*f1b3b320SCezary Rojewski MAX_PREALLOC_SIZE); 232*f1b3b320SCezary Rojewski 233*f1b3b320SCezary Rojewski if (dai->driver->capture.channels_min) 234*f1b3b320SCezary Rojewski snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, 235*f1b3b320SCezary Rojewski SNDRV_DMA_TYPE_DEV_SG, component->dev, 0, 236*f1b3b320SCezary Rojewski MAX_PREALLOC_SIZE); 237*f1b3b320SCezary Rojewski 238*f1b3b320SCezary Rojewski return 0; 239*f1b3b320SCezary Rojewski } 240*f1b3b320SCezary Rojewski 241*f1b3b320SCezary Rojewski static const struct snd_soc_component_driver avs_component_driver = { 242*f1b3b320SCezary Rojewski .name = "avs-pcm", 243*f1b3b320SCezary Rojewski .probe = avs_component_probe, 244*f1b3b320SCezary Rojewski .remove = avs_component_remove, 245*f1b3b320SCezary Rojewski .open = avs_component_open, 246*f1b3b320SCezary Rojewski .pointer = avs_component_pointer, 247*f1b3b320SCezary Rojewski .mmap = avs_component_mmap, 248*f1b3b320SCezary Rojewski .pcm_construct = avs_component_construct, 249*f1b3b320SCezary Rojewski .module_get_upon_open = 1, /* increment refcount when a pcm is opened */ 250*f1b3b320SCezary Rojewski .topology_name_prefix = "intel/avs", 251*f1b3b320SCezary Rojewski .non_legacy_dai_naming = true, 252*f1b3b320SCezary Rojewski }; 253*f1b3b320SCezary Rojewski 254*f1b3b320SCezary Rojewski __maybe_unused 255*f1b3b320SCezary Rojewski static int avs_soc_component_register(struct device *dev, const char *name, 256*f1b3b320SCezary Rojewski const struct snd_soc_component_driver *drv, 257*f1b3b320SCezary Rojewski struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais) 258*f1b3b320SCezary Rojewski { 259*f1b3b320SCezary Rojewski struct avs_soc_component *acomp; 260*f1b3b320SCezary Rojewski int ret; 261*f1b3b320SCezary Rojewski 262*f1b3b320SCezary Rojewski acomp = devm_kzalloc(dev, sizeof(*acomp), GFP_KERNEL); 263*f1b3b320SCezary Rojewski if (!acomp) 264*f1b3b320SCezary Rojewski return -ENOMEM; 265*f1b3b320SCezary Rojewski 266*f1b3b320SCezary Rojewski ret = snd_soc_component_initialize(&acomp->base, drv, dev); 267*f1b3b320SCezary Rojewski if (ret < 0) 268*f1b3b320SCezary Rojewski return ret; 269*f1b3b320SCezary Rojewski 270*f1b3b320SCezary Rojewski /* force name change after ASoC is done with its init */ 271*f1b3b320SCezary Rojewski acomp->base.name = name; 272*f1b3b320SCezary Rojewski INIT_LIST_HEAD(&acomp->node); 273*f1b3b320SCezary Rojewski 274*f1b3b320SCezary Rojewski return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais); 275*f1b3b320SCezary Rojewski } 276