162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ACPI support
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2020, Intel Corporation
662306a36Sopenharmony_ci * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/acpi.h>
1062306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "tb.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
1562306a36Sopenharmony_ci				    void **ret)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	struct acpi_device *adev = acpi_fetch_acpi_dev(handle);
1862306a36Sopenharmony_ci	struct fwnode_handle *fwnode;
1962306a36Sopenharmony_ci	struct tb_nhi *nhi = data;
2062306a36Sopenharmony_ci	struct pci_dev *pdev;
2162306a36Sopenharmony_ci	struct device *dev;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	if (!adev)
2462306a36Sopenharmony_ci		return AE_OK;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	fwnode = fwnode_find_reference(acpi_fwnode_handle(adev), "usb4-host-interface", 0);
2762306a36Sopenharmony_ci	if (IS_ERR(fwnode))
2862306a36Sopenharmony_ci		return AE_OK;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	/* It needs to reference this NHI */
3162306a36Sopenharmony_ci	if (dev_fwnode(&nhi->pdev->dev) != fwnode)
3262306a36Sopenharmony_ci		goto out_put;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	/*
3562306a36Sopenharmony_ci	 * Try to find physical device walking upwards to the hierarcy.
3662306a36Sopenharmony_ci	 * We need to do this because the xHCI driver might not yet be
3762306a36Sopenharmony_ci	 * bound so the USB3 SuperSpeed ports are not yet created.
3862306a36Sopenharmony_ci	 */
3962306a36Sopenharmony_ci	do {
4062306a36Sopenharmony_ci		dev = acpi_get_first_physical_node(adev);
4162306a36Sopenharmony_ci		if (dev)
4262306a36Sopenharmony_ci			break;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci		adev = acpi_dev_parent(adev);
4562306a36Sopenharmony_ci	} while (adev);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	/*
4862306a36Sopenharmony_ci	 * Check that the device is PCIe. This is because USB3
4962306a36Sopenharmony_ci	 * SuperSpeed ports have this property and they are not power
5062306a36Sopenharmony_ci	 * managed with the xHCI and the SuperSpeed hub so we create the
5162306a36Sopenharmony_ci	 * link from xHCI instead.
5262306a36Sopenharmony_ci	 */
5362306a36Sopenharmony_ci	while (dev && !dev_is_pci(dev))
5462306a36Sopenharmony_ci		dev = dev->parent;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (!dev)
5762306a36Sopenharmony_ci		goto out_put;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	/*
6062306a36Sopenharmony_ci	 * Check that this actually matches the type of device we
6162306a36Sopenharmony_ci	 * expect. It should either be xHCI or PCIe root/downstream
6262306a36Sopenharmony_ci	 * port.
6362306a36Sopenharmony_ci	 */
6462306a36Sopenharmony_ci	pdev = to_pci_dev(dev);
6562306a36Sopenharmony_ci	if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI ||
6662306a36Sopenharmony_ci	    (pci_is_pcie(pdev) &&
6762306a36Sopenharmony_ci		(pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
6862306a36Sopenharmony_ci		 pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM))) {
6962306a36Sopenharmony_ci		const struct device_link *link;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci		/*
7262306a36Sopenharmony_ci		 * Make them both active first to make sure the NHI does
7362306a36Sopenharmony_ci		 * not runtime suspend before the consumer. The
7462306a36Sopenharmony_ci		 * pm_runtime_put() below then allows the consumer to
7562306a36Sopenharmony_ci		 * runtime suspend again (which then allows NHI runtime
7662306a36Sopenharmony_ci		 * suspend too now that the device link is established).
7762306a36Sopenharmony_ci		 */
7862306a36Sopenharmony_ci		pm_runtime_get_sync(&pdev->dev);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci		link = device_link_add(&pdev->dev, &nhi->pdev->dev,
8162306a36Sopenharmony_ci				       DL_FLAG_AUTOREMOVE_SUPPLIER |
8262306a36Sopenharmony_ci				       DL_FLAG_RPM_ACTIVE |
8362306a36Sopenharmony_ci				       DL_FLAG_PM_RUNTIME);
8462306a36Sopenharmony_ci		if (link) {
8562306a36Sopenharmony_ci			dev_dbg(&nhi->pdev->dev, "created link from %s\n",
8662306a36Sopenharmony_ci				dev_name(&pdev->dev));
8762306a36Sopenharmony_ci			*(bool *)ret = true;
8862306a36Sopenharmony_ci		} else {
8962306a36Sopenharmony_ci			dev_warn(&nhi->pdev->dev, "device link creation from %s failed\n",
9062306a36Sopenharmony_ci				 dev_name(&pdev->dev));
9162306a36Sopenharmony_ci		}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		pm_runtime_put(&pdev->dev);
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ciout_put:
9762306a36Sopenharmony_ci	fwnode_handle_put(fwnode);
9862306a36Sopenharmony_ci	return AE_OK;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/**
10262306a36Sopenharmony_ci * tb_acpi_add_links() - Add device links based on ACPI description
10362306a36Sopenharmony_ci * @nhi: Pointer to NHI
10462306a36Sopenharmony_ci *
10562306a36Sopenharmony_ci * Goes over ACPI namespace finding tunneled ports that reference to
10662306a36Sopenharmony_ci * @nhi ACPI node. For each reference a device link is added. The link
10762306a36Sopenharmony_ci * is automatically removed by the driver core.
10862306a36Sopenharmony_ci *
10962306a36Sopenharmony_ci * Returns %true if at least one link was created.
11062306a36Sopenharmony_ci */
11162306a36Sopenharmony_cibool tb_acpi_add_links(struct tb_nhi *nhi)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	acpi_status status;
11462306a36Sopenharmony_ci	bool ret = false;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (!has_acpi_companion(&nhi->pdev->dev))
11762306a36Sopenharmony_ci		return false;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/*
12062306a36Sopenharmony_ci	 * Find all devices that have usb4-host-controller interface
12162306a36Sopenharmony_ci	 * property that references to this NHI.
12262306a36Sopenharmony_ci	 */
12362306a36Sopenharmony_ci	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 32,
12462306a36Sopenharmony_ci				     tb_acpi_add_link, NULL, nhi, (void **)&ret);
12562306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
12662306a36Sopenharmony_ci		dev_warn(&nhi->pdev->dev, "failed to enumerate tunneled ports\n");
12762306a36Sopenharmony_ci		return false;
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	return ret;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/**
13462306a36Sopenharmony_ci * tb_acpi_is_native() - Did the platform grant native TBT/USB4 control
13562306a36Sopenharmony_ci *
13662306a36Sopenharmony_ci * Returns %true if the platform granted OS native control over
13762306a36Sopenharmony_ci * TBT/USB4. In this case software based connection manager can be used,
13862306a36Sopenharmony_ci * otherwise there is firmware based connection manager running.
13962306a36Sopenharmony_ci */
14062306a36Sopenharmony_cibool tb_acpi_is_native(void)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	return osc_sb_native_usb4_support_confirmed &&
14362306a36Sopenharmony_ci	       osc_sb_native_usb4_control;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/**
14762306a36Sopenharmony_ci * tb_acpi_may_tunnel_usb3() - Is USB3 tunneling allowed by the platform
14862306a36Sopenharmony_ci *
14962306a36Sopenharmony_ci * When software based connection manager is used, this function
15062306a36Sopenharmony_ci * returns %true if platform allows native USB3 tunneling.
15162306a36Sopenharmony_ci */
15262306a36Sopenharmony_cibool tb_acpi_may_tunnel_usb3(void)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	if (tb_acpi_is_native())
15562306a36Sopenharmony_ci		return osc_sb_native_usb4_control & OSC_USB_USB3_TUNNELING;
15662306a36Sopenharmony_ci	return true;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/**
16062306a36Sopenharmony_ci * tb_acpi_may_tunnel_dp() - Is DisplayPort tunneling allowed by the platform
16162306a36Sopenharmony_ci *
16262306a36Sopenharmony_ci * When software based connection manager is used, this function
16362306a36Sopenharmony_ci * returns %true if platform allows native DP tunneling.
16462306a36Sopenharmony_ci */
16562306a36Sopenharmony_cibool tb_acpi_may_tunnel_dp(void)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	if (tb_acpi_is_native())
16862306a36Sopenharmony_ci		return osc_sb_native_usb4_control & OSC_USB_DP_TUNNELING;
16962306a36Sopenharmony_ci	return true;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/**
17362306a36Sopenharmony_ci * tb_acpi_may_tunnel_pcie() - Is PCIe tunneling allowed by the platform
17462306a36Sopenharmony_ci *
17562306a36Sopenharmony_ci * When software based connection manager is used, this function
17662306a36Sopenharmony_ci * returns %true if platform allows native PCIe tunneling.
17762306a36Sopenharmony_ci */
17862306a36Sopenharmony_cibool tb_acpi_may_tunnel_pcie(void)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	if (tb_acpi_is_native())
18162306a36Sopenharmony_ci		return osc_sb_native_usb4_control & OSC_USB_PCIE_TUNNELING;
18262306a36Sopenharmony_ci	return true;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/**
18662306a36Sopenharmony_ci * tb_acpi_is_xdomain_allowed() - Are XDomain connections allowed
18762306a36Sopenharmony_ci *
18862306a36Sopenharmony_ci * When software based connection manager is used, this function
18962306a36Sopenharmony_ci * returns %true if platform allows XDomain connections.
19062306a36Sopenharmony_ci */
19162306a36Sopenharmony_cibool tb_acpi_is_xdomain_allowed(void)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	if (tb_acpi_is_native())
19462306a36Sopenharmony_ci		return osc_sb_native_usb4_control & OSC_USB_XDOMAIN;
19562306a36Sopenharmony_ci	return true;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/* UUID for retimer _DSM: e0053122-795b-4122-8a5e-57be1d26acb3 */
19962306a36Sopenharmony_cistatic const guid_t retimer_dsm_guid =
20062306a36Sopenharmony_ci	GUID_INIT(0xe0053122, 0x795b, 0x4122,
20162306a36Sopenharmony_ci		  0x8a, 0x5e, 0x57, 0xbe, 0x1d, 0x26, 0xac, 0xb3);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci#define RETIMER_DSM_QUERY_ONLINE_STATE	1
20462306a36Sopenharmony_ci#define RETIMER_DSM_SET_ONLINE_STATE	2
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic int tb_acpi_retimer_set_power(struct tb_port *port, bool power)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct usb4_port *usb4 = port->usb4;
20962306a36Sopenharmony_ci	union acpi_object argv4[2];
21062306a36Sopenharmony_ci	struct acpi_device *adev;
21162306a36Sopenharmony_ci	union acpi_object *obj;
21262306a36Sopenharmony_ci	int ret;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	if (!usb4->can_offline)
21562306a36Sopenharmony_ci		return 0;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	adev = ACPI_COMPANION(&usb4->dev);
21862306a36Sopenharmony_ci	if (WARN_ON(!adev))
21962306a36Sopenharmony_ci		return 0;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/* Check if we are already powered on (and in correct mode) */
22262306a36Sopenharmony_ci	obj = acpi_evaluate_dsm_typed(adev->handle, &retimer_dsm_guid, 1,
22362306a36Sopenharmony_ci				      RETIMER_DSM_QUERY_ONLINE_STATE, NULL,
22462306a36Sopenharmony_ci				      ACPI_TYPE_INTEGER);
22562306a36Sopenharmony_ci	if (!obj) {
22662306a36Sopenharmony_ci		tb_port_warn(port, "ACPI: query online _DSM failed\n");
22762306a36Sopenharmony_ci		return -EIO;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	ret = obj->integer.value;
23162306a36Sopenharmony_ci	ACPI_FREE(obj);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	if (power == ret)
23462306a36Sopenharmony_ci		return 0;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	tb_port_dbg(port, "ACPI: calling _DSM to power %s retimers\n",
23762306a36Sopenharmony_ci		    power ? "on" : "off");
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	argv4[0].type = ACPI_TYPE_PACKAGE;
24062306a36Sopenharmony_ci	argv4[0].package.count = 1;
24162306a36Sopenharmony_ci	argv4[0].package.elements = &argv4[1];
24262306a36Sopenharmony_ci	argv4[1].integer.type = ACPI_TYPE_INTEGER;
24362306a36Sopenharmony_ci	argv4[1].integer.value = power;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	obj = acpi_evaluate_dsm_typed(adev->handle, &retimer_dsm_guid, 1,
24662306a36Sopenharmony_ci				      RETIMER_DSM_SET_ONLINE_STATE, argv4,
24762306a36Sopenharmony_ci				      ACPI_TYPE_INTEGER);
24862306a36Sopenharmony_ci	if (!obj) {
24962306a36Sopenharmony_ci		tb_port_warn(port,
25062306a36Sopenharmony_ci			     "ACPI: set online state _DSM evaluation failed\n");
25162306a36Sopenharmony_ci		return -EIO;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	ret = obj->integer.value;
25562306a36Sopenharmony_ci	ACPI_FREE(obj);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	if (ret >= 0) {
25862306a36Sopenharmony_ci		if (power)
25962306a36Sopenharmony_ci			return ret == 1 ? 0 : -EBUSY;
26062306a36Sopenharmony_ci		return 0;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	tb_port_warn(port, "ACPI: set online state _DSM failed with error %d\n", ret);
26462306a36Sopenharmony_ci	return -EIO;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/**
26862306a36Sopenharmony_ci * tb_acpi_power_on_retimers() - Call platform to power on retimers
26962306a36Sopenharmony_ci * @port: USB4 port
27062306a36Sopenharmony_ci *
27162306a36Sopenharmony_ci * Calls platform to turn on power to all retimers behind this USB4
27262306a36Sopenharmony_ci * port. After this function returns successfully the caller can
27362306a36Sopenharmony_ci * continue with the normal retimer flows (as specified in the USB4
27462306a36Sopenharmony_ci * spec). Note if this returns %-EBUSY it means the type-C port is in
27562306a36Sopenharmony_ci * non-USB4/TBT mode (there is non-USB4/TBT device connected).
27662306a36Sopenharmony_ci *
27762306a36Sopenharmony_ci * This should only be called if the USB4/TBT link is not up.
27862306a36Sopenharmony_ci *
27962306a36Sopenharmony_ci * Returns %0 on success.
28062306a36Sopenharmony_ci */
28162306a36Sopenharmony_ciint tb_acpi_power_on_retimers(struct tb_port *port)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	return tb_acpi_retimer_set_power(port, true);
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci/**
28762306a36Sopenharmony_ci * tb_acpi_power_off_retimers() - Call platform to power off retimers
28862306a36Sopenharmony_ci * @port: USB4 port
28962306a36Sopenharmony_ci *
29062306a36Sopenharmony_ci * This is the opposite of tb_acpi_power_on_retimers(). After returning
29162306a36Sopenharmony_ci * successfully the normal operations with the @port can continue.
29262306a36Sopenharmony_ci *
29362306a36Sopenharmony_ci * Returns %0 on success.
29462306a36Sopenharmony_ci */
29562306a36Sopenharmony_ciint tb_acpi_power_off_retimers(struct tb_port *port)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	return tb_acpi_retimer_set_power(port, false);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic bool tb_acpi_bus_match(struct device *dev)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	return tb_is_switch(dev) || tb_is_usb4_port_device(dev);
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic struct acpi_device *tb_acpi_switch_find_companion(struct tb_switch *sw)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	struct tb_switch *parent_sw = tb_switch_parent(sw);
30862306a36Sopenharmony_ci	struct acpi_device *adev = NULL;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/*
31162306a36Sopenharmony_ci	 * Device routers exists under the downstream facing USB4 port
31262306a36Sopenharmony_ci	 * of the parent router. Their _ADR is always 0.
31362306a36Sopenharmony_ci	 */
31462306a36Sopenharmony_ci	if (parent_sw) {
31562306a36Sopenharmony_ci		struct tb_port *port = tb_switch_downstream_port(sw);
31662306a36Sopenharmony_ci		struct acpi_device *port_adev;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci		port_adev = acpi_find_child_by_adr(ACPI_COMPANION(&parent_sw->dev),
31962306a36Sopenharmony_ci						   port->port);
32062306a36Sopenharmony_ci		if (port_adev)
32162306a36Sopenharmony_ci			adev = acpi_find_child_device(port_adev, 0, false);
32262306a36Sopenharmony_ci	} else {
32362306a36Sopenharmony_ci		struct tb_nhi *nhi = sw->tb->nhi;
32462306a36Sopenharmony_ci		struct acpi_device *parent_adev;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		parent_adev = ACPI_COMPANION(&nhi->pdev->dev);
32762306a36Sopenharmony_ci		if (parent_adev)
32862306a36Sopenharmony_ci			adev = acpi_find_child_device(parent_adev, 0, false);
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	return adev;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic struct acpi_device *tb_acpi_find_companion(struct device *dev)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	/*
33762306a36Sopenharmony_ci	 * The Thunderbolt/USB4 hierarchy looks like following:
33862306a36Sopenharmony_ci	 *
33962306a36Sopenharmony_ci	 * Device (NHI)
34062306a36Sopenharmony_ci	 *   Device (HR)		// Host router _ADR == 0
34162306a36Sopenharmony_ci	 *      Device (DFP0)		// Downstream port _ADR == lane 0 adapter
34262306a36Sopenharmony_ci	 *        Device (DR)		// Device router _ADR == 0
34362306a36Sopenharmony_ci	 *          Device (UFP)	// Upstream port _ADR == lane 0 adapter
34462306a36Sopenharmony_ci	 *      Device (DFP1)		// Downstream port _ADR == lane 0 adapter number
34562306a36Sopenharmony_ci	 *
34662306a36Sopenharmony_ci	 * At the moment we bind the host router to the corresponding
34762306a36Sopenharmony_ci	 * Linux device.
34862306a36Sopenharmony_ci	 */
34962306a36Sopenharmony_ci	if (tb_is_switch(dev))
35062306a36Sopenharmony_ci		return tb_acpi_switch_find_companion(tb_to_switch(dev));
35162306a36Sopenharmony_ci	if (tb_is_usb4_port_device(dev))
35262306a36Sopenharmony_ci		return acpi_find_child_by_adr(ACPI_COMPANION(dev->parent),
35362306a36Sopenharmony_ci					      tb_to_usb4_port_device(dev)->port->port);
35462306a36Sopenharmony_ci	return NULL;
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic void tb_acpi_setup(struct device *dev)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	struct acpi_device *adev = ACPI_COMPANION(dev);
36062306a36Sopenharmony_ci	struct usb4_port *usb4 = tb_to_usb4_port_device(dev);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (!adev || !usb4)
36362306a36Sopenharmony_ci		return;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	if (acpi_check_dsm(adev->handle, &retimer_dsm_guid, 1,
36662306a36Sopenharmony_ci			   BIT(RETIMER_DSM_QUERY_ONLINE_STATE) |
36762306a36Sopenharmony_ci			   BIT(RETIMER_DSM_SET_ONLINE_STATE)))
36862306a36Sopenharmony_ci		usb4->can_offline = true;
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic struct acpi_bus_type tb_acpi_bus = {
37262306a36Sopenharmony_ci	.name = "thunderbolt",
37362306a36Sopenharmony_ci	.match = tb_acpi_bus_match,
37462306a36Sopenharmony_ci	.find_companion = tb_acpi_find_companion,
37562306a36Sopenharmony_ci	.setup = tb_acpi_setup,
37662306a36Sopenharmony_ci};
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ciint tb_acpi_init(void)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	return register_acpi_bus_type(&tb_acpi_bus);
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_civoid tb_acpi_exit(void)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	unregister_acpi_bus_type(&tb_acpi_bus);
38662306a36Sopenharmony_ci}
387