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_COMETLAKE_LP) || \ 133 IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) 134 135 static const struct sof_dev_desc cml_desc = { 136 .machines = snd_soc_acpi_intel_cnl_machines, 137 .resindex_lpe_base = 0, 138 .resindex_pcicfg_base = -1, 139 .resindex_imr_base = -1, 140 .irqindex_host_ipc = -1, 141 .resindex_dma_base = -1, 142 .chip_info = &cnl_chip_info, 143 .default_fw_path = "intel/sof", 144 .default_tplg_path = "intel/sof-tplg", 145 .nocodec_fw_filename = "sof-cnl.ri", 146 .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", 147 .ops = &sof_cnl_ops, 148 .arch_ops = &sof_xtensa_arch_ops 149 }; 150 #endif 151 152 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) 153 static const struct sof_dev_desc icl_desc = { 154 .machines = snd_soc_acpi_intel_icl_machines, 155 .resindex_lpe_base = 0, 156 .resindex_pcicfg_base = -1, 157 .resindex_imr_base = -1, 158 .irqindex_host_ipc = -1, 159 .resindex_dma_base = -1, 160 .chip_info = &icl_chip_info, 161 .default_fw_path = "intel/sof", 162 .default_tplg_path = "intel/sof-tplg", 163 .nocodec_fw_filename = "sof-icl.ri", 164 .nocodec_tplg_filename = "sof-icl-nocodec.tplg", 165 .ops = &sof_cnl_ops, 166 .arch_ops = &sof_xtensa_arch_ops 167 }; 168 #endif 169 170 #if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) 171 static const struct sof_dev_desc skl_desc = { 172 .machines = snd_soc_acpi_intel_skl_machines, 173 .resindex_lpe_base = 0, 174 .resindex_pcicfg_base = -1, 175 .resindex_imr_base = -1, 176 .irqindex_host_ipc = -1, 177 .resindex_dma_base = -1, 178 .chip_info = &skl_chip_info, 179 .default_fw_path = "intel/sof", 180 .default_tplg_path = "intel/sof-tplg", 181 .nocodec_fw_filename = "sof-skl.ri", 182 .nocodec_tplg_filename = "sof-skl-nocodec.tplg", 183 .ops = &sof_skl_ops, 184 .arch_ops = &sof_xtensa_arch_ops 185 }; 186 #endif 187 188 #if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) 189 static const struct sof_dev_desc kbl_desc = { 190 .machines = snd_soc_acpi_intel_kbl_machines, 191 .resindex_lpe_base = 0, 192 .resindex_pcicfg_base = -1, 193 .resindex_imr_base = -1, 194 .irqindex_host_ipc = -1, 195 .resindex_dma_base = -1, 196 .chip_info = &skl_chip_info, 197 .default_fw_path = "intel/sof", 198 .default_tplg_path = "intel/sof-tplg", 199 .nocodec_fw_filename = "sof-kbl.ri", 200 .nocodec_tplg_filename = "sof-kbl-nocodec.tplg", 201 .ops = &sof_skl_ops, 202 .arch_ops = &sof_xtensa_arch_ops 203 }; 204 #endif 205 206 static const struct dev_pm_ops sof_pci_pm = { 207 SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) 208 SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, 209 snd_sof_runtime_idle) 210 }; 211 212 static void sof_pci_probe_complete(struct device *dev) 213 { 214 dev_dbg(dev, "Completing SOF PCI probe"); 215 216 /* allow runtime_pm */ 217 pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); 218 pm_runtime_use_autosuspend(dev); 219 220 /* 221 * runtime pm for pci device is "forbidden" by default. 222 * so call pm_runtime_allow() to enable it. 223 */ 224 pm_runtime_allow(dev); 225 226 /* follow recommendation in pci-driver.c to decrement usage counter */ 227 pm_runtime_put_noidle(dev); 228 } 229 230 static int sof_pci_probe(struct pci_dev *pci, 231 const struct pci_device_id *pci_id) 232 { 233 struct device *dev = &pci->dev; 234 const struct sof_dev_desc *desc = 235 (const struct sof_dev_desc *)pci_id->driver_data; 236 struct snd_soc_acpi_mach *mach; 237 struct snd_sof_pdata *sof_pdata; 238 const struct snd_sof_dsp_ops *ops; 239 int ret; 240 241 dev_dbg(&pci->dev, "PCI DSP detected"); 242 243 /* get ops for platform */ 244 ops = desc->ops; 245 if (!ops) { 246 dev_err(dev, "error: no matching PCI descriptor ops\n"); 247 return -ENODEV; 248 } 249 250 sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); 251 if (!sof_pdata) 252 return -ENOMEM; 253 254 ret = pcim_enable_device(pci); 255 if (ret < 0) 256 return ret; 257 258 ret = pci_request_regions(pci, "Audio DSP"); 259 if (ret < 0) 260 return ret; 261 262 #if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) 263 /* force nocodec mode */ 264 dev_warn(dev, "Force to use nocodec mode\n"); 265 mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); 266 if (!mach) { 267 ret = -ENOMEM; 268 goto release_regions; 269 } 270 ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); 271 if (ret < 0) 272 goto release_regions; 273 274 #else 275 /* find machine */ 276 mach = snd_soc_acpi_find_machine(desc->machines); 277 if (!mach) { 278 dev_warn(dev, "warning: No matching ASoC machine driver found\n"); 279 } else { 280 mach->mach_params.platform = dev_name(dev); 281 sof_pdata->fw_filename = mach->sof_fw_filename; 282 sof_pdata->tplg_filename = mach->sof_tplg_filename; 283 } 284 #endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */ 285 286 sof_pdata->name = pci_name(pci); 287 sof_pdata->machine = mach; 288 sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data; 289 sof_pdata->dev = dev; 290 sof_pdata->platform = dev_name(dev); 291 292 /* alternate fw and tplg filenames ? */ 293 if (fw_path) 294 sof_pdata->fw_filename_prefix = fw_path; 295 else 296 sof_pdata->fw_filename_prefix = 297 sof_pdata->desc->default_fw_path; 298 299 if (tplg_path) 300 sof_pdata->tplg_filename_prefix = tplg_path; 301 else 302 sof_pdata->tplg_filename_prefix = 303 sof_pdata->desc->default_tplg_path; 304 305 #if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 306 /* set callback to enable runtime_pm */ 307 sof_pdata->sof_probe_complete = sof_pci_probe_complete; 308 #endif 309 /* call sof helper for DSP hardware probe */ 310 ret = snd_sof_device_probe(dev, sof_pdata); 311 if (ret) { 312 dev_err(dev, "error: failed to probe DSP hardware!\n"); 313 goto release_regions; 314 } 315 316 #if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 317 sof_pci_probe_complete(dev); 318 #endif 319 320 return ret; 321 322 release_regions: 323 pci_release_regions(pci); 324 325 return ret; 326 } 327 328 static void sof_pci_remove(struct pci_dev *pci) 329 { 330 /* call sof helper for DSP hardware remove */ 331 snd_sof_device_remove(&pci->dev); 332 333 /* follow recommendation in pci-driver.c to increment usage counter */ 334 pm_runtime_get_noresume(&pci->dev); 335 336 /* release pci regions and disable device */ 337 pci_release_regions(pci); 338 } 339 340 /* PCI IDs */ 341 static const struct pci_device_id sof_pci_ids[] = { 342 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) 343 { PCI_DEVICE(0x8086, 0x119a), 344 .driver_data = (unsigned long)&tng_desc}, 345 #endif 346 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 347 /* BXT-P & Apollolake */ 348 { PCI_DEVICE(0x8086, 0x5a98), 349 .driver_data = (unsigned long)&bxt_desc}, 350 { PCI_DEVICE(0x8086, 0x1a98), 351 .driver_data = (unsigned long)&bxt_desc}, 352 #endif 353 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) 354 { PCI_DEVICE(0x8086, 0x3198), 355 .driver_data = (unsigned long)&glk_desc}, 356 #endif 357 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) 358 { PCI_DEVICE(0x8086, 0x9dc8), 359 .driver_data = (unsigned long)&cnl_desc}, 360 #endif 361 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) 362 { PCI_DEVICE(0x8086, 0xa348), 363 .driver_data = (unsigned long)&cfl_desc}, 364 #endif 365 #if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) 366 { PCI_DEVICE(0x8086, 0x9d71), 367 .driver_data = (unsigned long)&kbl_desc}, 368 #endif 369 #if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) 370 { PCI_DEVICE(0x8086, 0x9d70), 371 .driver_data = (unsigned long)&skl_desc}, 372 #endif 373 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) 374 { PCI_DEVICE(0x8086, 0x34C8), 375 .driver_data = (unsigned long)&icl_desc}, 376 #endif 377 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) 378 { PCI_DEVICE(0x8086, 0x02c8), 379 .driver_data = (unsigned long)&cml_desc}, 380 #endif 381 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) 382 { PCI_DEVICE(0x8086, 0x06c8), 383 .driver_data = (unsigned long)&cml_desc}, 384 #endif 385 { 0, } 386 }; 387 MODULE_DEVICE_TABLE(pci, sof_pci_ids); 388 389 /* pci_driver definition */ 390 static struct pci_driver snd_sof_pci_driver = { 391 .name = "sof-audio-pci", 392 .id_table = sof_pci_ids, 393 .probe = sof_pci_probe, 394 .remove = sof_pci_remove, 395 .driver = { 396 .pm = &sof_pci_pm, 397 }, 398 }; 399 module_pci_driver(snd_sof_pci_driver); 400 401 MODULE_LICENSE("Dual BSD/GPL"); 402