2019-10-22 20:43:12 +03:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Jaroslav Kysela <perex@perex.cz>
2020-04-09 22:02:51 +03:00
# include <linux/acpi.h>
2019-10-22 20:43:12 +03:00
# include <linux/bits.h>
# include <linux/dmi.h>
# include <linux/module.h>
# include <linux/pci.h>
2020-04-09 22:02:51 +03:00
# include <linux/soundwire/sdw.h>
# include <linux/soundwire/sdw_intel.h>
2019-10-22 20:43:12 +03:00
# include <sound/core.h>
# include <sound/intel-dsp-config.h>
# include <sound/intel-nhlt.h>
static int dsp_driver ;
module_param ( dsp_driver , int , 0444 ) ;
MODULE_PARM_DESC ( dsp_driver , " Force the DSP driver for Intel DSP (0=auto, 1=legacy, 2=SST, 3=SOF) " ) ;
2020-04-09 22:02:51 +03:00
# define FLAG_SST BIT(0)
# define FLAG_SOF BIT(1)
2020-05-06 23:39:51 +03:00
# define FLAG_SST_ONLY_IF_DMIC BIT(15)
2020-04-09 22:02:51 +03:00
# define FLAG_SOF_ONLY_IF_DMIC BIT(16)
# define FLAG_SOF_ONLY_IF_SOUNDWIRE BIT(17)
# define FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE (FLAG_SOF_ONLY_IF_DMIC | \
FLAG_SOF_ONLY_IF_SOUNDWIRE )
2019-10-22 20:43:12 +03:00
struct config_entry {
u32 flags ;
u16 device ;
2020-11-13 01:38:14 +03:00
u8 acpi_hid [ ACPI_ID_LEN ] ;
2019-10-22 20:43:12 +03:00
const struct dmi_system_id * dmi_table ;
} ;
/*
* configuration table
* - the order of similar PCI ID entries is important !
* - the first successful match will win
*/
static const struct config_entry config_table [ ] = {
2019-10-22 20:43:13 +03:00
/* Merrifield */
# if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD)
2019-10-22 20:43:12 +03:00
{
2019-10-22 20:43:13 +03:00
. flags = FLAG_SOF ,
. device = 0x119a ,
2019-10-22 20:43:12 +03:00
} ,
2019-10-22 20:43:13 +03:00
# endif
/* Broxton-T */
# if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
2019-10-22 20:43:12 +03:00
{
. flags = FLAG_SOF ,
2019-10-22 20:43:13 +03:00
. device = 0x1a98 ,
2019-10-22 20:43:12 +03:00
} ,
# endif
2019-10-22 20:43:13 +03:00
/*
* Apollolake ( Broxton - P )
2020-09-02 18:42:50 +03:00
* the legacy HDAudio driver is used except on Up Squared ( SOF ) and
2019-10-22 20:43:13 +03:00
* Chromebooks ( SST )
*/
# if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
2019-10-22 20:43:12 +03:00
{
2019-10-22 20:43:13 +03:00
. flags = FLAG_SOF ,
. device = 0x5a98 ,
. dmi_table = ( const struct dmi_system_id [ ] ) {
{
. ident = " Up Squared " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " AAEON " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " UP-APL01 " ) ,
}
} ,
{ }
}
2019-10-22 20:43:12 +03:00
} ,
2019-10-22 20:43:13 +03:00
# endif
# if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL)
2019-10-22 20:43:12 +03:00
{
2019-10-22 20:43:13 +03:00
. flags = FLAG_SST ,
. device = 0x5a98 ,
. dmi_table = ( const struct dmi_system_id [ ] ) {
{
. ident = " Google Chromebooks " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Google " ) ,
}
} ,
{ }
}
2019-10-22 20:43:12 +03:00
} ,
# endif
2019-10-22 20:43:13 +03:00
/*
2020-09-02 18:42:50 +03:00
* Skylake and Kabylake use legacy HDAudio driver except for Google
2019-10-22 20:43:13 +03:00
* Chromebooks ( SST )
*/
/* Sunrise Point-LP */
# if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL)
2019-10-22 20:43:12 +03:00
{
2019-10-22 20:43:13 +03:00
. flags = FLAG_SST ,
. device = 0x9d70 ,
. dmi_table = ( const struct dmi_system_id [ ] ) {
{
. ident = " Google Chromebooks " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Google " ) ,
}
} ,
{ }
}
2019-10-22 20:43:12 +03:00
} ,
2020-05-06 23:39:51 +03:00
{
. flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC ,
. device = 0x9d70 ,
} ,
2019-10-22 20:43:12 +03:00
# endif
2019-10-22 20:43:13 +03:00
/* Kabylake-LP */
# if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL)
2019-10-22 20:43:12 +03:00
{
2019-10-22 20:43:13 +03:00
. flags = FLAG_SST ,
. device = 0x9d71 ,
. dmi_table = ( const struct dmi_system_id [ ] ) {
{
. ident = " Google Chromebooks " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Google " ) ,
}
} ,
{ }
}
2019-10-22 20:43:12 +03:00
} ,
2020-05-06 23:39:51 +03:00
{
. flags = FLAG_SST | FLAG_SST_ONLY_IF_DMIC ,
. device = 0x9d71 ,
} ,
2019-10-22 20:43:12 +03:00
# endif
2019-10-22 20:43:13 +03:00
/*
2020-09-02 18:42:50 +03:00
* Geminilake uses legacy HDAudio driver except for Google
2019-10-22 20:43:13 +03:00
* Chromebooks
*/
2019-10-22 20:43:12 +03:00
/* Geminilake */
# if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE)
{
. flags = FLAG_SOF ,
. device = 0x3198 ,
. dmi_table = ( const struct dmi_system_id [ ] ) {
{
. ident = " Google Chromebooks " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Google " ) ,
}
} ,
{ }
}
} ,
# endif
2019-10-22 20:43:13 +03:00
/*
* CoffeeLake , CannonLake , CometLake , IceLake , TigerLake use legacy
2020-09-02 18:42:50 +03:00
* HDAudio driver except for Google Chromebooks and when DMICs are
2019-10-22 20:43:13 +03:00
* present . Two cases are required since Coreboot does not expose NHLT
* tables .
*
* When the Chromebook quirk is not present , it ' s based on information
* that no such device exists . When the quirk is present , it could be
* either based on product information or a placeholder .
*/
/* Cannonlake */
# if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE)
2019-10-22 20:43:12 +03:00
{
2019-10-22 20:43:13 +03:00
. flags = FLAG_SOF ,
. device = 0x9dc8 ,
. dmi_table = ( const struct dmi_system_id [ ] ) {
{
. ident = " Google Chromebooks " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Google " ) ,
}
} ,
{ }
}
2019-10-22 20:43:12 +03:00
} ,
{
2020-04-09 22:02:51 +03:00
. flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE ,
2019-10-22 20:43:13 +03:00
. device = 0x9dc8 ,
2019-10-22 20:43:12 +03:00
} ,
# endif
2019-10-22 20:43:13 +03:00
/* Coffelake */
# if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE)
{
. flags = FLAG_SOF ,
. device = 0xa348 ,
. dmi_table = ( const struct dmi_system_id [ ] ) {
{
. ident = " Google Chromebooks " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Google " ) ,
}
} ,
{ }
}
} ,
2019-10-22 20:43:12 +03:00
{
2020-04-09 22:02:51 +03:00
. flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE ,
2019-10-22 20:43:13 +03:00
. device = 0xa348 ,
2019-10-22 20:43:12 +03:00
} ,
# endif
2019-10-22 20:43:13 +03:00
2020-06-17 19:47:53 +03:00
# if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE)
2019-10-22 20:43:13 +03:00
/* Cometlake-LP */
2019-10-22 20:43:12 +03:00
{
. flags = FLAG_SOF ,
2019-10-22 20:43:13 +03:00
. device = 0x02c8 ,
2019-10-22 20:43:12 +03:00
. dmi_table = ( const struct dmi_system_id [ ] ) {
{
2019-10-22 20:43:13 +03:00
. ident = " Google Chromebooks " ,
2019-10-22 20:43:12 +03:00
. matches = {
2019-10-22 20:43:13 +03:00
DMI_MATCH ( DMI_SYS_VENDOR , " Google " ) ,
2019-10-22 20:43:12 +03:00
}
} ,
2020-04-09 22:02:51 +03:00
{
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Inc " ) ,
DMI_EXACT_MATCH ( DMI_PRODUCT_SKU , " 09C6 " )
} ,
} ,
{
/* early version of SKU 09C6 */
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Inc " ) ,
DMI_EXACT_MATCH ( DMI_PRODUCT_SKU , " 0983 " )
} ,
} ,
2019-10-22 20:43:12 +03:00
{ }
}
} ,
{
2020-04-09 22:02:51 +03:00
. flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE ,
2019-10-22 20:43:13 +03:00
. device = 0x02c8 ,
2019-10-22 20:43:12 +03:00
} ,
2019-10-22 20:43:13 +03:00
/* Cometlake-H */
2019-10-22 20:43:12 +03:00
{
2020-04-09 22:02:51 +03:00
. flags = FLAG_SOF ,
. device = 0x06c8 ,
. dmi_table = ( const struct dmi_system_id [ ] ) {
{
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Inc " ) ,
DMI_EXACT_MATCH ( DMI_PRODUCT_SKU , " 098F " ) ,
} ,
} ,
{
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Dell Inc " ) ,
DMI_EXACT_MATCH ( DMI_PRODUCT_SKU , " 0990 " ) ,
} ,
} ,
{ }
}
} ,
{
. flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE ,
2019-10-22 20:43:13 +03:00
. device = 0x06c8 ,
2019-10-22 20:43:12 +03:00
} ,
# endif
2019-10-22 20:43:13 +03:00
/* Icelake */
# if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE)
2019-10-22 20:43:12 +03:00
{
2019-10-22 20:43:13 +03:00
. flags = FLAG_SOF ,
. device = 0x34c8 ,
. dmi_table = ( const struct dmi_system_id [ ] ) {
{
. ident = " Google Chromebooks " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Google " ) ,
}
} ,
{ }
}
2019-10-22 20:43:12 +03:00
} ,
{
2020-04-09 22:02:51 +03:00
. flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE ,
2019-10-22 20:43:13 +03:00
. device = 0x34c8 ,
2019-10-22 20:43:12 +03:00
} ,
# endif
2019-10-22 20:43:13 +03:00
2019-10-22 20:43:12 +03:00
/* Tigerlake */
# if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
2019-10-22 20:43:13 +03:00
{
. flags = FLAG_SOF ,
. device = 0xa0c8 ,
. dmi_table = ( const struct dmi_system_id [ ] ) {
{
. ident = " Google Chromebooks " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Google " ) ,
}
} ,
{ }
}
} ,
2019-10-22 20:43:12 +03:00
{
2020-04-09 22:02:51 +03:00
. flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE ,
2019-10-22 20:43:12 +03:00
. device = 0xa0c8 ,
} ,
2021-01-25 11:30:51 +03:00
{
. flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE ,
. device = 0x43c8 ,
} ,
2019-10-22 20:43:12 +03:00
# endif
2019-10-22 20:43:13 +03:00
/* Elkhart Lake */
# if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE)
2019-10-22 20:43:12 +03:00
{
. flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC ,
2019-10-22 20:43:13 +03:00
. device = 0x4b55 ,
2019-10-22 20:43:12 +03:00
} ,
# endif
2019-10-22 20:43:13 +03:00
2021-02-10 14:13:10 +03:00
/* Alder Lake */
# if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE)
{
. flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE ,
. device = 0x7ad0 ,
} ,
{
. flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE ,
. device = 0x51c8 ,
} ,
# endif
2019-10-22 20:43:12 +03:00
} ;
static const struct config_entry * snd_intel_dsp_find_config
( struct pci_dev * pci , const struct config_entry * table , u32 len )
{
u16 device ;
device = pci - > device ;
for ( ; len > 0 ; len - - , table + + ) {
if ( table - > device ! = device )
continue ;
if ( table - > dmi_table & & ! dmi_check_system ( table - > dmi_table ) )
continue ;
return table ;
}
return NULL ;
}
static int snd_intel_dsp_check_dmic ( struct pci_dev * pci )
{
struct nhlt_acpi_table * nhlt ;
int ret = 0 ;
nhlt = intel_nhlt_init ( & pci - > dev ) ;
if ( nhlt ) {
if ( intel_nhlt_get_dmic_geo ( & pci - > dev , nhlt ) )
ret = 1 ;
intel_nhlt_free ( nhlt ) ;
}
return ret ;
}
2020-04-09 22:02:51 +03:00
# if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
static int snd_intel_dsp_check_soundwire ( struct pci_dev * pci )
{
struct sdw_intel_acpi_info info ;
acpi_handle handle ;
int ret ;
handle = ACPI_HANDLE ( & pci - > dev ) ;
ret = sdw_intel_acpi_scan ( handle , & info ) ;
if ( ret < 0 )
return ret ;
return info . link_mask ;
}
# else
static int snd_intel_dsp_check_soundwire ( struct pci_dev * pci )
{
return 0 ;
}
# endif
2019-10-22 20:43:12 +03:00
int snd_intel_dsp_driver_probe ( struct pci_dev * pci )
{
const struct config_entry * cfg ;
/* Intel vendor only */
2019-10-28 16:06:34 +03:00
if ( pci - > vendor ! = 0x8086 )
2019-10-22 20:43:12 +03:00
return SND_INTEL_DSP_DRIVER_ANY ;
2020-11-13 01:38:25 +03:00
/*
* Legacy devices don ' t have a PCI - based DSP and use HDaudio
* for HDMI / DP support , ignore kernel parameter
*/
switch ( pci - > device ) {
case 0x160c : /* Broadwell */
case 0x0a0c : /* Haswell */
case 0x0c0c :
case 0x0d0c :
case 0x0f04 : /* Baytrail */
case 0x2284 : /* Braswell */
return SND_INTEL_DSP_DRIVER_ANY ;
}
2019-10-28 16:06:34 +03:00
if ( dsp_driver > 0 & & dsp_driver < = SND_INTEL_DSP_DRIVER_LAST )
return dsp_driver ;
2019-10-22 20:43:12 +03:00
/*
* detect DSP by checking class / subclass / prog - id information
* class = 04 subclass 03 prog - if 00 : no DSP , use legacy driver
* class = 04 subclass 01 prog - if 00 : DSP is present
* ( and may be required e . g . for DMIC or SSP support )
* class = 04 subclass 03 prog - if 80 : use DSP or legacy mode
*/
if ( pci - > class = = 0x040300 )
return SND_INTEL_DSP_DRIVER_LEGACY ;
if ( pci - > class ! = 0x040100 & & pci - > class ! = 0x040380 ) {
2020-09-02 18:42:50 +03:00
dev_err ( & pci - > dev , " Unknown PCI class/subclass/prog-if information (0x%06x) found, selecting HDAudio legacy driver \n " , pci - > class ) ;
2019-10-22 20:43:12 +03:00
return SND_INTEL_DSP_DRIVER_LEGACY ;
}
dev_info ( & pci - > dev , " DSP detected with PCI class/subclass/prog-if info 0x%06x \n " , pci - > class ) ;
/* find the configuration for the specific device */
cfg = snd_intel_dsp_find_config ( pci , config_table , ARRAY_SIZE ( config_table ) ) ;
if ( ! cfg )
return SND_INTEL_DSP_DRIVER_ANY ;
if ( cfg - > flags & FLAG_SOF ) {
2020-04-09 22:02:51 +03:00
if ( cfg - > flags & FLAG_SOF_ONLY_IF_SOUNDWIRE & &
snd_intel_dsp_check_soundwire ( pci ) > 0 ) {
dev_info ( & pci - > dev , " SoundWire enabled on CannonLake+ platform, using SOF driver \n " ) ;
return SND_INTEL_DSP_DRIVER_SOF ;
}
if ( cfg - > flags & FLAG_SOF_ONLY_IF_DMIC & &
snd_intel_dsp_check_dmic ( pci ) ) {
dev_info ( & pci - > dev , " Digital mics found on Skylake+ platform, using SOF driver \n " ) ;
2019-10-22 20:43:12 +03:00
return SND_INTEL_DSP_DRIVER_SOF ;
}
2020-04-09 22:02:51 +03:00
if ( ! ( cfg - > flags & FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE ) )
return SND_INTEL_DSP_DRIVER_SOF ;
2019-10-22 20:43:12 +03:00
}
2020-05-06 23:39:51 +03:00
if ( cfg - > flags & FLAG_SST ) {
if ( cfg - > flags & FLAG_SST_ONLY_IF_DMIC ) {
if ( snd_intel_dsp_check_dmic ( pci ) ) {
dev_info ( & pci - > dev , " Digital mics found on Skylake+ platform, using SST driver \n " ) ;
return SND_INTEL_DSP_DRIVER_SST ;
}
} else {
return SND_INTEL_DSP_DRIVER_SST ;
}
}
2019-10-22 20:43:12 +03:00
return SND_INTEL_DSP_DRIVER_LEGACY ;
}
EXPORT_SYMBOL_GPL ( snd_intel_dsp_driver_probe ) ;
2021-02-08 16:59:19 +03:00
/* Should we default to SOF or SST for BYT/CHT ? */
# if IS_ENABLED(CONFIG_SND_INTEL_BYT_PREFER_SOF) || \
! IS_ENABLED ( CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI )
# define FLAG_SST_OR_SOF_BYT FLAG_SOF
# else
# define FLAG_SST_OR_SOF_BYT FLAG_SST
# endif
2020-11-13 01:38:14 +03:00
/*
* configuration table
* - the order of similar ACPI ID entries is important !
* - the first successful match will win
*/
static const struct config_entry acpi_config_table [ ] = {
2021-02-08 16:59:19 +03:00
# if IS_ENABLED(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI) || \
IS_ENABLED ( CONFIG_SND_SOC_SOF_BAYTRAIL )
2020-11-13 01:38:14 +03:00
/* BayTrail */
{
2021-02-08 16:59:19 +03:00
. flags = FLAG_SST_OR_SOF_BYT ,
2020-11-13 01:38:14 +03:00
. acpi_hid = " 80860F28 " ,
} ,
/* CherryTrail */
{
2021-02-08 16:59:19 +03:00
. flags = FLAG_SST_OR_SOF_BYT ,
2020-11-13 01:38:14 +03:00
. acpi_hid = " 808622A8 " ,
} ,
# endif
2020-11-13 01:38:21 +03:00
/* Broadwell */
# if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
{
. flags = FLAG_SST ,
. acpi_hid = " INT3438 "
} ,
# endif
# if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL)
{
. flags = FLAG_SOF ,
. acpi_hid = " INT3438 "
} ,
# endif
/* Haswell - not supported by SOF but added for consistency */
# if IS_ENABLED(CONFIG_SND_SOC_INTEL_CATPT)
{
. flags = FLAG_SST ,
. acpi_hid = " INT33C8 "
} ,
# endif
2020-11-13 01:38:14 +03:00
} ;
static const struct config_entry * snd_intel_acpi_dsp_find_config ( const u8 acpi_hid [ ACPI_ID_LEN ] ,
const struct config_entry * table ,
u32 len )
{
for ( ; len > 0 ; len - - , table + + ) {
if ( memcmp ( table - > acpi_hid , acpi_hid , ACPI_ID_LEN ) )
continue ;
if ( table - > dmi_table & & ! dmi_check_system ( table - > dmi_table ) )
continue ;
return table ;
}
return NULL ;
}
int snd_intel_acpi_dsp_driver_probe ( struct device * dev , const u8 acpi_hid [ ACPI_ID_LEN ] )
{
const struct config_entry * cfg ;
if ( dsp_driver > SND_INTEL_DSP_DRIVER_LEGACY & & dsp_driver < = SND_INTEL_DSP_DRIVER_LAST )
return dsp_driver ;
if ( dsp_driver = = SND_INTEL_DSP_DRIVER_LEGACY ) {
dev_warn ( dev , " dsp_driver parameter %d not supported, using automatic detection \n " ,
SND_INTEL_DSP_DRIVER_LEGACY ) ;
}
/* find the configuration for the specific device */
cfg = snd_intel_acpi_dsp_find_config ( acpi_hid , acpi_config_table ,
ARRAY_SIZE ( acpi_config_table ) ) ;
if ( ! cfg )
return SND_INTEL_DSP_DRIVER_ANY ;
if ( cfg - > flags & FLAG_SST )
return SND_INTEL_DSP_DRIVER_SST ;
if ( cfg - > flags & FLAG_SOF )
return SND_INTEL_DSP_DRIVER_SOF ;
return SND_INTEL_DSP_DRIVER_SST ;
}
EXPORT_SYMBOL_GPL ( snd_intel_acpi_dsp_driver_probe ) ;
2019-10-22 20:43:12 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " Intel DSP config driver " ) ;
2021-03-02 03:31:24 +03:00
MODULE_IMPORT_NS ( SND_INTEL_SOUNDWIRE_ACPI ) ;