linux/sound/hda/intel-sdw-acpi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
   2// Copyright(c) 2015-2021 Intel Corporation.
   3
   4/*
   5 * SDW Intel ACPI scan helpers
   6 */
   7
   8#include <linux/acpi.h>
   9#include <linux/bits.h>
  10#include <linux/bitfield.h>
  11#include <linux/device.h>
  12#include <linux/errno.h>
  13#include <linux/export.h>
  14#include <linux/fwnode.h>
  15#include <linux/module.h>
  16#include <linux/soundwire/sdw_intel.h>
  17#include <linux/string.h>
  18
  19#define SDW_LINK_TYPE           4 /* from Intel ACPI documentation */
  20#define SDW_MAX_LINKS           4
  21
  22static int ctrl_link_mask;
  23module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444);
  24MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)");
  25
  26static bool is_link_enabled(struct fwnode_handle *fw_node, int i)
  27{
  28        struct fwnode_handle *link;
  29        char name[32];
  30        u32 quirk_mask = 0;
  31
  32        /* Find master handle */
  33        snprintf(name, sizeof(name),
  34                 "mipi-sdw-link-%d-subproperties", i);
  35
  36        link = fwnode_get_named_child_node(fw_node, name);
  37        if (!link)
  38                return false;
  39
  40        fwnode_property_read_u32(link,
  41                                 "intel-quirk-mask",
  42                                 &quirk_mask);
  43
  44        if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
  45                return false;
  46
  47        return true;
  48}
  49
  50static int
  51sdw_intel_scan_controller(struct sdw_intel_acpi_info *info)
  52{
  53        struct acpi_device *adev;
  54        int ret, i;
  55        u8 count;
  56
  57        if (acpi_bus_get_device(info->handle, &adev))
  58                return -EINVAL;
  59
  60        /* Found controller, find links supported */
  61        count = 0;
  62        ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev),
  63                                            "mipi-sdw-master-count", &count, 1);
  64
  65        /*
  66         * In theory we could check the number of links supported in
  67         * hardware, but in that step we cannot assume SoundWire IP is
  68         * powered.
  69         *
  70         * In addition, if the BIOS doesn't even provide this
  71         * 'master-count' property then all the inits based on link
  72         * masks will fail as well.
  73         *
  74         * We will check the hardware capabilities in the startup() step
  75         */
  76
  77        if (ret) {
  78                dev_err(&adev->dev,
  79                        "Failed to read mipi-sdw-master-count: %d\n", ret);
  80                return -EINVAL;
  81        }
  82
  83        /* Check count is within bounds */
  84        if (count > SDW_MAX_LINKS) {
  85                dev_err(&adev->dev, "Link count %d exceeds max %d\n",
  86                        count, SDW_MAX_LINKS);
  87                return -EINVAL;
  88        }
  89
  90        if (!count) {
  91                dev_warn(&adev->dev, "No SoundWire links detected\n");
  92                return -EINVAL;
  93        }
  94        dev_dbg(&adev->dev, "ACPI reports %d SDW Link devices\n", count);
  95
  96        info->count = count;
  97        info->link_mask = 0;
  98
  99        for (i = 0; i < count; i++) {
 100                if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) {
 101                        dev_dbg(&adev->dev,
 102                                "Link %d masked, will not be enabled\n", i);
 103                        continue;
 104                }
 105
 106                if (!is_link_enabled(acpi_fwnode_handle(adev), i)) {
 107                        dev_dbg(&adev->dev,
 108                                "Link %d not selected in firmware\n", i);
 109                        continue;
 110                }
 111
 112                info->link_mask |= BIT(i);
 113        }
 114
 115        return 0;
 116}
 117
 118static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
 119                                     void *cdata, void **return_value)
 120{
 121        struct sdw_intel_acpi_info *info = cdata;
 122        struct acpi_device *adev;
 123        acpi_status status;
 124        u64 adr;
 125
 126        status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
 127        if (ACPI_FAILURE(status))
 128                return AE_OK; /* keep going */
 129
 130        if (acpi_bus_get_device(handle, &adev)) {
 131                pr_err("%s: Couldn't find ACPI handle\n", __func__);
 132                return AE_NOT_FOUND;
 133        }
 134
 135        info->handle = handle;
 136
 137        /*
 138         * On some Intel platforms, multiple children of the HDAS
 139         * device can be found, but only one of them is the SoundWire
 140         * controller. The SNDW device is always exposed with
 141         * Name(_ADR, 0x40000000), with bits 31..28 representing the
 142         * SoundWire link so filter accordingly
 143         */
 144        if (FIELD_GET(GENMASK(31, 28), adr) != SDW_LINK_TYPE)
 145                return AE_OK; /* keep going */
 146
 147        /* device found, stop namespace walk */
 148        return AE_CTRL_TERMINATE;
 149}
 150
 151/**
 152 * sdw_intel_acpi_scan() - SoundWire Intel init routine
 153 * @parent_handle: ACPI parent handle
 154 * @info: description of what firmware/DSDT tables expose
 155 *
 156 * This scans the namespace and queries firmware to figure out which
 157 * links to enable. A follow-up use of sdw_intel_probe() and
 158 * sdw_intel_startup() is required for creation of devices and bus
 159 * startup
 160 */
 161int sdw_intel_acpi_scan(acpi_handle *parent_handle,
 162                        struct sdw_intel_acpi_info *info)
 163{
 164        acpi_status status;
 165
 166        info->handle = NULL;
 167        status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
 168                                     parent_handle, 1,
 169                                     sdw_intel_acpi_cb,
 170                                     NULL, info, NULL);
 171        if (ACPI_FAILURE(status) || info->handle == NULL)
 172                return -ENODEV;
 173
 174        return sdw_intel_scan_controller(info);
 175}
 176EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, SND_INTEL_SOUNDWIRE_ACPI);
 177
 178MODULE_LICENSE("Dual BSD/GPL");
 179MODULE_DESCRIPTION("Intel Soundwire ACPI helpers");
 180