2021-03-02 03:31:24 +03:00
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
// Copyright(c) 2015-2021 Intel Corporation.
/*
* SDW Intel ACPI scan helpers
*/
# include <linux/acpi.h>
2021-03-02 03:31:25 +03:00
# include <linux/bits.h>
# include <linux/bitfield.h>
# include <linux/device.h>
# include <linux/errno.h>
2021-03-02 03:31:24 +03:00
# include <linux/export.h>
2021-03-02 03:31:25 +03:00
# include <linux/fwnode.h>
2021-03-02 03:31:24 +03:00
# include <linux/module.h>
# include <linux/soundwire/sdw_intel.h>
# include <linux/string.h>
# define SDW_LINK_TYPE 4 /* from Intel ACPI documentation */
# define SDW_MAX_LINKS 4
static int ctrl_link_mask ;
module_param_named ( sdw_link_mask , ctrl_link_mask , int , 0444 ) ;
MODULE_PARM_DESC ( sdw_link_mask , " Intel link mask (one bit per link) " ) ;
2023-09-12 19:26:17 +03:00
static bool is_link_enabled ( struct fwnode_handle * fw_node , u8 idx )
2021-03-02 03:31:24 +03:00
{
struct fwnode_handle * link ;
char name [ 32 ] ;
u32 quirk_mask = 0 ;
/* Find master handle */
snprintf ( name , sizeof ( name ) ,
2023-09-12 19:26:17 +03:00
" mipi-sdw-link-%hhu-subproperties " , idx ) ;
2021-03-02 03:31:24 +03:00
link = fwnode_get_named_child_node ( fw_node , name ) ;
if ( ! link )
return false ;
fwnode_property_read_u32 ( link ,
" intel-quirk-mask " ,
& quirk_mask ) ;
if ( quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE )
return false ;
return true ;
}
static int
sdw_intel_scan_controller ( struct sdw_intel_acpi_info * info )
{
2022-01-26 22:48:49 +03:00
struct acpi_device * adev = acpi_fetch_acpi_dev ( info - > handle ) ;
2023-09-12 19:26:17 +03:00
u8 count , i ;
int ret ;
2021-03-02 03:31:24 +03:00
2022-01-26 22:48:49 +03:00
if ( ! adev )
2021-03-02 03:31:24 +03:00
return - EINVAL ;
/* Found controller, find links supported */
count = 0 ;
ret = fwnode_property_read_u8_array ( acpi_fwnode_handle ( adev ) ,
" mipi-sdw-master-count " , & count , 1 ) ;
/*
* In theory we could check the number of links supported in
* hardware , but in that step we cannot assume SoundWire IP is
* powered .
*
* In addition , if the BIOS doesn ' t even provide this
* ' master - count ' property then all the inits based on link
* masks will fail as well .
*
* We will check the hardware capabilities in the startup ( ) step
*/
if ( ret ) {
dev_err ( & adev - > dev ,
" Failed to read mipi-sdw-master-count: %d \n " , ret ) ;
return - EINVAL ;
}
/* Check count is within bounds */
if ( count > SDW_MAX_LINKS ) {
dev_err ( & adev - > dev , " Link count %d exceeds max %d \n " ,
count , SDW_MAX_LINKS ) ;
return - EINVAL ;
}
if ( ! count ) {
dev_warn ( & adev - > dev , " No SoundWire links detected \n " ) ;
return - EINVAL ;
}
dev_dbg ( & adev - > dev , " ACPI reports %d SDW Link devices \n " , count ) ;
info - > count = count ;
info - > link_mask = 0 ;
for ( i = 0 ; i < count ; i + + ) {
if ( ctrl_link_mask & & ! ( ctrl_link_mask & BIT ( i ) ) ) {
dev_dbg ( & adev - > dev ,
" Link %d masked, will not be enabled \n " , i ) ;
continue ;
}
if ( ! is_link_enabled ( acpi_fwnode_handle ( adev ) , i ) ) {
dev_dbg ( & adev - > dev ,
" Link %d not selected in firmware \n " , i ) ;
continue ;
}
info - > link_mask | = BIT ( i ) ;
}
return 0 ;
}
static acpi_status sdw_intel_acpi_cb ( acpi_handle handle , u32 level ,
void * cdata , void * * return_value )
{
struct sdw_intel_acpi_info * info = cdata ;
acpi_status status ;
u64 adr ;
status = acpi_evaluate_integer ( handle , METHOD_NAME__ADR , NULL , & adr ) ;
if ( ACPI_FAILURE ( status ) )
return AE_OK ; /* keep going */
2022-01-26 22:48:49 +03:00
if ( ! acpi_fetch_acpi_dev ( handle ) ) {
2021-03-02 03:31:24 +03:00
pr_err ( " %s: Couldn't find ACPI handle \n " , __func__ ) ;
return AE_NOT_FOUND ;
}
/*
* On some Intel platforms , multiple children of the HDAS
* device can be found , but only one of them is the SoundWire
* controller . The SNDW device is always exposed with
* Name ( _ADR , 0x40000000 ) , with bits 31. .28 representing the
* SoundWire link so filter accordingly
*/
if ( FIELD_GET ( GENMASK ( 31 , 28 ) , adr ) ! = SDW_LINK_TYPE )
return AE_OK ; /* keep going */
2021-12-21 04:08:16 +03:00
/* found the correct SoundWire controller */
info - > handle = handle ;
2021-03-02 03:31:24 +03:00
/* device found, stop namespace walk */
return AE_CTRL_TERMINATE ;
}
/**
* sdw_intel_acpi_scan ( ) - SoundWire Intel init routine
* @ parent_handle : ACPI parent handle
* @ info : description of what firmware / DSDT tables expose
*
* This scans the namespace and queries firmware to figure out which
* links to enable . A follow - up use of sdw_intel_probe ( ) and
* sdw_intel_startup ( ) is required for creation of devices and bus
* startup
*/
int sdw_intel_acpi_scan ( acpi_handle * parent_handle ,
struct sdw_intel_acpi_info * info )
{
acpi_status status ;
info - > handle = NULL ;
2021-12-21 04:08:17 +03:00
/*
* In the HDAS ACPI scope , ' SNDW ' may be either the child of
* ' HDAS ' or the grandchild of ' HDAS ' . So let ' s go through
* the ACPI from ' HDAS ' at max depth of 2 to find the ' SNDW '
* device .
*/
2021-03-02 03:31:24 +03:00
status = acpi_walk_namespace ( ACPI_TYPE_DEVICE ,
2021-12-21 04:08:17 +03:00
parent_handle , 2 ,
2021-03-02 03:31:24 +03:00
sdw_intel_acpi_cb ,
NULL , info , NULL ) ;
if ( ACPI_FAILURE ( status ) | | info - > handle = = NULL )
return - ENODEV ;
return sdw_intel_scan_controller ( info ) ;
}
EXPORT_SYMBOL_NS ( sdw_intel_acpi_scan , SND_INTEL_SOUNDWIRE_ACPI ) ;
MODULE_LICENSE ( " Dual BSD/GPL " ) ;
MODULE_DESCRIPTION ( " Intel Soundwire ACPI helpers " ) ;