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 .nocodec_tplg_filename = "sof-jsl-nocodec.tplg", 239 .ops = &sof_cnl_ops, 240 }; 241 #endif 242 243 static const struct dev_pm_ops sof_pci_pm = { 244 .prepare = snd_sof_prepare, 245 .complete = snd_sof_complete, 246 SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) 247 SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, 248 snd_sof_runtime_idle) 249 }; 250 251 static void sof_pci_probe_complete(struct device *dev) 252 { 253 dev_dbg(dev, "Completing SOF PCI probe"); 254 255 if (sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME) 256 return; 257 258 /* allow runtime_pm */ 259 pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); 260 pm_runtime_use_autosuspend(dev); 261 262 /* 263 * runtime pm for pci device is "forbidden" by default. 264 * so call pm_runtime_allow() to enable it. 265 */ 266 pm_runtime_allow(dev); 267 268 /* mark last_busy for pm_runtime to make sure not suspend immediately */ 269 pm_runtime_mark_last_busy(dev); 270 271 /* follow recommendation in pci-driver.c to decrement usage counter */ 272 pm_runtime_put_noidle(dev); 273 } 274 275 static int sof_pci_probe(struct pci_dev *pci, 276 const struct pci_device_id *pci_id) 277 { 278 struct device *dev = &pci->dev; 279 const struct sof_dev_desc *desc = 280 (const struct sof_dev_desc *)pci_id->driver_data; 281 struct snd_sof_pdata *sof_pdata; 282 const struct snd_sof_dsp_ops *ops; 283 int ret; 284 285 ret = snd_intel_dsp_driver_probe(pci); 286 if (ret != SND_INTEL_DSP_DRIVER_ANY && 287 ret != SND_INTEL_DSP_DRIVER_SOF) 288 return -ENODEV; 289 290 dev_dbg(&pci->dev, "PCI DSP detected"); 291 292 /* get ops for platform */ 293 ops = desc->ops; 294 if (!ops) { 295 dev_err(dev, "error: no matching PCI descriptor ops\n"); 296 return -ENODEV; 297 } 298 299 sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); 300 if (!sof_pdata) 301 return -ENOMEM; 302 303 ret = pcim_enable_device(pci); 304 if (ret < 0) 305 return ret; 306 307 ret = pci_request_regions(pci, "Audio DSP"); 308 if (ret < 0) 309 return ret; 310 311 sof_pdata->name = pci_name(pci); 312 sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data; 313 sof_pdata->dev = dev; 314 sof_pdata->fw_filename = desc->default_fw_filename; 315 316 /* 317 * for platforms using the SOF community key, change the 318 * default path automatically to pick the right files from the 319 * linux-firmware tree. This can be overridden with the 320 * fw_path kernel parameter, e.g. for developers. 321 */ 322 323 /* alternate fw and tplg filenames ? */ 324 if (fw_path) { 325 sof_pdata->fw_filename_prefix = fw_path; 326 327 dev_dbg(dev, 328 "Module parameter used, changed fw path to %s\n", 329 sof_pdata->fw_filename_prefix); 330 331 } else if (dmi_check_system(community_key_platforms)) { 332 sof_pdata->fw_filename_prefix = 333 devm_kasprintf(dev, GFP_KERNEL, "%s/%s", 334 sof_pdata->desc->default_fw_path, 335 "community"); 336 337 dev_dbg(dev, 338 "Platform uses community key, changed fw path to %s\n", 339 sof_pdata->fw_filename_prefix); 340 } else { 341 sof_pdata->fw_filename_prefix = 342 sof_pdata->desc->default_fw_path; 343 } 344 345 if (tplg_path) 346 sof_pdata->tplg_filename_prefix = tplg_path; 347 else 348 sof_pdata->tplg_filename_prefix = 349 sof_pdata->desc->default_tplg_path; 350 351 #if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 352 /* set callback to enable runtime_pm */ 353 sof_pdata->sof_probe_complete = sof_pci_probe_complete; 354 #endif 355 /* call sof helper for DSP hardware probe */ 356 ret = snd_sof_device_probe(dev, sof_pdata); 357 if (ret) { 358 dev_err(dev, "error: failed to probe DSP hardware!\n"); 359 goto release_regions; 360 } 361 362 #if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) 363 sof_pci_probe_complete(dev); 364 #endif 365 366 return ret; 367 368 release_regions: 369 pci_release_regions(pci); 370 371 return ret; 372 } 373 374 static void sof_pci_remove(struct pci_dev *pci) 375 { 376 /* call sof helper for DSP hardware remove */ 377 snd_sof_device_remove(&pci->dev); 378 379 /* follow recommendation in pci-driver.c to increment usage counter */ 380 if (!(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME)) 381 pm_runtime_get_noresume(&pci->dev); 382 383 /* release pci regions and disable device */ 384 pci_release_regions(pci); 385 } 386 387 /* PCI IDs */ 388 static const struct pci_device_id sof_pci_ids[] = { 389 #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) 390 { PCI_DEVICE(0x8086, 0x119a), 391 .driver_data = (unsigned long)&tng_desc}, 392 #endif 393 #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) 394 /* BXT-P & Apollolake */ 395 { PCI_DEVICE(0x8086, 0x5a98), 396 .driver_data = (unsigned long)&bxt_desc}, 397 { PCI_DEVICE(0x8086, 0x1a98), 398 .driver_data = (unsigned long)&bxt_desc}, 399 #endif 400 #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) 401 { PCI_DEVICE(0x8086, 0x3198), 402 .driver_data = (unsigned long)&glk_desc}, 403 #endif 404 #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) 405 { PCI_DEVICE(0x8086, 0x9dc8), 406 .driver_data = (unsigned long)&cnl_desc}, 407 #endif 408 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) 409 { PCI_DEVICE(0x8086, 0xa348), 410 .driver_data = (unsigned long)&cfl_desc}, 411 #endif 412 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) 413 { PCI_DEVICE(0x8086, 0x34C8), 414 .driver_data = (unsigned long)&icl_desc}, 415 #endif 416 #if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) 417 { PCI_DEVICE(0x8086, 0x38c8), 418 .driver_data = (unsigned long)&jsl_desc}, 419 #endif 420 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) 421 { PCI_DEVICE(0x8086, 0x02c8), 422 .driver_data = (unsigned long)&cml_desc}, 423 #endif 424 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) 425 { PCI_DEVICE(0x8086, 0x06c8), 426 .driver_data = (unsigned long)&cml_desc}, 427 #endif 428 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) 429 { PCI_DEVICE(0x8086, 0xa0c8), 430 .driver_data = (unsigned long)&tgl_desc}, 431 #endif 432 #if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) 433 { PCI_DEVICE(0x8086, 0x4b55), 434 .driver_data = (unsigned long)&ehl_desc}, 435 #endif 436 { 0, } 437 }; 438 MODULE_DEVICE_TABLE(pci, sof_pci_ids); 439 440 /* pci_driver definition */ 441 static struct pci_driver snd_sof_pci_driver = { 442 .name = "sof-audio-pci", 443 .id_table = sof_pci_ids, 444 .probe = sof_pci_probe, 445 .remove = sof_pci_remove, 446 .driver = { 447 .pm = &sof_pci_pm, 448 }, 449 }; 450 module_pci_driver(snd_sof_pci_driver); 451 452 MODULE_LICENSE("Dual BSD/GPL"); 453 MODULE_IMPORT_NS(SND_SOC_SOF_MERRIFIELD); 454 MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); 455