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 /* mark last_busy for pm_runtime to make sure not suspend immediately */ 227 pm_runtime_mark_last_busy(dev); 228 229 /* follow recommendation in pci-driver.c to decrement usage counter */ 230 pm_runtime_put_noidle(dev); 231 } 232 233 static int sof_pci_probe(struct pci_dev *pci, 234 const struct pci_device_id *pci_id) 235 { 236 struct device *dev = &pci->dev; 237 const struct sof_dev_desc *desc = 238 (const struct sof_dev_desc *)pci_id->driver_data; 239 struct snd_soc_acpi_mach *mach; 240 struct snd_sof_pdata *sof_pdata; 241 const struct snd_sof_dsp_ops *ops; 242 int ret; 243 244 dev_dbg(&pci->dev, "PCI DSP detected"); 245 246 /* get ops for platform */ 247 ops = desc->ops; 248 if (!ops) { 249 dev_err(dev, "error: no matching PCI descriptor ops\n"); 250 return -ENODEV; 251 } 252 253 sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); 254 if (!sof_pdata) 255 return -ENOMEM; 256 257 ret = pcim_enable_device(pci); 258 if (ret < 0) 259 return ret; 260 261 ret = pci_request_regions(pci, "Audio DSP"); 262 if (ret < 0) 263 return ret; 264 265 #if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) 266 /* force nocodec mode */ 267 dev_warn(dev, "Force to use nocodec mode\n"); 268 mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); 269 if (!mach) { 270 ret = -ENOMEM; 271 goto release_regions; 272 } 273 ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); 274 if (ret < 0) 275 goto release_regions; 276 277 #else 278 /* find machine */ 279 mach = snd_soc_acpi_find_machine(desc->machines); 280 if (!mach) { 281 dev_warn(dev, "warning: No matching ASoC machine driver found\n"); 282 } else { 283 mach->mach_params.platform = dev_name(dev); 284 sof_pdata->fw_filename = mach->sof_fw_filename; 285 sof_pdata->tplg_filename = mach->sof_tplg_filename; 286 } 287 #endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */ 288 289 sof_pdata->name = pci_name(pci); 290 sof_pdata->machine = mach; 291 sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data; 292 sof_pdata->dev = dev; 293 sof_pdata->platform = dev_name(dev); 294 295 /* alternate fw and tplg filenames ? */ 296 if (fw_path) 297 sof_pdata->fw_filename_prefix = fw_path; 298 else 299 sof_pdata->fw_filename_prefix = 300 sof_pdata->desc->default_fw_path; 301 302 if (tplg_path) 303 sof_pdata->tplg_filename_prefix = tplg_path; 304 else 305 sof_pdata->tplg_filename_prefix = 306 sof_pdata->desc->default_tplg_path; 307 308 #if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 309 /* set callback to enable runtime_pm */ 310 sof_pdata->sof_probe_complete = sof_pci_probe_complete; 311 #endif 312 /* call sof helper for DSP hardware probe */ 313 ret = snd_sof_device_probe(dev, sof_pdata); 314 if (ret) { 315 dev_err(dev, "error: failed to probe DSP hardware!\n"); 316 goto release_regions; 317 } 318 319 #if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 320 sof_pci_probe_complete(dev); 321 #endif 322 323 return ret; 324 325 release_regions: 326 pci_release_regions(pci); 327 328 return ret; 329 } 330 331 static void sof_pci_remove(struct pci_dev *pci) 332 { 333 /* call sof helper for DSP hardware remove */ 334 snd_sof_device_remove(&pci->dev); 335 336 /* follow recommendation in pci-driver.c to increment usage counter */ 337 pm_runtime_get_noresume(&pci->dev); 338 339 /* release pci regions and disable device */ 340 pci_release_regions(pci); 341 } 342 343 /* PCI IDs */ 344 static const struct pci_device_id sof_pci_ids[] = { 345 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) 346 { PCI_DEVICE(0x8086, 0x119a), 347 .driver_data = (unsigned long)&tng_desc}, 348 #endif 349 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 350 /* BXT-P & Apollolake */ 351 { PCI_DEVICE(0x8086, 0x5a98), 352 .driver_data = (unsigned long)&bxt_desc}, 353 { PCI_DEVICE(0x8086, 0x1a98), 354 .driver_data = (unsigned long)&bxt_desc}, 355 #endif 356 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) 357 { PCI_DEVICE(0x8086, 0x3198), 358 .driver_data = (unsigned long)&glk_desc}, 359 #endif 360 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) 361 { PCI_DEVICE(0x8086, 0x9dc8), 362 .driver_data = (unsigned long)&cnl_desc}, 363 #endif 364 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) 365 { PCI_DEVICE(0x8086, 0xa348), 366 .driver_data = (unsigned long)&cfl_desc}, 367 #endif 368 #if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) 369 { PCI_DEVICE(0x8086, 0x9d71), 370 .driver_data = (unsigned long)&kbl_desc}, 371 #endif 372 #if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) 373 { PCI_DEVICE(0x8086, 0x9d70), 374 .driver_data = (unsigned long)&skl_desc}, 375 #endif 376 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) 377 { PCI_DEVICE(0x8086, 0x34C8), 378 .driver_data = (unsigned long)&icl_desc}, 379 #endif 380 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) 381 { PCI_DEVICE(0x8086, 0x02c8), 382 .driver_data = (unsigned long)&cml_desc}, 383 #endif 384 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) 385 { PCI_DEVICE(0x8086, 0x06c8), 386 .driver_data = (unsigned long)&cml_desc}, 387 #endif 388 { 0, } 389 }; 390 MODULE_DEVICE_TABLE(pci, sof_pci_ids); 391 392 /* pci_driver definition */ 393 static struct pci_driver snd_sof_pci_driver = { 394 .name = "sof-audio-pci", 395 .id_table = sof_pci_ids, 396 .probe = sof_pci_probe, 397 .remove = sof_pci_remove, 398 .driver = { 399 .pm = &sof_pci_pm, 400 }, 401 }; 402 module_pci_driver(snd_sof_pci_driver); 403 404 MODULE_LICENSE("Dual BSD/GPL"); 405