| 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/module.h> | 
|---|
| 15 | #include <linux/property.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 |  | 
|---|
| 21 | static int ctrl_link_mask; | 
|---|
| 22 | module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444); | 
|---|
| 23 | MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)"); | 
|---|
| 24 |  | 
|---|
| 25 | static ulong ctrl_addr = 0x40000000; | 
|---|
| 26 | module_param_named(sdw_ctrl_addr, ctrl_addr, ulong, 0444); | 
|---|
| 27 | MODULE_PARM_DESC(sdw_ctrl_addr, "Intel SoundWire Controller _ADR"); | 
|---|
| 28 |  | 
|---|
| 29 | static bool is_link_enabled(struct fwnode_handle *fw_node, u8 idx) | 
|---|
| 30 | { | 
|---|
| 31 | struct fwnode_handle *link; | 
|---|
| 32 | char name[32]; | 
|---|
| 33 | u32 quirk_mask = 0; | 
|---|
| 34 |  | 
|---|
| 35 | /* Find master handle */ | 
|---|
| 36 | snprintf(buf: name, size: sizeof(name), | 
|---|
| 37 | fmt: "mipi-sdw-link-%hhu-subproperties", idx); | 
|---|
| 38 |  | 
|---|
| 39 | link = fwnode_get_named_child_node(fwnode: fw_node, childname: name); | 
|---|
| 40 | if (!link) | 
|---|
| 41 | return false; | 
|---|
| 42 |  | 
|---|
| 43 | fwnode_property_read_u32(fwnode: link, | 
|---|
| 44 | propname: "intel-quirk-mask", | 
|---|
| 45 | val: &quirk_mask); | 
|---|
| 46 |  | 
|---|
| 47 | fwnode_handle_put(fwnode: link); | 
|---|
| 48 |  | 
|---|
| 49 | if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE) | 
|---|
| 50 | return false; | 
|---|
| 51 |  | 
|---|
| 52 | return true; | 
|---|
| 53 | } | 
|---|
| 54 |  | 
|---|
| 55 | static int | 
|---|
| 56 | sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) | 
|---|
| 57 | { | 
|---|
| 58 | struct acpi_device *adev = acpi_fetch_acpi_dev(handle: info->handle); | 
|---|
| 59 | struct fwnode_handle *fwnode; | 
|---|
| 60 | unsigned long list; | 
|---|
| 61 | unsigned int i; | 
|---|
| 62 | u32 count; | 
|---|
| 63 | u32 tmp; | 
|---|
| 64 | int ret; | 
|---|
| 65 |  | 
|---|
| 66 | if (!adev) | 
|---|
| 67 | return -EINVAL; | 
|---|
| 68 |  | 
|---|
| 69 | fwnode = acpi_fwnode_handle(adev); | 
|---|
| 70 |  | 
|---|
| 71 | /* | 
|---|
| 72 | * Found controller, find links supported | 
|---|
| 73 | * | 
|---|
| 74 | * In theory we could check the number of links supported in | 
|---|
| 75 | * hardware, but in that step we cannot assume SoundWire IP is | 
|---|
| 76 | * powered. | 
|---|
| 77 | * | 
|---|
| 78 | * In addition, if the BIOS doesn't even provide this | 
|---|
| 79 | * 'master-count' property then all the inits based on link | 
|---|
| 80 | * masks will fail as well. | 
|---|
| 81 | * | 
|---|
| 82 | * We will check the hardware capabilities in the startup() step | 
|---|
| 83 | */ | 
|---|
| 84 | ret = fwnode_property_read_u32(fwnode, propname: "mipi-sdw-manager-list", val: &tmp); | 
|---|
| 85 | if (ret) { | 
|---|
| 86 | ret = fwnode_property_read_u32(fwnode, propname: "mipi-sdw-master-count", val: &count); | 
|---|
| 87 | if (ret) { | 
|---|
| 88 | dev_err(&adev->dev, | 
|---|
| 89 | "Failed to read mipi-sdw-master-count: %d\n", | 
|---|
| 90 | ret); | 
|---|
| 91 | return ret; | 
|---|
| 92 | } | 
|---|
| 93 | list = GENMASK(count - 1, 0); | 
|---|
| 94 | } else { | 
|---|
| 95 | list = tmp; | 
|---|
| 96 | count = hweight32(list); | 
|---|
| 97 | } | 
|---|
| 98 |  | 
|---|
| 99 | /* Check count is within bounds */ | 
|---|
| 100 | if (count > SDW_INTEL_MAX_LINKS) { | 
|---|
| 101 | dev_err(&adev->dev, "Link count %d exceeds max %d\n", | 
|---|
| 102 | count, SDW_INTEL_MAX_LINKS); | 
|---|
| 103 | return -EINVAL; | 
|---|
| 104 | } | 
|---|
| 105 |  | 
|---|
| 106 | if (!count) { | 
|---|
| 107 | dev_warn(&adev->dev, "No SoundWire links detected\n"); | 
|---|
| 108 | return -EINVAL; | 
|---|
| 109 | } | 
|---|
| 110 | dev_dbg(&adev->dev, "ACPI reports %d SDW Link devices\n", count); | 
|---|
| 111 |  | 
|---|
| 112 | info->count = count; | 
|---|
| 113 | info->link_mask = 0; | 
|---|
| 114 |  | 
|---|
| 115 | for_each_set_bit(i, &list, SDW_INTEL_MAX_LINKS) { | 
|---|
| 116 | if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) { | 
|---|
| 117 | dev_dbg(&adev->dev, | 
|---|
| 118 | "Link %d masked, will not be enabled\n", i); | 
|---|
| 119 | continue; | 
|---|
| 120 | } | 
|---|
| 121 |  | 
|---|
| 122 | if (!is_link_enabled(fw_node: fwnode, idx: i)) { | 
|---|
| 123 | dev_dbg(&adev->dev, | 
|---|
| 124 | "Link %d not selected in firmware\n", i); | 
|---|
| 125 | continue; | 
|---|
| 126 | } | 
|---|
| 127 |  | 
|---|
| 128 | info->link_mask |= BIT(i); | 
|---|
| 129 | } | 
|---|
| 130 |  | 
|---|
| 131 | return 0; | 
|---|
| 132 | } | 
|---|
| 133 |  | 
|---|
| 134 | static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, | 
|---|
| 135 | void *cdata, void **return_value) | 
|---|
| 136 | { | 
|---|
| 137 | struct sdw_intel_acpi_info *info = cdata; | 
|---|
| 138 | u64 adr; | 
|---|
| 139 | int ret; | 
|---|
| 140 |  | 
|---|
| 141 | ret = acpi_get_local_u64_address(handle, addr: &adr); | 
|---|
| 142 | if (ret < 0) | 
|---|
| 143 | return AE_OK; /* keep going */ | 
|---|
| 144 |  | 
|---|
| 145 | if (!acpi_fetch_acpi_dev(handle)) { | 
|---|
| 146 | pr_err( "%s: Couldn't find ACPI handle\n", __func__); | 
|---|
| 147 | return AE_NOT_FOUND; | 
|---|
| 148 | } | 
|---|
| 149 |  | 
|---|
| 150 | /* | 
|---|
| 151 | * On some Intel platforms, multiple children of the HDAS | 
|---|
| 152 | * device can be found, but only one of them is the SoundWire | 
|---|
| 153 | * controller. The SNDW device is always exposed with | 
|---|
| 154 | * Name(_ADR, 0x40000000), with bits 31..28 representing the | 
|---|
| 155 | * SoundWire link so filter accordingly | 
|---|
| 156 | */ | 
|---|
| 157 | if (FIELD_GET(GENMASK(31, 28), adr) != SDW_LINK_TYPE) | 
|---|
| 158 | return AE_OK; /* keep going */ | 
|---|
| 159 |  | 
|---|
| 160 | if (adr != ctrl_addr) | 
|---|
| 161 | return AE_OK; /* keep going */ | 
|---|
| 162 |  | 
|---|
| 163 | /* found the correct SoundWire controller */ | 
|---|
| 164 | info->handle = handle; | 
|---|
| 165 |  | 
|---|
| 166 | /* device found, stop namespace walk */ | 
|---|
| 167 | return AE_CTRL_TERMINATE; | 
|---|
| 168 | } | 
|---|
| 169 |  | 
|---|
| 170 | /** | 
|---|
| 171 | * sdw_intel_acpi_scan() - SoundWire Intel init routine | 
|---|
| 172 | * @parent_handle: ACPI parent handle | 
|---|
| 173 | * @info: description of what firmware/DSDT tables expose | 
|---|
| 174 | * | 
|---|
| 175 | * This scans the namespace and queries firmware to figure out which | 
|---|
| 176 | * links to enable. A follow-up use of sdw_intel_probe() and | 
|---|
| 177 | * sdw_intel_startup() is required for creation of devices and bus | 
|---|
| 178 | * startup | 
|---|
| 179 | */ | 
|---|
| 180 | int sdw_intel_acpi_scan(acpi_handle parent_handle, | 
|---|
| 181 | struct sdw_intel_acpi_info *info) | 
|---|
| 182 | { | 
|---|
| 183 | acpi_status status; | 
|---|
| 184 |  | 
|---|
| 185 | info->handle = NULL; | 
|---|
| 186 | /* | 
|---|
| 187 | * In the HDAS ACPI scope, 'SNDW' may be either the child of | 
|---|
| 188 | * 'HDAS' or the grandchild of 'HDAS'. So let's go through | 
|---|
| 189 | * the ACPI from 'HDAS' at max depth of 2 to find the 'SNDW' | 
|---|
| 190 | * device. | 
|---|
| 191 | */ | 
|---|
| 192 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, | 
|---|
| 193 | start_object: parent_handle, max_depth: 2, | 
|---|
| 194 | descending_callback: sdw_intel_acpi_cb, | 
|---|
| 195 | NULL, context: info, NULL); | 
|---|
| 196 | if (ACPI_FAILURE(status) || info->handle == NULL) | 
|---|
| 197 | return -ENODEV; | 
|---|
| 198 |  | 
|---|
| 199 | return sdw_intel_scan_controller(info); | 
|---|
| 200 | } | 
|---|
| 201 | EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, "SND_INTEL_SOUNDWIRE_ACPI"); | 
|---|
| 202 |  | 
|---|
| 203 | MODULE_LICENSE( "Dual BSD/GPL"); | 
|---|
| 204 | MODULE_DESCRIPTION( "Intel Soundwire ACPI helpers"); | 
|---|
| 205 |  | 
|---|