2020-05-01 09:58:50 -05:00
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2019-04-12 11:09:00 -05:00
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
// Copyright(c) 2018 Intel Corporation. All rights reserved.
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
//
# include <linux/firmware.h>
2020-01-07 10:08:39 -06:00
# include <linux/dmi.h>
2019-04-12 11:09:00 -05:00
# include <linux/module.h>
# include <linux/pci.h>
2022-04-21 11:33:55 -05:00
# include <linux/platform_data/x86/soc.h>
2019-04-12 11:09:00 -05:00
# include <linux/pm_runtime.h>
# include <sound/soc-acpi.h>
# include <sound/soc-acpi-intel-match.h>
# include <sound/sof.h>
# include "ops.h"
2021-03-01 18:31:21 -06:00
# include "sof-pci-dev.h"
2019-04-12 11:09:00 -05:00
static char * fw_path ;
module_param ( fw_path , charp , 0444 ) ;
MODULE_PARM_DESC ( fw_path , " alternate path for SOF firmware. " ) ;
2022-04-14 13:48:07 -05:00
static char * fw_filename ;
module_param ( fw_filename , charp , 0444 ) ;
MODULE_PARM_DESC ( fw_filename , " alternate filename for SOF firmware. " ) ;
2019-04-12 11:09:00 -05:00
static char * tplg_path ;
module_param ( tplg_path , charp , 0444 ) ;
MODULE_PARM_DESC ( tplg_path , " alternate path for SOF topology. " ) ;
2022-04-14 13:48:08 -05:00
static char * tplg_filename ;
module_param ( tplg_filename , charp , 0444 ) ;
MODULE_PARM_DESC ( tplg_filename , " alternate filename for SOF topology. " ) ;
2019-10-08 11:44:38 -05:00
static int sof_pci_debug ;
module_param_named ( sof_pci_debug , sof_pci_debug , int , 0444 ) ;
MODULE_PARM_DESC ( sof_pci_debug , " SOF PCI debug options (0x0 all off) " ) ;
2022-04-21 11:33:56 -05:00
static int sof_pci_ipc_type = - 1 ;
module_param_named ( ipc_type , sof_pci_ipc_type , int , 0444 ) ;
MODULE_PARM_DESC ( ipc_type , " SOF IPC type (0): SOF, (1) Intel CAVS " ) ;
2022-04-14 13:48:08 -05:00
static const char * sof_dmi_override_tplg_name ;
2022-04-21 11:33:55 -05:00
static bool sof_dmi_use_community_key ;
2020-08-21 14:56:00 -05:00
2019-10-08 11:44:38 -05:00
# define SOF_PCI_DISABLE_PM_RUNTIME BIT(0)
2020-08-21 14:56:00 -05:00
static int sof_tplg_cb ( const struct dmi_system_id * id )
{
2022-04-14 13:48:08 -05:00
sof_dmi_override_tplg_name = id - > driver_data ;
2020-08-21 14:56:00 -05:00
return 1 ;
}
static const struct dmi_system_id sof_tplg_table [ ] = {
{
. callback = sof_tplg_cb ,
. matches = {
DMI_MATCH ( DMI_PRODUCT_FAMILY , " Google_Volteer " ) ,
2020-09-10 19:27:05 +03:00
DMI_MATCH ( DMI_OEM_STRING , " AUDIO-MAX98373_ALC5682I_I2S_UP4 " ) ,
2020-08-21 14:56:00 -05:00
} ,
. driver_data = " sof-tgl-rt5682-ssp0-max98373-ssp2.tplg " ,
} ,
2021-08-02 10:21:49 -05:00
{
. callback = sof_tplg_cb ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Intel Corporation " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Alder Lake Client Platform " ) ,
DMI_MATCH ( DMI_OEM_STRING , " AUDIO-ADL_MAX98373_ALC5682I_I2S " ) ,
} ,
. driver_data = " sof-adl-rt5682-ssp0-max98373-ssp2.tplg " ,
} ,
2021-11-24 22:04:53 -05:00
{
. callback = sof_tplg_cb ,
. matches = {
DMI_MATCH ( DMI_PRODUCT_FAMILY , " Google_Brya " ) ,
DMI_MATCH ( DMI_OEM_STRING , " AUDIO-MAX98390_ALC5682I_I2S " ) ,
} ,
. driver_data = " sof-adl-max98390-ssp2-rt5682-ssp0.tplg " ,
} ,
2022-02-18 16:27:41 +08:00
{
. callback = sof_tplg_cb ,
. matches = {
DMI_MATCH ( DMI_PRODUCT_FAMILY , " Google_Brya " ) ,
DMI_MATCH ( DMI_OEM_STRING , " AUDIO_AMP-MAX98360_ALC5682VS_I2S_2WAY " ) ,
} ,
. driver_data = " sof-adl-max98360a-rt5682-2way.tplg " ,
} ,
2022-03-10 11:16:50 -06:00
{
. callback = sof_tplg_cb ,
. matches = {
DMI_MATCH ( DMI_PRODUCT_FAMILY , " Google_Brya " ) ,
DMI_MATCH ( DMI_OEM_STRING , " AUDIO-AUDIO_MAX98357_ALC5682I_I2S_2WAY " ) ,
} ,
. driver_data = " sof-adl-max98357a-rt5682-2way.tplg " ,
} ,
2022-03-24 16:47:08 +08:00
{
. callback = sof_tplg_cb ,
. matches = {
DMI_MATCH ( DMI_PRODUCT_FAMILY , " Google_Brya " ) ,
DMI_MATCH ( DMI_OEM_STRING , " AUDIO-MAX98360_ALC5682I_I2S_AMP_SSP2 " ) ,
} ,
. driver_data = " sof-adl-max98357a-rt5682.tplg " ,
} ,
2020-08-21 14:56:00 -05:00
{ }
} ;
2022-04-21 11:33:55 -05:00
/* all Up boards use the community key */
static int up_use_community_key ( const struct dmi_system_id * id )
{
sof_dmi_use_community_key = true ;
return 1 ;
}
/*
* For ApolloLake Chromebooks we want to force the use of the Intel production key .
* All newer platforms use the community key
*/
static int chromebook_use_community_key ( const struct dmi_system_id * id )
{
if ( ! soc_intel_is_apl ( ) )
sof_dmi_use_community_key = true ;
return 1 ;
}
2020-01-07 10:08:39 -06:00
static const struct dmi_system_id community_key_platforms [ ] = {
{
2021-11-19 17:13:27 -06:00
. ident = " Up boards " ,
2022-04-21 11:33:55 -05:00
. callback = up_use_community_key ,
2020-01-07 10:08:39 -06:00
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " AAEON " ) ,
2021-02-08 17:18:53 -06:00
}
} ,
2020-01-07 10:08:39 -06:00
{
. ident = " Google Chromebooks " ,
2022-04-21 11:33:55 -05:00
. callback = chromebook_use_community_key ,
2020-01-07 10:08:39 -06:00
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Google " ) ,
}
} ,
{ } ,
} ;
2021-03-01 18:31:21 -06:00
const struct dev_pm_ops sof_pci_pm = {
2019-10-25 17:41:22 -05:00
. prepare = snd_sof_prepare ,
. complete = snd_sof_complete ,
2019-04-12 11:09:00 -05:00
SET_SYSTEM_SLEEP_PM_OPS ( snd_sof_suspend , snd_sof_resume )
SET_RUNTIME_PM_OPS ( snd_sof_runtime_suspend , snd_sof_runtime_resume ,
2019-07-02 16:24:27 +03:00
snd_sof_runtime_idle )
2019-04-12 11:09:00 -05:00
} ;
2021-03-01 18:31:21 -06:00
EXPORT_SYMBOL_NS ( sof_pci_pm , SND_SOC_SOF_PCI_DEV ) ;
2019-04-12 11:09:00 -05:00
static void sof_pci_probe_complete ( struct device * dev )
{
dev_dbg ( dev , " Completing SOF PCI probe " ) ;
2019-10-08 11:44:38 -05:00
if ( sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME )
return ;
2019-04-12 11:09:00 -05:00
/* allow runtime_pm */
pm_runtime_set_autosuspend_delay ( dev , SND_SOF_SUSPEND_DELAY_MS ) ;
pm_runtime_use_autosuspend ( dev ) ;
/*
* runtime pm for pci device is " forbidden " by default .
* so call pm_runtime_allow ( ) to enable it .
*/
pm_runtime_allow ( dev ) ;
2019-07-22 09:13:42 -05:00
/* mark last_busy for pm_runtime to make sure not suspend immediately */
pm_runtime_mark_last_busy ( dev ) ;
2019-04-12 11:09:00 -05:00
/* follow recommendation in pci-driver.c to decrement usage counter */
pm_runtime_put_noidle ( dev ) ;
}
2021-03-01 18:31:21 -06:00
int sof_pci_probe ( struct pci_dev * pci , const struct pci_device_id * pci_id )
2019-04-12 11:09:00 -05:00
{
struct device * dev = & pci - > dev ;
const struct sof_dev_desc * desc =
( const struct sof_dev_desc * ) pci_id - > driver_data ;
struct snd_sof_pdata * sof_pdata ;
int ret ;
dev_dbg ( & pci - > dev , " PCI DSP detected " ) ;
2022-04-26 13:33:57 -05:00
if ( ! desc ) {
dev_err ( dev , " error: no matching PCI descriptor \n " ) ;
return - ENODEV ;
}
2021-05-21 12:27:58 +03:00
if ( ! desc - > ops ) {
2019-04-12 11:09:00 -05:00
dev_err ( dev , " error: no matching PCI descriptor ops \n " ) ;
return - ENODEV ;
}
sof_pdata = devm_kzalloc ( dev , sizeof ( * sof_pdata ) , GFP_KERNEL ) ;
if ( ! sof_pdata )
return - ENOMEM ;
ret = pcim_enable_device ( pci ) ;
if ( ret < 0 )
return ret ;
ret = pci_request_regions ( pci , " Audio DSP " ) ;
if ( ret < 0 )
return ret ;
sof_pdata - > name = pci_name ( pci ) ;
2021-05-21 12:27:59 +03:00
sof_pdata - > desc = desc ;
2019-04-12 11:09:00 -05:00
sof_pdata - > dev = dev ;
2022-04-14 13:48:06 -05:00
sof_pdata - > ipc_type = desc - > ipc_default ;
2022-04-14 13:48:07 -05:00
2022-04-21 11:33:56 -05:00
if ( sof_pci_ipc_type < 0 ) {
sof_pdata - > ipc_type = desc - > ipc_default ;
} else {
dev_info ( dev , " overriding default IPC %d to requested %d \n " ,
desc - > ipc_default , sof_pci_ipc_type ) ;
if ( sof_pci_ipc_type > = SOF_IPC_TYPE_COUNT ) {
dev_err ( dev , " invalid request value %d \n " , sof_pci_ipc_type ) ;
2022-04-26 21:25:39 +08:00
ret = - EINVAL ;
goto out ;
2022-04-21 11:33:56 -05:00
}
if ( ! ( BIT ( sof_pci_ipc_type ) & desc - > ipc_supported_mask ) ) {
dev_err ( dev , " invalid request value %d, supported mask is %#x \n " ,
sof_pci_ipc_type , desc - > ipc_supported_mask ) ;
2022-04-26 21:25:39 +08:00
ret = - EINVAL ;
goto out ;
2022-04-21 11:33:56 -05:00
}
sof_pdata - > ipc_type = sof_pci_ipc_type ;
}
2022-04-14 13:48:07 -05:00
if ( fw_filename ) {
sof_pdata - > fw_filename = fw_filename ;
dev_dbg ( dev , " Module parameter used, changed fw filename to %s \n " ,
sof_pdata - > fw_filename ) ;
} else {
sof_pdata - > fw_filename = desc - > default_fw_filename [ sof_pdata - > ipc_type ] ;
}
2019-04-12 11:09:00 -05:00
2020-01-07 10:08:39 -06:00
/*
* for platforms using the SOF community key , change the
* default path automatically to pick the right files from the
* linux - firmware tree . This can be overridden with the
* fw_path kernel parameter , e . g . for developers .
*/
2019-04-12 11:09:00 -05:00
/* alternate fw and tplg filenames ? */
2020-01-07 10:08:39 -06:00
if ( fw_path ) {
2019-04-12 11:09:00 -05:00
sof_pdata - > fw_filename_prefix = fw_path ;
2020-01-07 10:08:39 -06:00
dev_dbg ( dev ,
" Module parameter used, changed fw path to %s \n " ,
sof_pdata - > fw_filename_prefix ) ;
2022-04-21 11:33:55 -05:00
} else if ( dmi_check_system ( community_key_platforms ) & & sof_dmi_use_community_key ) {
2020-01-07 10:08:39 -06:00
sof_pdata - > fw_filename_prefix =
devm_kasprintf ( dev , GFP_KERNEL , " %s/%s " ,
2022-04-14 13:48:06 -05:00
sof_pdata - > desc - > default_fw_path [ sof_pdata - > ipc_type ] ,
2020-01-07 10:08:39 -06:00
" community " ) ;
dev_dbg ( dev ,
" Platform uses community key, changed fw path to %s \n " ,
sof_pdata - > fw_filename_prefix ) ;
} else {
2019-04-12 11:09:00 -05:00
sof_pdata - > fw_filename_prefix =
2022-04-14 13:48:06 -05:00
sof_pdata - > desc - > default_fw_path [ sof_pdata - > ipc_type ] ;
2020-01-07 10:08:39 -06:00
}
2019-04-12 11:09:00 -05:00
if ( tplg_path )
sof_pdata - > tplg_filename_prefix = tplg_path ;
else
sof_pdata - > tplg_filename_prefix =
2022-04-14 13:48:06 -05:00
sof_pdata - > desc - > default_tplg_path [ sof_pdata - > ipc_type ] ;
2019-04-12 11:09:00 -05:00
2022-04-14 13:48:08 -05:00
/*
* the topology filename will be provided in the machine descriptor , unless
* it is overridden by a module parameter or DMI quirk .
*/
if ( tplg_filename ) {
sof_pdata - > tplg_filename = tplg_filename ;
dev_dbg ( dev , " Module parameter used, changed tplg filename to %s \n " ,
sof_pdata - > tplg_filename ) ;
} else {
dmi_check_system ( sof_tplg_table ) ;
if ( sof_dmi_override_tplg_name )
sof_pdata - > tplg_filename = sof_dmi_override_tplg_name ;
}
2020-08-21 14:56:00 -05:00
2021-04-09 15:09:59 -07:00
/* set callback to be called on successful device probe to enable runtime_pm */
2019-04-12 11:09:00 -05:00
sof_pdata - > sof_probe_complete = sof_pci_probe_complete ;
2021-04-09 15:09:59 -07:00
2019-04-12 11:09:00 -05:00
/* call sof helper for DSP hardware probe */
ret = snd_sof_device_probe ( dev , sof_pdata ) ;
2022-04-26 21:25:39 +08:00
out :
2021-04-09 15:09:59 -07:00
if ( ret )
pci_release_regions ( pci ) ;
2019-04-12 11:09:00 -05:00
return ret ;
}
2021-03-01 18:31:21 -06:00
EXPORT_SYMBOL_NS ( sof_pci_probe , SND_SOC_SOF_PCI_DEV ) ;
2019-04-12 11:09:00 -05:00
2021-03-01 18:31:21 -06:00
void sof_pci_remove ( struct pci_dev * pci )
2019-04-12 11:09:00 -05:00
{
/* call sof helper for DSP hardware remove */
snd_sof_device_remove ( & pci - > dev ) ;
/* follow recommendation in pci-driver.c to increment usage counter */
2021-02-10 12:52:37 +02:00
if ( snd_sof_device_probe_completed ( & pci - > dev ) & &
! ( sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME ) )
2019-10-08 11:44:38 -05:00
pm_runtime_get_noresume ( & pci - > dev ) ;
2019-04-12 11:09:00 -05:00
/* release pci regions and disable device */
pci_release_regions ( pci ) ;
}
2021-03-01 18:31:21 -06:00
EXPORT_SYMBOL_NS ( sof_pci_remove , SND_SOC_SOF_PCI_DEV ) ;
2019-04-12 11:09:00 -05:00
2021-03-01 18:31:21 -06:00
void sof_pci_shutdown ( struct pci_dev * pci )
2021-01-13 17:26:16 +02:00
{
snd_sof_device_shutdown ( & pci - > dev ) ;
}
2021-03-01 18:31:21 -06:00
EXPORT_SYMBOL_NS ( sof_pci_shutdown , SND_SOC_SOF_PCI_DEV ) ;
2019-04-12 11:09:00 -05:00
MODULE_LICENSE ( " Dual BSD/GPL " ) ;