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 <[email protected]> 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/intel-dsp-config.h> 16 #include <sound/soc-acpi.h> 17 #include <sound/soc-acpi-intel-match.h> 18 #include <sound/sof.h> 19 #include "ops.h" 20 21 /* platform specific devices */ 22 #include "intel/shim.h" 23 #include "intel/hda.h" 24 25 static char *fw_path; 26 module_param(fw_path, charp, 0444); 27 MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); 28 29 static char *tplg_path; 30 module_param(tplg_path, charp, 0444); 31 MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); 32 33 static int sof_pci_debug; 34 module_param_named(sof_pci_debug, sof_pci_debug, int, 0444); 35 MODULE_PARM_DESC(sof_pci_debug, "SOF PCI debug options (0x0 all off)"); 36 37 #define SOF_PCI_DISABLE_PM_RUNTIME BIT(0) 38 39 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 40 static const struct sof_dev_desc bxt_desc = { 41 .machines = snd_soc_acpi_intel_bxt_machines, 42 .resindex_lpe_base = 0, 43 .resindex_pcicfg_base = -1, 44 .resindex_imr_base = -1, 45 .irqindex_host_ipc = -1, 46 .resindex_dma_base = -1, 47 .chip_info = &apl_chip_info, 48 .default_fw_path = "intel/sof", 49 .default_tplg_path = "intel/sof-tplg", 50 .default_fw_filename = "sof-apl.ri", 51 .nocodec_tplg_filename = "sof-apl-nocodec.tplg", 52 .ops = &sof_apl_ops, 53 }; 54 #endif 55 56 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) 57 static const struct sof_dev_desc glk_desc = { 58 .machines = snd_soc_acpi_intel_glk_machines, 59 .resindex_lpe_base = 0, 60 .resindex_pcicfg_base = -1, 61 .resindex_imr_base = -1, 62 .irqindex_host_ipc = -1, 63 .resindex_dma_base = -1, 64 .chip_info = &apl_chip_info, 65 .default_fw_path = "intel/sof", 66 .default_tplg_path = "intel/sof-tplg", 67 .default_fw_filename = "sof-glk.ri", 68 .nocodec_tplg_filename = "sof-glk-nocodec.tplg", 69 .ops = &sof_apl_ops, 70 }; 71 #endif 72 73 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) 74 static struct snd_soc_acpi_mach sof_tng_machines[] = { 75 { 76 .id = "INT343A", 77 .drv_name = "edison", 78 .sof_fw_filename = "sof-byt.ri", 79 .sof_tplg_filename = "sof-byt.tplg", 80 }, 81 {} 82 }; 83 84 static const struct sof_dev_desc tng_desc = { 85 .machines = sof_tng_machines, 86 .resindex_lpe_base = 3, /* IRAM, but subtract IRAM offset */ 87 .resindex_pcicfg_base = -1, 88 .resindex_imr_base = 0, 89 .irqindex_host_ipc = -1, 90 .resindex_dma_base = -1, 91 .chip_info = &tng_chip_info, 92 .default_fw_path = "intel/sof", 93 .default_tplg_path = "intel/sof-tplg", 94 .default_fw_filename = "sof-byt.ri", 95 .nocodec_tplg_filename = "sof-byt.tplg", 96 .ops = &sof_tng_ops, 97 }; 98 #endif 99 100 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) 101 static const struct sof_dev_desc cnl_desc = { 102 .machines = snd_soc_acpi_intel_cnl_machines, 103 .resindex_lpe_base = 0, 104 .resindex_pcicfg_base = -1, 105 .resindex_imr_base = -1, 106 .irqindex_host_ipc = -1, 107 .resindex_dma_base = -1, 108 .chip_info = &cnl_chip_info, 109 .default_fw_path = "intel/sof", 110 .default_tplg_path = "intel/sof-tplg", 111 .default_fw_filename = "sof-cnl.ri", 112 .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", 113 .ops = &sof_cnl_ops, 114 }; 115 #endif 116 117 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) 118 static const struct sof_dev_desc cfl_desc = { 119 .machines = snd_soc_acpi_intel_cfl_machines, 120 .resindex_lpe_base = 0, 121 .resindex_pcicfg_base = -1, 122 .resindex_imr_base = -1, 123 .irqindex_host_ipc = -1, 124 .resindex_dma_base = -1, 125 .chip_info = &cnl_chip_info, 126 .default_fw_path = "intel/sof", 127 .default_tplg_path = "intel/sof-tplg", 128 .default_fw_filename = "sof-cfl.ri", 129 .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", 130 .ops = &sof_cnl_ops, 131 }; 132 #endif 133 134 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) || \ 135 IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) 136 137 static const struct sof_dev_desc cml_desc = { 138 .machines = snd_soc_acpi_intel_cml_machines, 139 .resindex_lpe_base = 0, 140 .resindex_pcicfg_base = -1, 141 .resindex_imr_base = -1, 142 .irqindex_host_ipc = -1, 143 .resindex_dma_base = -1, 144 .chip_info = &cnl_chip_info, 145 .default_fw_path = "intel/sof", 146 .default_tplg_path = "intel/sof-tplg", 147 .default_fw_filename = "sof-cml.ri", 148 .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", 149 .ops = &sof_cnl_ops, 150 }; 151 #endif 152 153 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) 154 static const struct sof_dev_desc icl_desc = { 155 .machines = snd_soc_acpi_intel_icl_machines, 156 .resindex_lpe_base = 0, 157 .resindex_pcicfg_base = -1, 158 .resindex_imr_base = -1, 159 .irqindex_host_ipc = -1, 160 .resindex_dma_base = -1, 161 .chip_info = &icl_chip_info, 162 .default_fw_path = "intel/sof", 163 .default_tplg_path = "intel/sof-tplg", 164 .default_fw_filename = "sof-icl.ri", 165 .nocodec_tplg_filename = "sof-icl-nocodec.tplg", 166 .ops = &sof_cnl_ops, 167 }; 168 #endif 169 170 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) 171 static const struct sof_dev_desc tgl_desc = { 172 .machines = snd_soc_acpi_intel_tgl_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 = &tgl_chip_info, 179 .default_fw_path = "intel/sof", 180 .default_tplg_path = "intel/sof-tplg", 181 .default_fw_filename = "sof-tgl.ri", 182 .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", 183 .ops = &sof_cnl_ops, 184 }; 185 #endif 186 187 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) 188 static const struct sof_dev_desc ehl_desc = { 189 .machines = snd_soc_acpi_intel_ehl_machines, 190 .resindex_lpe_base = 0, 191 .resindex_pcicfg_base = -1, 192 .resindex_imr_base = -1, 193 .irqindex_host_ipc = -1, 194 .resindex_dma_base = -1, 195 .chip_info = &ehl_chip_info, 196 .default_fw_path = "intel/sof", 197 .default_tplg_path = "intel/sof-tplg", 198 .default_fw_filename = "sof-ehl.ri", 199 .nocodec_tplg_filename = "sof-ehl-nocodec.tplg", 200 .ops = &sof_cnl_ops, 201 }; 202 #endif 203 204 #if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) 205 static const struct sof_dev_desc jsl_desc = { 206 .machines = snd_soc_acpi_intel_jsl_machines, 207 .resindex_lpe_base = 0, 208 .resindex_pcicfg_base = -1, 209 .resindex_imr_base = -1, 210 .irqindex_host_ipc = -1, 211 .resindex_dma_base = -1, 212 .chip_info = &jsl_chip_info, 213 .default_fw_path = "intel/sof", 214 .default_tplg_path = "intel/sof-tplg", 215 .nocodec_tplg_filename = "sof-jsl-nocodec.tplg", 216 .ops = &sof_cnl_ops, 217 }; 218 #endif 219 220 static const struct dev_pm_ops sof_pci_pm = { 221 .prepare = snd_sof_prepare, 222 .complete = snd_sof_complete, 223 SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) 224 SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, 225 snd_sof_runtime_idle) 226 }; 227 228 static void sof_pci_probe_complete(struct device *dev) 229 { 230 dev_dbg(dev, "Completing SOF PCI probe"); 231 232 if (sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME) 233 return; 234 235 /* allow runtime_pm */ 236 pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); 237 pm_runtime_use_autosuspend(dev); 238 239 /* 240 * runtime pm for pci device is "forbidden" by default. 241 * so call pm_runtime_allow() to enable it. 242 */ 243 pm_runtime_allow(dev); 244 245 /* mark last_busy for pm_runtime to make sure not suspend immediately */ 246 pm_runtime_mark_last_busy(dev); 247 248 /* follow recommendation in pci-driver.c to decrement usage counter */ 249 pm_runtime_put_noidle(dev); 250 } 251 252 static int sof_pci_probe(struct pci_dev *pci, 253 const struct pci_device_id *pci_id) 254 { 255 struct device *dev = &pci->dev; 256 const struct sof_dev_desc *desc = 257 (const struct sof_dev_desc *)pci_id->driver_data; 258 struct snd_sof_pdata *sof_pdata; 259 const struct snd_sof_dsp_ops *ops; 260 int ret; 261 262 ret = snd_intel_dsp_driver_probe(pci); 263 if (ret != SND_INTEL_DSP_DRIVER_ANY && 264 ret != SND_INTEL_DSP_DRIVER_SOF) 265 return -ENODEV; 266 267 dev_dbg(&pci->dev, "PCI DSP detected"); 268 269 /* get ops for platform */ 270 ops = desc->ops; 271 if (!ops) { 272 dev_err(dev, "error: no matching PCI descriptor ops\n"); 273 return -ENODEV; 274 } 275 276 sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); 277 if (!sof_pdata) 278 return -ENOMEM; 279 280 ret = pcim_enable_device(pci); 281 if (ret < 0) 282 return ret; 283 284 ret = pci_request_regions(pci, "Audio DSP"); 285 if (ret < 0) 286 return ret; 287 288 sof_pdata->name = pci_name(pci); 289 sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data; 290 sof_pdata->dev = dev; 291 sof_pdata->fw_filename = desc->default_fw_filename; 292 293 /* alternate fw and tplg filenames ? */ 294 if (fw_path) 295 sof_pdata->fw_filename_prefix = fw_path; 296 else 297 sof_pdata->fw_filename_prefix = 298 sof_pdata->desc->default_fw_path; 299 300 if (tplg_path) 301 sof_pdata->tplg_filename_prefix = tplg_path; 302 else 303 sof_pdata->tplg_filename_prefix = 304 sof_pdata->desc->default_tplg_path; 305 306 #if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 307 /* set callback to enable runtime_pm */ 308 sof_pdata->sof_probe_complete = sof_pci_probe_complete; 309 #endif 310 /* call sof helper for DSP hardware probe */ 311 ret = snd_sof_device_probe(dev, sof_pdata); 312 if (ret) { 313 dev_err(dev, "error: failed to probe DSP hardware!\n"); 314 goto release_regions; 315 } 316 317 #if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 318 sof_pci_probe_complete(dev); 319 #endif 320 321 return ret; 322 323 release_regions: 324 pci_release_regions(pci); 325 326 return ret; 327 } 328 329 static void sof_pci_remove(struct pci_dev *pci) 330 { 331 /* call sof helper for DSP hardware remove */ 332 snd_sof_device_remove(&pci->dev); 333 334 /* follow recommendation in pci-driver.c to increment usage counter */ 335 if (!(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME)) 336 pm_runtime_get_noresume(&pci->dev); 337 338 /* release pci regions and disable device */ 339 pci_release_regions(pci); 340 } 341 342 /* PCI IDs */ 343 static const struct pci_device_id sof_pci_ids[] = { 344 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) 345 { PCI_DEVICE(0x8086, 0x119a), 346 .driver_data = (unsigned long)&tng_desc}, 347 #endif 348 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 349 /* BXT-P & Apollolake */ 350 { PCI_DEVICE(0x8086, 0x5a98), 351 .driver_data = (unsigned long)&bxt_desc}, 352 { PCI_DEVICE(0x8086, 0x1a98), 353 .driver_data = (unsigned long)&bxt_desc}, 354 #endif 355 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) 356 { PCI_DEVICE(0x8086, 0x3198), 357 .driver_data = (unsigned long)&glk_desc}, 358 #endif 359 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) 360 { PCI_DEVICE(0x8086, 0x9dc8), 361 .driver_data = (unsigned long)&cnl_desc}, 362 #endif 363 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) 364 { PCI_DEVICE(0x8086, 0xa348), 365 .driver_data = (unsigned long)&cfl_desc}, 366 #endif 367 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) 368 { PCI_DEVICE(0x8086, 0x34C8), 369 .driver_data = (unsigned long)&icl_desc}, 370 #endif 371 #if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) 372 { PCI_DEVICE(0x8086, 0x38c8), 373 .driver_data = (unsigned long)&jsl_desc}, 374 #endif 375 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) 376 { PCI_DEVICE(0x8086, 0x02c8), 377 .driver_data = (unsigned long)&cml_desc}, 378 #endif 379 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) 380 { PCI_DEVICE(0x8086, 0x06c8), 381 .driver_data = (unsigned long)&cml_desc}, 382 #endif 383 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) 384 { PCI_DEVICE(0x8086, 0xa0c8), 385 .driver_data = (unsigned long)&tgl_desc}, 386 #endif 387 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) 388 { PCI_DEVICE(0x8086, 0x4b55), 389 .driver_data = (unsigned long)&ehl_desc}, 390 #endif 391 { 0, } 392 }; 393 MODULE_DEVICE_TABLE(pci, sof_pci_ids); 394 395 /* pci_driver definition */ 396 static struct pci_driver snd_sof_pci_driver = { 397 .name = "sof-audio-pci", 398 .id_table = sof_pci_ids, 399 .probe = sof_pci_probe, 400 .remove = sof_pci_remove, 401 .driver = { 402 .pm = &sof_pci_pm, 403 }, 404 }; 405 module_pci_driver(snd_sof_pci_driver); 406 407 MODULE_LICENSE("Dual BSD/GPL"); 408 MODULE_IMPORT_NS(SND_SOC_SOF_MERRIFIELD); 409 MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); 410