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