162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Thunderbolt/USB4 retimer support.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2020, Intel Corporation
662306a36Sopenharmony_ci * Authors: Kranthi Kuntala <kranthi.kuntala@intel.com>
762306a36Sopenharmony_ci *	    Mika Westerberg <mika.westerberg@linux.intel.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/delay.h>
1162306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1262306a36Sopenharmony_ci#include <linux/sched/signal.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "sb_regs.h"
1562306a36Sopenharmony_ci#include "tb.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define TB_MAX_RETIMER_INDEX	6
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/**
2062306a36Sopenharmony_ci * tb_retimer_nvm_read() - Read contents of retimer NVM
2162306a36Sopenharmony_ci * @rt: Retimer device
2262306a36Sopenharmony_ci * @address: NVM address (in bytes) to start reading
2362306a36Sopenharmony_ci * @buf: Data read from NVM is stored here
2462306a36Sopenharmony_ci * @size: Number of bytes to read
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * Reads retimer NVM and copies the contents to @buf. Returns %0 if the
2762306a36Sopenharmony_ci * read was successful and negative errno in case of failure.
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_ciint tb_retimer_nvm_read(struct tb_retimer *rt, unsigned int address, void *buf,
3062306a36Sopenharmony_ci			size_t size)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	return usb4_port_retimer_nvm_read(rt->port, rt->index, address, buf, size);
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic int nvm_read(void *priv, unsigned int offset, void *val, size_t bytes)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	struct tb_nvm *nvm = priv;
3862306a36Sopenharmony_ci	struct tb_retimer *rt = tb_to_retimer(nvm->dev);
3962306a36Sopenharmony_ci	int ret;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	pm_runtime_get_sync(&rt->dev);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (!mutex_trylock(&rt->tb->lock)) {
4462306a36Sopenharmony_ci		ret = restart_syscall();
4562306a36Sopenharmony_ci		goto out;
4662306a36Sopenharmony_ci	}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	ret = tb_retimer_nvm_read(rt, offset, val, bytes);
4962306a36Sopenharmony_ci	mutex_unlock(&rt->tb->lock);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciout:
5262306a36Sopenharmony_ci	pm_runtime_mark_last_busy(&rt->dev);
5362306a36Sopenharmony_ci	pm_runtime_put_autosuspend(&rt->dev);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	return ret;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic int nvm_write(void *priv, unsigned int offset, void *val, size_t bytes)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	struct tb_nvm *nvm = priv;
6162306a36Sopenharmony_ci	struct tb_retimer *rt = tb_to_retimer(nvm->dev);
6262306a36Sopenharmony_ci	int ret = 0;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (!mutex_trylock(&rt->tb->lock))
6562306a36Sopenharmony_ci		return restart_syscall();
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	ret = tb_nvm_write_buf(nvm, offset, val, bytes);
6862306a36Sopenharmony_ci	mutex_unlock(&rt->tb->lock);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	return ret;
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic int tb_retimer_nvm_add(struct tb_retimer *rt)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct tb_nvm *nvm;
7662306a36Sopenharmony_ci	int ret;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	nvm = tb_nvm_alloc(&rt->dev);
7962306a36Sopenharmony_ci	if (IS_ERR(nvm)) {
8062306a36Sopenharmony_ci		ret = PTR_ERR(nvm) == -EOPNOTSUPP ? 0 : PTR_ERR(nvm);
8162306a36Sopenharmony_ci		goto err_nvm;
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	ret = tb_nvm_read_version(nvm);
8562306a36Sopenharmony_ci	if (ret)
8662306a36Sopenharmony_ci		goto err_nvm;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	ret = tb_nvm_add_active(nvm, nvm_read);
8962306a36Sopenharmony_ci	if (ret)
9062306a36Sopenharmony_ci		goto err_nvm;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	ret = tb_nvm_add_non_active(nvm, nvm_write);
9362306a36Sopenharmony_ci	if (ret)
9462306a36Sopenharmony_ci		goto err_nvm;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	rt->nvm = nvm;
9762306a36Sopenharmony_ci	return 0;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cierr_nvm:
10062306a36Sopenharmony_ci	dev_dbg(&rt->dev, "NVM upgrade disabled\n");
10162306a36Sopenharmony_ci	if (!IS_ERR(nvm))
10262306a36Sopenharmony_ci		tb_nvm_free(nvm);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	return ret;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic int tb_retimer_nvm_validate_and_write(struct tb_retimer *rt)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	unsigned int image_size;
11062306a36Sopenharmony_ci	const u8 *buf;
11162306a36Sopenharmony_ci	int ret;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	ret = tb_nvm_validate(rt->nvm);
11462306a36Sopenharmony_ci	if (ret)
11562306a36Sopenharmony_ci		return ret;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	buf = rt->nvm->buf_data_start;
11862306a36Sopenharmony_ci	image_size = rt->nvm->buf_data_size;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	ret = usb4_port_retimer_nvm_write(rt->port, rt->index, 0, buf,
12162306a36Sopenharmony_ci					 image_size);
12262306a36Sopenharmony_ci	if (ret)
12362306a36Sopenharmony_ci		return ret;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	rt->nvm->flushed = true;
12662306a36Sopenharmony_ci	return 0;
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic int tb_retimer_nvm_authenticate(struct tb_retimer *rt, bool auth_only)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	u32 status;
13262306a36Sopenharmony_ci	int ret;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	if (auth_only) {
13562306a36Sopenharmony_ci		ret = usb4_port_retimer_nvm_set_offset(rt->port, rt->index, 0);
13662306a36Sopenharmony_ci		if (ret)
13762306a36Sopenharmony_ci			return ret;
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	ret = usb4_port_retimer_nvm_authenticate(rt->port, rt->index);
14162306a36Sopenharmony_ci	if (ret)
14262306a36Sopenharmony_ci		return ret;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	usleep_range(100, 150);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/*
14762306a36Sopenharmony_ci	 * Check the status now if we still can access the retimer. It
14862306a36Sopenharmony_ci	 * is expected that the below fails.
14962306a36Sopenharmony_ci	 */
15062306a36Sopenharmony_ci	ret = usb4_port_retimer_nvm_authenticate_status(rt->port, rt->index,
15162306a36Sopenharmony_ci							&status);
15262306a36Sopenharmony_ci	if (!ret) {
15362306a36Sopenharmony_ci		rt->auth_status = status;
15462306a36Sopenharmony_ci		return status ? -EINVAL : 0;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	return 0;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic ssize_t device_show(struct device *dev, struct device_attribute *attr,
16162306a36Sopenharmony_ci			   char *buf)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct tb_retimer *rt = tb_to_retimer(dev);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	return sysfs_emit(buf, "%#x\n", rt->device);
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(device);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic ssize_t nvm_authenticate_show(struct device *dev,
17062306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	struct tb_retimer *rt = tb_to_retimer(dev);
17362306a36Sopenharmony_ci	int ret;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (!mutex_trylock(&rt->tb->lock))
17662306a36Sopenharmony_ci		return restart_syscall();
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	if (!rt->nvm)
17962306a36Sopenharmony_ci		ret = -EAGAIN;
18062306a36Sopenharmony_ci	else if (rt->no_nvm_upgrade)
18162306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
18262306a36Sopenharmony_ci	else
18362306a36Sopenharmony_ci		ret = sysfs_emit(buf, "%#x\n", rt->auth_status);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	mutex_unlock(&rt->tb->lock);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	return ret;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic void tb_retimer_nvm_authenticate_status(struct tb_port *port, u32 *status)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	int i;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	tb_port_dbg(port, "reading NVM authentication status of retimers\n");
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/*
19762306a36Sopenharmony_ci	 * Before doing anything else, read the authentication status.
19862306a36Sopenharmony_ci	 * If the retimer has it set, store it for the new retimer
19962306a36Sopenharmony_ci	 * device instance.
20062306a36Sopenharmony_ci	 */
20162306a36Sopenharmony_ci	for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++)
20262306a36Sopenharmony_ci		usb4_port_retimer_nvm_authenticate_status(port, i, &status[i]);
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic void tb_retimer_set_inbound_sbtx(struct tb_port *port)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	int i;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/*
21062306a36Sopenharmony_ci	 * When USB4 port is online sideband communications are
21162306a36Sopenharmony_ci	 * already up.
21262306a36Sopenharmony_ci	 */
21362306a36Sopenharmony_ci	if (!usb4_port_device_is_offline(port->usb4))
21462306a36Sopenharmony_ci		return;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	tb_port_dbg(port, "enabling sideband transactions\n");
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++)
21962306a36Sopenharmony_ci		usb4_port_retimer_set_inbound_sbtx(port, i);
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic void tb_retimer_unset_inbound_sbtx(struct tb_port *port)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	int i;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/*
22762306a36Sopenharmony_ci	 * When USB4 port is offline we need to keep the sideband
22862306a36Sopenharmony_ci	 * communications up to make it possible to communicate with
22962306a36Sopenharmony_ci	 * the connected retimers.
23062306a36Sopenharmony_ci	 */
23162306a36Sopenharmony_ci	if (usb4_port_device_is_offline(port->usb4))
23262306a36Sopenharmony_ci		return;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	tb_port_dbg(port, "disabling sideband transactions\n");
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	for (i = TB_MAX_RETIMER_INDEX; i >= 1; i--)
23762306a36Sopenharmony_ci		usb4_port_retimer_unset_inbound_sbtx(port, i);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic ssize_t nvm_authenticate_store(struct device *dev,
24162306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t count)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	struct tb_retimer *rt = tb_to_retimer(dev);
24462306a36Sopenharmony_ci	int val, ret;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	pm_runtime_get_sync(&rt->dev);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (!mutex_trylock(&rt->tb->lock)) {
24962306a36Sopenharmony_ci		ret = restart_syscall();
25062306a36Sopenharmony_ci		goto exit_rpm;
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (!rt->nvm) {
25462306a36Sopenharmony_ci		ret = -EAGAIN;
25562306a36Sopenharmony_ci		goto exit_unlock;
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	ret = kstrtoint(buf, 10, &val);
25962306a36Sopenharmony_ci	if (ret)
26062306a36Sopenharmony_ci		goto exit_unlock;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* Always clear status */
26362306a36Sopenharmony_ci	rt->auth_status = 0;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (val) {
26662306a36Sopenharmony_ci		/*
26762306a36Sopenharmony_ci		 * When NVM authentication starts the retimer is not
26862306a36Sopenharmony_ci		 * accessible so calling tb_retimer_unset_inbound_sbtx()
26962306a36Sopenharmony_ci		 * will fail and therefore we do not call it. Exception
27062306a36Sopenharmony_ci		 * is when the validation fails or we only write the new
27162306a36Sopenharmony_ci		 * NVM image without authentication.
27262306a36Sopenharmony_ci		 */
27362306a36Sopenharmony_ci		tb_retimer_set_inbound_sbtx(rt->port);
27462306a36Sopenharmony_ci		if (val == AUTHENTICATE_ONLY) {
27562306a36Sopenharmony_ci			ret = tb_retimer_nvm_authenticate(rt, true);
27662306a36Sopenharmony_ci		} else {
27762306a36Sopenharmony_ci			if (!rt->nvm->flushed) {
27862306a36Sopenharmony_ci				if (!rt->nvm->buf) {
27962306a36Sopenharmony_ci					ret = -EINVAL;
28062306a36Sopenharmony_ci					goto exit_unlock;
28162306a36Sopenharmony_ci				}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci				ret = tb_retimer_nvm_validate_and_write(rt);
28462306a36Sopenharmony_ci				if (ret || val == WRITE_ONLY)
28562306a36Sopenharmony_ci					goto exit_unlock;
28662306a36Sopenharmony_ci			}
28762306a36Sopenharmony_ci			if (val == WRITE_AND_AUTHENTICATE)
28862306a36Sopenharmony_ci				ret = tb_retimer_nvm_authenticate(rt, false);
28962306a36Sopenharmony_ci		}
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ciexit_unlock:
29362306a36Sopenharmony_ci	if (ret || val == WRITE_ONLY)
29462306a36Sopenharmony_ci		tb_retimer_unset_inbound_sbtx(rt->port);
29562306a36Sopenharmony_ci	mutex_unlock(&rt->tb->lock);
29662306a36Sopenharmony_ciexit_rpm:
29762306a36Sopenharmony_ci	pm_runtime_mark_last_busy(&rt->dev);
29862306a36Sopenharmony_ci	pm_runtime_put_autosuspend(&rt->dev);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (ret)
30162306a36Sopenharmony_ci		return ret;
30262306a36Sopenharmony_ci	return count;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_cistatic DEVICE_ATTR_RW(nvm_authenticate);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic ssize_t nvm_version_show(struct device *dev,
30762306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	struct tb_retimer *rt = tb_to_retimer(dev);
31062306a36Sopenharmony_ci	int ret;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	if (!mutex_trylock(&rt->tb->lock))
31362306a36Sopenharmony_ci		return restart_syscall();
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	if (!rt->nvm)
31662306a36Sopenharmony_ci		ret = -EAGAIN;
31762306a36Sopenharmony_ci	else
31862306a36Sopenharmony_ci		ret = sysfs_emit(buf, "%x.%x\n", rt->nvm->major, rt->nvm->minor);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	mutex_unlock(&rt->tb->lock);
32162306a36Sopenharmony_ci	return ret;
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(nvm_version);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic ssize_t vendor_show(struct device *dev, struct device_attribute *attr,
32662306a36Sopenharmony_ci			   char *buf)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct tb_retimer *rt = tb_to_retimer(dev);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	return sysfs_emit(buf, "%#x\n", rt->vendor);
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(vendor);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic struct attribute *retimer_attrs[] = {
33562306a36Sopenharmony_ci	&dev_attr_device.attr,
33662306a36Sopenharmony_ci	&dev_attr_nvm_authenticate.attr,
33762306a36Sopenharmony_ci	&dev_attr_nvm_version.attr,
33862306a36Sopenharmony_ci	&dev_attr_vendor.attr,
33962306a36Sopenharmony_ci	NULL
34062306a36Sopenharmony_ci};
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic const struct attribute_group retimer_group = {
34362306a36Sopenharmony_ci	.attrs = retimer_attrs,
34462306a36Sopenharmony_ci};
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic const struct attribute_group *retimer_groups[] = {
34762306a36Sopenharmony_ci	&retimer_group,
34862306a36Sopenharmony_ci	NULL
34962306a36Sopenharmony_ci};
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic void tb_retimer_release(struct device *dev)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	struct tb_retimer *rt = tb_to_retimer(dev);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	kfree(rt);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistruct device_type tb_retimer_type = {
35962306a36Sopenharmony_ci	.name = "thunderbolt_retimer",
36062306a36Sopenharmony_ci	.groups = retimer_groups,
36162306a36Sopenharmony_ci	.release = tb_retimer_release,
36262306a36Sopenharmony_ci};
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic int tb_retimer_add(struct tb_port *port, u8 index, u32 auth_status)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	struct tb_retimer *rt;
36762306a36Sopenharmony_ci	u32 vendor, device;
36862306a36Sopenharmony_ci	int ret;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	ret = usb4_port_retimer_read(port, index, USB4_SB_VENDOR_ID, &vendor,
37162306a36Sopenharmony_ci				     sizeof(vendor));
37262306a36Sopenharmony_ci	if (ret) {
37362306a36Sopenharmony_ci		if (ret != -ENODEV)
37462306a36Sopenharmony_ci			tb_port_warn(port, "failed read retimer VendorId: %d\n", ret);
37562306a36Sopenharmony_ci		return ret;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	ret = usb4_port_retimer_read(port, index, USB4_SB_PRODUCT_ID, &device,
37962306a36Sopenharmony_ci				     sizeof(device));
38062306a36Sopenharmony_ci	if (ret) {
38162306a36Sopenharmony_ci		if (ret != -ENODEV)
38262306a36Sopenharmony_ci			tb_port_warn(port, "failed read retimer ProductId: %d\n", ret);
38362306a36Sopenharmony_ci		return ret;
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	/*
38762306a36Sopenharmony_ci	 * Check that it supports NVM operations. If not then don't add
38862306a36Sopenharmony_ci	 * the device at all.
38962306a36Sopenharmony_ci	 */
39062306a36Sopenharmony_ci	ret = usb4_port_retimer_nvm_sector_size(port, index);
39162306a36Sopenharmony_ci	if (ret < 0)
39262306a36Sopenharmony_ci		return ret;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	rt = kzalloc(sizeof(*rt), GFP_KERNEL);
39562306a36Sopenharmony_ci	if (!rt)
39662306a36Sopenharmony_ci		return -ENOMEM;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	rt->index = index;
39962306a36Sopenharmony_ci	rt->vendor = vendor;
40062306a36Sopenharmony_ci	rt->device = device;
40162306a36Sopenharmony_ci	rt->auth_status = auth_status;
40262306a36Sopenharmony_ci	rt->port = port;
40362306a36Sopenharmony_ci	rt->tb = port->sw->tb;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	rt->dev.parent = &port->usb4->dev;
40662306a36Sopenharmony_ci	rt->dev.bus = &tb_bus_type;
40762306a36Sopenharmony_ci	rt->dev.type = &tb_retimer_type;
40862306a36Sopenharmony_ci	dev_set_name(&rt->dev, "%s:%u.%u", dev_name(&port->sw->dev),
40962306a36Sopenharmony_ci		     port->port, index);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	ret = device_register(&rt->dev);
41262306a36Sopenharmony_ci	if (ret) {
41362306a36Sopenharmony_ci		dev_err(&rt->dev, "failed to register retimer: %d\n", ret);
41462306a36Sopenharmony_ci		put_device(&rt->dev);
41562306a36Sopenharmony_ci		return ret;
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	ret = tb_retimer_nvm_add(rt);
41962306a36Sopenharmony_ci	if (ret) {
42062306a36Sopenharmony_ci		dev_err(&rt->dev, "failed to add NVM devices: %d\n", ret);
42162306a36Sopenharmony_ci		device_unregister(&rt->dev);
42262306a36Sopenharmony_ci		return ret;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	dev_info(&rt->dev, "new retimer found, vendor=%#x device=%#x\n",
42662306a36Sopenharmony_ci		 rt->vendor, rt->device);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	pm_runtime_no_callbacks(&rt->dev);
42962306a36Sopenharmony_ci	pm_runtime_set_active(&rt->dev);
43062306a36Sopenharmony_ci	pm_runtime_enable(&rt->dev);
43162306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(&rt->dev, TB_AUTOSUSPEND_DELAY);
43262306a36Sopenharmony_ci	pm_runtime_mark_last_busy(&rt->dev);
43362306a36Sopenharmony_ci	pm_runtime_use_autosuspend(&rt->dev);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	return 0;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic void tb_retimer_remove(struct tb_retimer *rt)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	dev_info(&rt->dev, "retimer disconnected\n");
44162306a36Sopenharmony_ci	tb_nvm_free(rt->nvm);
44262306a36Sopenharmony_ci	device_unregister(&rt->dev);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistruct tb_retimer_lookup {
44662306a36Sopenharmony_ci	const struct tb_port *port;
44762306a36Sopenharmony_ci	u8 index;
44862306a36Sopenharmony_ci};
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic int retimer_match(struct device *dev, void *data)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	const struct tb_retimer_lookup *lookup = data;
45362306a36Sopenharmony_ci	struct tb_retimer *rt = tb_to_retimer(dev);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	return rt && rt->port == lookup->port && rt->index == lookup->index;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic struct tb_retimer *tb_port_find_retimer(struct tb_port *port, u8 index)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	struct tb_retimer_lookup lookup = { .port = port, .index = index };
46162306a36Sopenharmony_ci	struct device *dev;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	dev = device_find_child(&port->usb4->dev, &lookup, retimer_match);
46462306a36Sopenharmony_ci	if (dev)
46562306a36Sopenharmony_ci		return tb_to_retimer(dev);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	return NULL;
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci/**
47162306a36Sopenharmony_ci * tb_retimer_scan() - Scan for on-board retimers under port
47262306a36Sopenharmony_ci * @port: USB4 port to scan
47362306a36Sopenharmony_ci * @add: If true also registers found retimers
47462306a36Sopenharmony_ci *
47562306a36Sopenharmony_ci * Brings the sideband into a state where retimers can be accessed.
47662306a36Sopenharmony_ci * Then Tries to enumerate on-board retimers connected to @port. Found
47762306a36Sopenharmony_ci * retimers are registered as children of @port if @add is set.  Does
47862306a36Sopenharmony_ci * not scan for cable retimers for now.
47962306a36Sopenharmony_ci */
48062306a36Sopenharmony_ciint tb_retimer_scan(struct tb_port *port, bool add)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	u32 status[TB_MAX_RETIMER_INDEX + 1] = {};
48362306a36Sopenharmony_ci	int ret, i, last_idx = 0;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	/*
48662306a36Sopenharmony_ci	 * Send broadcast RT to make sure retimer indices facing this
48762306a36Sopenharmony_ci	 * port are set.
48862306a36Sopenharmony_ci	 */
48962306a36Sopenharmony_ci	ret = usb4_port_enumerate_retimers(port);
49062306a36Sopenharmony_ci	if (ret)
49162306a36Sopenharmony_ci		return ret;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	/*
49462306a36Sopenharmony_ci	 * Immediately after sending enumerate retimers read the
49562306a36Sopenharmony_ci	 * authentication status of each retimer.
49662306a36Sopenharmony_ci	 */
49762306a36Sopenharmony_ci	tb_retimer_nvm_authenticate_status(port, status);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	/*
50062306a36Sopenharmony_ci	 * Enable sideband channel for each retimer. We can do this
50162306a36Sopenharmony_ci	 * regardless whether there is device connected or not.
50262306a36Sopenharmony_ci	 */
50362306a36Sopenharmony_ci	tb_retimer_set_inbound_sbtx(port);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	for (i = 1; i <= TB_MAX_RETIMER_INDEX; i++) {
50662306a36Sopenharmony_ci		/*
50762306a36Sopenharmony_ci		 * Last retimer is true only for the last on-board
50862306a36Sopenharmony_ci		 * retimer (the one connected directly to the Type-C
50962306a36Sopenharmony_ci		 * port).
51062306a36Sopenharmony_ci		 */
51162306a36Sopenharmony_ci		ret = usb4_port_retimer_is_last(port, i);
51262306a36Sopenharmony_ci		if (ret > 0)
51362306a36Sopenharmony_ci			last_idx = i;
51462306a36Sopenharmony_ci		else if (ret < 0)
51562306a36Sopenharmony_ci			break;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	tb_retimer_unset_inbound_sbtx(port);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (!last_idx)
52162306a36Sopenharmony_ci		return 0;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* Add on-board retimers if they do not exist already */
52462306a36Sopenharmony_ci	ret = 0;
52562306a36Sopenharmony_ci	for (i = 1; i <= last_idx; i++) {
52662306a36Sopenharmony_ci		struct tb_retimer *rt;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci		rt = tb_port_find_retimer(port, i);
52962306a36Sopenharmony_ci		if (rt) {
53062306a36Sopenharmony_ci			put_device(&rt->dev);
53162306a36Sopenharmony_ci		} else if (add) {
53262306a36Sopenharmony_ci			ret = tb_retimer_add(port, i, status[i]);
53362306a36Sopenharmony_ci			if (ret && ret != -EOPNOTSUPP)
53462306a36Sopenharmony_ci				break;
53562306a36Sopenharmony_ci		}
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	return ret;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic int remove_retimer(struct device *dev, void *data)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	struct tb_retimer *rt = tb_to_retimer(dev);
54462306a36Sopenharmony_ci	struct tb_port *port = data;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	if (rt && rt->port == port)
54762306a36Sopenharmony_ci		tb_retimer_remove(rt);
54862306a36Sopenharmony_ci	return 0;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci/**
55262306a36Sopenharmony_ci * tb_retimer_remove_all() - Remove all retimers under port
55362306a36Sopenharmony_ci * @port: USB4 port whose retimers to remove
55462306a36Sopenharmony_ci *
55562306a36Sopenharmony_ci * This removes all previously added retimers under @port.
55662306a36Sopenharmony_ci */
55762306a36Sopenharmony_civoid tb_retimer_remove_all(struct tb_port *port)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	struct usb4_port *usb4;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	usb4 = port->usb4;
56262306a36Sopenharmony_ci	if (usb4)
56362306a36Sopenharmony_ci		device_for_each_child_reverse(&usb4->dev, port,
56462306a36Sopenharmony_ci					      remove_retimer);
56562306a36Sopenharmony_ci}
566