1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2 // 3 // This file is provided under a dual BSD/GPLv2 license. When using or 4 // redistributing this file, you may do so under either license. 5 // 6 // Copyright(c) 2018 Intel Corporation. All rights reserved. 7 // 8 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> 9 // 10 11 #include <linux/firmware.h> 12 #include <linux/module.h> 13 #include <linux/pci.h> 14 #include <linux/pm_runtime.h> 15 #include <sound/soc-acpi.h> 16 #include <sound/soc-acpi-intel-match.h> 17 #include <sound/sof.h> 18 #include "ops.h" 19 20 /* platform specific devices */ 21 #include "intel/shim.h" 22 #include "intel/hda.h" 23 24 static char *fw_path; 25 module_param(fw_path, charp, 0444); 26 MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); 27 28 static char *tplg_path; 29 module_param(tplg_path, charp, 0444); 30 MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); 31 32 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 33 static const struct sof_dev_desc bxt_desc = { 34 .machines = snd_soc_acpi_intel_bxt_machines, 35 .resindex_lpe_base = 0, 36 .resindex_pcicfg_base = -1, 37 .resindex_imr_base = -1, 38 .irqindex_host_ipc = -1, 39 .resindex_dma_base = -1, 40 .chip_info = &apl_chip_info, 41 .default_fw_path = "intel/sof", 42 .default_tplg_path = "intel/sof-tplg", 43 .nocodec_fw_filename = "sof-apl.ri", 44 .nocodec_tplg_filename = "sof-apl-nocodec.tplg", 45 .ops = &sof_apl_ops, 46 .arch_ops = &sof_xtensa_arch_ops 47 }; 48 #endif 49 50 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) 51 static const struct sof_dev_desc glk_desc = { 52 .machines = snd_soc_acpi_intel_glk_machines, 53 .resindex_lpe_base = 0, 54 .resindex_pcicfg_base = -1, 55 .resindex_imr_base = -1, 56 .irqindex_host_ipc = -1, 57 .resindex_dma_base = -1, 58 .chip_info = &apl_chip_info, 59 .default_fw_path = "intel/sof", 60 .default_tplg_path = "intel/sof-tplg", 61 .nocodec_fw_filename = "sof-glk.ri", 62 .nocodec_tplg_filename = "sof-glk-nocodec.tplg", 63 .ops = &sof_apl_ops, 64 .arch_ops = &sof_xtensa_arch_ops 65 }; 66 #endif 67 68 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) 69 static struct snd_soc_acpi_mach sof_tng_machines[] = { 70 { 71 .id = "INT343A", 72 .drv_name = "edison", 73 .sof_fw_filename = "sof-byt.ri", 74 .sof_tplg_filename = "sof-byt.tplg", 75 }, 76 {} 77 }; 78 79 static const struct sof_dev_desc tng_desc = { 80 .machines = sof_tng_machines, 81 .resindex_lpe_base = 3, /* IRAM, but subtract IRAM offset */ 82 .resindex_pcicfg_base = -1, 83 .resindex_imr_base = 0, 84 .irqindex_host_ipc = -1, 85 .resindex_dma_base = -1, 86 .chip_info = &tng_chip_info, 87 .default_fw_path = "intel/sof", 88 .default_tplg_path = "intel/sof-tplg", 89 .nocodec_fw_filename = "sof-byt.ri", 90 .nocodec_tplg_filename = "sof-byt.tplg", 91 .ops = &sof_tng_ops, 92 .arch_ops = &sof_xtensa_arch_ops 93 }; 94 #endif 95 96 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) 97 static const struct sof_dev_desc cnl_desc = { 98 .machines = snd_soc_acpi_intel_cnl_machines, 99 .resindex_lpe_base = 0, 100 .resindex_pcicfg_base = -1, 101 .resindex_imr_base = -1, 102 .irqindex_host_ipc = -1, 103 .resindex_dma_base = -1, 104 .chip_info = &cnl_chip_info, 105 .default_fw_path = "intel/sof", 106 .default_tplg_path = "intel/sof-tplg", 107 .nocodec_fw_filename = "sof-cnl.ri", 108 .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", 109 .ops = &sof_cnl_ops, 110 .arch_ops = &sof_xtensa_arch_ops 111 }; 112 #endif 113 114 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) 115 static const struct sof_dev_desc cfl_desc = { 116 .machines = snd_soc_acpi_intel_cnl_machines, 117 .resindex_lpe_base = 0, 118 .resindex_pcicfg_base = -1, 119 .resindex_imr_base = -1, 120 .irqindex_host_ipc = -1, 121 .resindex_dma_base = -1, 122 .chip_info = &cnl_chip_info, 123 .default_fw_path = "intel/sof", 124 .default_tplg_path = "intel/sof-tplg", 125 .nocodec_fw_filename = "sof-cnl.ri", 126 .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", 127 .ops = &sof_cnl_ops, 128 .arch_ops = &sof_xtensa_arch_ops 129 }; 130 #endif 131 132 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) 133 static const struct sof_dev_desc icl_desc = { 134 .machines = snd_soc_acpi_intel_icl_machines, 135 .resindex_lpe_base = 0, 136 .resindex_pcicfg_base = -1, 137 .resindex_imr_base = -1, 138 .irqindex_host_ipc = -1, 139 .resindex_dma_base = -1, 140 .chip_info = &cnl_chip_info, 141 .default_fw_path = "intel/sof", 142 .default_tplg_path = "intel/sof-tplg", 143 .nocodec_fw_filename = "sof-icl.ri", 144 .nocodec_tplg_filename = "sof-icl-nocodec.tplg", 145 .ops = &sof_cnl_ops, 146 .arch_ops = &sof_xtensa_arch_ops 147 }; 148 #endif 149 150 #if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) 151 static const struct sof_dev_desc skl_desc = { 152 .machines = snd_soc_acpi_intel_skl_machines, 153 .resindex_lpe_base = 0, 154 .resindex_pcicfg_base = -1, 155 .resindex_imr_base = -1, 156 .irqindex_host_ipc = -1, 157 .resindex_dma_base = -1, 158 .chip_info = &skl_chip_info, 159 .default_fw_path = "intel/sof", 160 .default_tplg_path = "intel/sof-tplg", 161 .nocodec_fw_filename = "sof-skl.ri", 162 .nocodec_tplg_filename = "sof-skl-nocodec.tplg", 163 .ops = &sof_skl_ops, 164 .arch_ops = &sof_xtensa_arch_ops 165 }; 166 #endif 167 168 #if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) 169 static const struct sof_dev_desc kbl_desc = { 170 .machines = snd_soc_acpi_intel_kbl_machines, 171 .resindex_lpe_base = 0, 172 .resindex_pcicfg_base = -1, 173 .resindex_imr_base = -1, 174 .irqindex_host_ipc = -1, 175 .resindex_dma_base = -1, 176 .chip_info = &skl_chip_info, 177 .default_fw_path = "intel/sof", 178 .default_tplg_path = "intel/sof-tplg", 179 .nocodec_fw_filename = "sof-kbl.ri", 180 .nocodec_tplg_filename = "sof-kbl-nocodec.tplg", 181 .ops = &sof_skl_ops, 182 .arch_ops = &sof_xtensa_arch_ops 183 }; 184 #endif 185 186 static const struct dev_pm_ops sof_pci_pm = { 187 SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) 188 SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, 189 NULL) 190 }; 191 192 static void sof_pci_probe_complete(struct device *dev) 193 { 194 dev_dbg(dev, "Completing SOF PCI probe"); 195 196 /* allow runtime_pm */ 197 pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); 198 pm_runtime_use_autosuspend(dev); 199 200 /* 201 * runtime pm for pci device is "forbidden" by default. 202 * so call pm_runtime_allow() to enable it. 203 */ 204 pm_runtime_allow(dev); 205 206 /* follow recommendation in pci-driver.c to decrement usage counter */ 207 pm_runtime_put_noidle(dev); 208 } 209 210 static int sof_pci_probe(struct pci_dev *pci, 211 const struct pci_device_id *pci_id) 212 { 213 struct device *dev = &pci->dev; 214 const struct sof_dev_desc *desc = 215 (const struct sof_dev_desc *)pci_id->driver_data; 216 struct snd_soc_acpi_mach *mach; 217 struct snd_sof_pdata *sof_pdata; 218 const struct snd_sof_dsp_ops *ops; 219 int ret; 220 221 dev_dbg(&pci->dev, "PCI DSP detected"); 222 223 /* get ops for platform */ 224 ops = desc->ops; 225 if (!ops) { 226 dev_err(dev, "error: no matching PCI descriptor ops\n"); 227 return -ENODEV; 228 } 229 230 sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); 231 if (!sof_pdata) 232 return -ENOMEM; 233 234 ret = pcim_enable_device(pci); 235 if (ret < 0) 236 return ret; 237 238 ret = pci_request_regions(pci, "Audio DSP"); 239 if (ret < 0) 240 return ret; 241 242 #if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) 243 /* force nocodec mode */ 244 dev_warn(dev, "Force to use nocodec mode\n"); 245 mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); 246 if (!mach) { 247 ret = -ENOMEM; 248 goto release_regions; 249 } 250 ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); 251 if (ret < 0) 252 goto release_regions; 253 254 #else 255 /* find machine */ 256 mach = snd_soc_acpi_find_machine(desc->machines); 257 if (!mach) { 258 dev_warn(dev, "warning: No matching ASoC machine driver found\n"); 259 } else { 260 mach->mach_params.platform = dev_name(dev); 261 sof_pdata->fw_filename = mach->sof_fw_filename; 262 sof_pdata->tplg_filename = mach->sof_tplg_filename; 263 } 264 #endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */ 265 266 sof_pdata->name = pci_name(pci); 267 sof_pdata->machine = mach; 268 sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data; 269 sof_pdata->dev = dev; 270 sof_pdata->platform = dev_name(dev); 271 272 /* alternate fw and tplg filenames ? */ 273 if (fw_path) 274 sof_pdata->fw_filename_prefix = fw_path; 275 else 276 sof_pdata->fw_filename_prefix = 277 sof_pdata->desc->default_fw_path; 278 279 if (tplg_path) 280 sof_pdata->tplg_filename_prefix = tplg_path; 281 else 282 sof_pdata->tplg_filename_prefix = 283 sof_pdata->desc->default_tplg_path; 284 285 #if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 286 /* set callback to enable runtime_pm */ 287 sof_pdata->sof_probe_complete = sof_pci_probe_complete; 288 #endif 289 /* call sof helper for DSP hardware probe */ 290 ret = snd_sof_device_probe(dev, sof_pdata); 291 if (ret) { 292 dev_err(dev, "error: failed to probe DSP hardware!\n"); 293 goto release_regions; 294 } 295 296 #if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 297 sof_pci_probe_complete(dev); 298 #endif 299 300 return ret; 301 302 release_regions: 303 pci_release_regions(pci); 304 305 return ret; 306 } 307 308 static void sof_pci_remove(struct pci_dev *pci) 309 { 310 /* call sof helper for DSP hardware remove */ 311 snd_sof_device_remove(&pci->dev); 312 313 /* follow recommendation in pci-driver.c to increment usage counter */ 314 pm_runtime_get_noresume(&pci->dev); 315 316 /* release pci regions and disable device */ 317 pci_release_regions(pci); 318 } 319 320 /* PCI IDs */ 321 static const struct pci_device_id sof_pci_ids[] = { 322 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) 323 { PCI_DEVICE(0x8086, 0x119a), 324 .driver_data = (unsigned long)&tng_desc}, 325 #endif 326 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 327 /* BXT-P & Apollolake */ 328 { PCI_DEVICE(0x8086, 0x5a98), 329 .driver_data = (unsigned long)&bxt_desc}, 330 { PCI_DEVICE(0x8086, 0x1a98), 331 .driver_data = (unsigned long)&bxt_desc}, 332 #endif 333 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) 334 { PCI_DEVICE(0x8086, 0x3198), 335 .driver_data = (unsigned long)&glk_desc}, 336 #endif 337 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) 338 { PCI_DEVICE(0x8086, 0x9dc8), 339 .driver_data = (unsigned long)&cnl_desc}, 340 #endif 341 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) 342 { PCI_DEVICE(0x8086, 0xa348), 343 .driver_data = (unsigned long)&cfl_desc}, 344 #endif 345 #if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) 346 { PCI_DEVICE(0x8086, 0x9d71), 347 .driver_data = (unsigned long)&kbl_desc}, 348 #endif 349 #if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) 350 { PCI_DEVICE(0x8086, 0x9d70), 351 .driver_data = (unsigned long)&skl_desc}, 352 #endif 353 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) 354 { PCI_DEVICE(0x8086, 0x34C8), 355 .driver_data = (unsigned long)&icl_desc}, 356 #endif 357 { 0, } 358 }; 359 MODULE_DEVICE_TABLE(pci, sof_pci_ids); 360 361 /* pci_driver definition */ 362 static struct pci_driver snd_sof_pci_driver = { 363 .name = "sof-audio-pci", 364 .id_table = sof_pci_ids, 365 .probe = sof_pci_probe, 366 .remove = sof_pci_remove, 367 .driver = { 368 .pm = &sof_pci_pm, 369 }, 370 }; 371 module_pci_driver(snd_sof_pci_driver); 372 373 MODULE_LICENSE("Dual BSD/GPL"); 374