Commit 881eccbe authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull soundwire updates from Vinod Koul:
 "Updates for Intel, Cadence and Qualcomm drivers:

   - another round of Intel driver cleanup to prepare for future code
     reorg which is expected in next cycle (Pierre-Louis Bossart)

   - bus unattach notifications processing during re-enumeration along
     with Cadence driver updates for this (Richard Fitzgerald)

   - Qualcomm driver updates to handle device0 status (Srinivas
     Kandagatla)"

* tag 'soundwire-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: (42 commits)
  soundwire: intel: add helper to stop bus
  soundwire: intel: introduce helpers to start bus
  soundwire: intel: introduce intel_shim_check_wake() helper
  soundwire: intel: simplify read ops assignment
  soundwire: intel: remove intel_init() wrapper
  soundwire: intel: move shim initialization before power up/down
  soundwire: intel: remove clock_stop parameter in intel_shim_init()
  soundwire: intel: move all PDI initialization under intel_register_dai()
  soundwire: intel: move DAI registration and debugfs init earlier
  soundwire: intel: simplify flow and use devm_ for DAI registration
  soundwire: intel: fix error handling on dai registration issues
  soundwire: cadence: Simplify error paths in cdns_xfer_msg()
  soundwire: cadence: Fix error check in cdns_xfer_msg()
  soundwire: cadence: Write to correct address for each FIFO chunk
  soundwire: bus: Fix wrong port number in sdw_handle_slave_alerts()
  soundwire: qcom: do not send status of device 0 during alert
  soundwire: qcom: update status from device id 1
  soundwire: cadence: Don't overwrite msg->buf during write commands
  soundwire: bus: Don't exit early if no device IDs were programmed
  soundwire: cadence: Fix lost ATTACHED interrupts when enumerating
  ...
parents 33e591de 503ae285
Loading
Loading
Loading
Loading
+66 −28
Original line number Diff line number Diff line
@@ -11,11 +11,12 @@
#include "bus.h"
#include "sysfs_local.h"

static DEFINE_IDA(sdw_ida);
static DEFINE_IDA(sdw_bus_ida);
static DEFINE_IDA(sdw_peripheral_ida);

static int sdw_get_id(struct sdw_bus *bus)
{
	int rc = ida_alloc(&sdw_ida, GFP_KERNEL);
	int rc = ida_alloc(&sdw_bus_ida, GFP_KERNEL);

	if (rc < 0)
		return rc;
@@ -75,7 +76,6 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,

	/*
	 * Initialize multi_link flag
	 * TODO: populate this flag by reading property from FW node
	 */
	bus->multi_link = false;
	if (bus->ops->read_prop) {
@@ -157,9 +157,11 @@ static int sdw_delete_slave(struct device *dev, void *data)

	mutex_lock(&bus->bus_lock);

	if (slave->dev_num) /* clear dev_num if assigned */
	if (slave->dev_num) { /* clear dev_num if assigned */
		clear_bit(slave->dev_num, bus->assigned);

		if (bus->dev_num_ida_min)
			ida_free(&sdw_peripheral_ida, slave->dev_num);
	}
	list_del_init(&slave->node);
	mutex_unlock(&bus->bus_lock);

@@ -179,7 +181,7 @@ void sdw_bus_master_delete(struct sdw_bus *bus)
	sdw_master_device_del(bus);

	sdw_bus_debugfs_exit(bus);
	ida_free(&sdw_ida, bus->id);
	ida_free(&sdw_bus_ida, bus->id);
}
EXPORT_SYMBOL(sdw_bus_master_delete);

@@ -671,11 +673,19 @@ static int sdw_get_device_num(struct sdw_slave *slave)
{
	int bit;

	if (slave->bus->dev_num_ida_min) {
		bit = ida_alloc_range(&sdw_peripheral_ida,
				      slave->bus->dev_num_ida_min, SDW_MAX_DEVICES,
				      GFP_KERNEL);
		if (bit < 0)
			goto err;
	} else {
		bit = find_first_zero_bit(slave->bus->assigned, SDW_MAX_DEVICES);
		if (bit == SDW_MAX_DEVICES) {
			bit = -ENODEV;
			goto err;
		}
	}

	/*
	 * Do not update dev_num in Slave data structure here,
@@ -751,7 +761,7 @@ void sdw_extract_slave_id(struct sdw_bus *bus,
}
EXPORT_SYMBOL(sdw_extract_slave_id);

static int sdw_program_device_num(struct sdw_bus *bus)
static int sdw_program_device_num(struct sdw_bus *bus, bool *programmed)
{
	u8 buf[SDW_NUM_DEV_ID_REGISTERS] = {0};
	struct sdw_slave *slave, *_s;
@@ -761,6 +771,8 @@ static int sdw_program_device_num(struct sdw_bus *bus)
	int count = 0, ret;
	u64 addr;

	*programmed = false;

	/* No Slave, so use raw xfer api */
	ret = sdw_fill_msg(&msg, NULL, SDW_SCP_DEVID_0,
			   SDW_NUM_DEV_ID_REGISTERS, 0, SDW_MSG_FLAG_READ, buf);
@@ -795,6 +807,16 @@ static int sdw_program_device_num(struct sdw_bus *bus)
			if (sdw_compare_devid(slave, id) == 0) {
				found = true;

				/*
				 * To prevent skipping state-machine stages don't
				 * program a device until we've seen it UNATTACH.
				 * Must return here because no other device on #0
				 * can be detected until this one has been
				 * assigned a device ID.
				 */
				if (slave->status != SDW_SLAVE_UNATTACHED)
					return 0;

				/*
				 * Assign a new dev_num to this Slave and
				 * not mark it present. It will be marked
@@ -809,6 +831,8 @@ static int sdw_program_device_num(struct sdw_bus *bus)
					return ret;
				}

				*programmed = true;

				break;
			}
		}
@@ -848,13 +872,13 @@ static void sdw_modify_slave_status(struct sdw_slave *slave,
	mutex_lock(&bus->bus_lock);

	dev_vdbg(bus->dev,
		 "%s: changing status slave %d status %d new status %d\n",
		 __func__, slave->dev_num, slave->status, status);
		 "changing status slave %d status %d new status %d\n",
		 slave->dev_num, slave->status, status);

	if (status == SDW_SLAVE_UNATTACHED) {
		dev_dbg(&slave->dev,
			"%s: initializing enumeration and init completion for Slave %d\n",
			__func__, slave->dev_num);
			"initializing enumeration and init completion for Slave %d\n",
			slave->dev_num);

		init_completion(&slave->enumeration_complete);
		init_completion(&slave->initialization_complete);
@@ -862,8 +886,8 @@ static void sdw_modify_slave_status(struct sdw_slave *slave,
	} else if ((status == SDW_SLAVE_ATTACHED) &&
		   (slave->status == SDW_SLAVE_UNATTACHED)) {
		dev_dbg(&slave->dev,
			"%s: signaling enumeration completion for Slave %d\n",
			__func__, slave->dev_num);
			"signaling enumeration completion for Slave %d\n",
			slave->dev_num);

		complete(&slave->enumeration_complete);
	}
@@ -1630,7 +1654,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
			port = buf2[0] & SDW_SCP_INTSTAT2_PORT4_10;
			for_each_set_bit(bit, &port, 8) {
				/* scp2 ports start from 4 */
				port_num = bit + 3;
				port_num = bit + 4;
				sdw_handle_port_interrupt(slave,
						port_num,
						&port_status[port_num]);
@@ -1642,7 +1666,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
			port = buf2[1] & SDW_SCP_INTSTAT3_PORT11_14;
			for_each_set_bit(bit, &port, 8) {
				/* scp3 ports start from 11 */
				port_num = bit + 10;
				port_num = bit + 11;
				sdw_handle_port_interrupt(slave,
						port_num,
						&port_status[port_num]);
@@ -1768,7 +1792,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
{
	enum sdw_slave_status prev_status;
	struct sdw_slave *slave;
	bool attached_initializing;
	bool attached_initializing, id_programmed;
	int i, ret = 0;

	/* first check if any Slaves fell off the bus */
@@ -1789,19 +1813,33 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
			dev_warn(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n",
				 i, slave->status);
			sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED);

			/* Ensure driver knows that peripheral unattached */
			ret = sdw_update_slave_status(slave, status[i]);
			if (ret < 0)
				dev_warn(&slave->dev, "Update Slave status failed:%d\n", ret);
		}
	}

	if (status[0] == SDW_SLAVE_ATTACHED) {
		dev_dbg(bus->dev, "Slave attached, programming device number\n");
		ret = sdw_program_device_num(bus);
		if (ret < 0)
			dev_err(bus->dev, "Slave attach failed: %d\n", ret);

		/*
		 * programming a device number will have side effects,
		 * so we deal with other devices at a later time
		 * Programming a device number will have side effects,
		 * so we deal with other devices at a later time.
		 * This relies on those devices reporting ATTACHED, which will
		 * trigger another call to this function. This will only
		 * happen if at least one device ID was programmed.
		 * Error returns from sdw_program_device_num() are currently
		 * ignored because there's no useful recovery that can be done.
		 * Returning the error here could result in the current status
		 * of other devices not being handled, because if no device IDs
		 * were programmed there's nothing to guarantee a status change
		 * to trigger another call to this function.
		 */
		return ret;
		sdw_program_device_num(bus, &id_programmed);
		if (id_programmed)
			return 0;
	}

	/* Continue to check other slave statuses */
@@ -1870,8 +1908,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
				"Update Slave status failed:%d\n", ret);
		if (attached_initializing) {
			dev_dbg(&slave->dev,
				"%s: signaling initialization completion for Slave %d\n",
				__func__, slave->dev_num);
				"signaling initialization completion for Slave %d\n",
				slave->dev_num);

			complete(&slave->initialization_complete);

+56 −48
Original line number Diff line number Diff line
@@ -544,9 +544,12 @@ cdns_fill_msg_resp(struct sdw_cdns *cdns,
		return SDW_CMD_IGNORED;
	}

	if (msg->flags == SDW_MSG_FLAG_READ) {
		/* fill response */
		for (i = 0; i < count; i++)
		msg->buf[i + offset] = FIELD_GET(CDNS_MCP_RESP_RDATA, cdns->response_buf[i]);
			msg->buf[i + offset] = FIELD_GET(CDNS_MCP_RESP_RDATA,
							 cdns->response_buf[i]);
	}

	return SDW_CMD_OK;
}
@@ -566,7 +569,7 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,
	}

	base = CDNS_MCP_CMD_BASE;
	addr = msg->addr;
	addr = msg->addr + offset;

	for (i = 0; i < count; i++) {
		data = FIELD_PREP(CDNS_MCP_CMD_DEV_ADDR, msg->dev_num);
@@ -705,18 +708,15 @@ cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg)
	for (i = 0; i < msg->len / CDNS_MCP_CMD_LEN; i++) {
		ret = _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN,
				     CDNS_MCP_CMD_LEN, false);
		if (ret < 0)
			goto exit;
		if (ret != SDW_CMD_OK)
			return ret;
	}

	if (!(msg->len % CDNS_MCP_CMD_LEN))
		goto exit;
		return SDW_CMD_OK;

	ret = _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN,
	return _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN,
			      msg->len % CDNS_MCP_CMD_LEN, false);

exit:
	return ret;
}
EXPORT_SYMBOL(cdns_xfer_msg);

@@ -790,6 +790,7 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
	enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
	bool is_slave = false;
	u32 mask;
	u32 val;
	int i, set_status;

	memset(status, 0, sizeof(status));
@@ -797,12 +798,12 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
	for (i = 0; i <= SDW_MAX_DEVICES; i++) {
		mask = (slave_intstat >> (i * CDNS_MCP_SLAVE_STATUS_NUM)) &
			CDNS_MCP_SLAVE_STATUS_BITS;
		if (!mask)
			continue;

		is_slave = true;
		set_status = 0;

		if (mask) {
			is_slave = true;

			if (mask & CDNS_MCP_SLAVE_INTSTAT_RESERVED) {
				status[i] = SDW_SLAVE_RESERVED;
				set_status++;
@@ -822,16 +823,13 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
				status[i] = SDW_SLAVE_UNATTACHED;
				set_status++;
			}
		}

		/* first check if Slave reported multiple status */
		if (set_status > 1) {
			u32 val;

			dev_warn_ratelimited(cdns->dev,
					     "Slave %d reported multiple Status: %d\n",
					     i, mask);

			/* check latest status extracted from PING commands */
		/*
		 * check that there was a single reported Slave status and when
		 * there is not use the latest status extracted from PING commands
		 */
		if (set_status != 1) {
			val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
			val >>= (i * 2);

@@ -850,11 +848,6 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
				status[i] = SDW_SLAVE_RESERVED;
				break;
			}

			dev_warn_ratelimited(cdns->dev,
					     "Slave %d status updated to %d\n",
					     i, status[i]);

		}
	}

@@ -969,9 +962,22 @@ static void cdns_update_slave_status_work(struct work_struct *work)
	u32 device0_status;
	int retry_count = 0;

	/*
	 * Clear main interrupt first so we don't lose any assertions
	 * that happen during this function.
	 */
	cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_SLAVE_MASK);

	slave0 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0);
	slave1 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);

	/*
	 * Clear the bits before handling so we don't lose any
	 * bits that re-assert.
	 */
	cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave0);
	cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave1);

	/* combine the two status */
	slave_intstat = ((u64)slave1 << 32) | slave0;

@@ -979,8 +985,6 @@ static void cdns_update_slave_status_work(struct work_struct *work)

update_status:
	cdns_update_slave_status(cdns, slave_intstat);
	cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave0);
	cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave1);

	/*
	 * When there is more than one peripheral per link, it's
@@ -997,6 +1001,11 @@ static void cdns_update_slave_status_work(struct work_struct *work)
	 * attention with PING commands. There is no need to check for
	 * ALERTS since they are not allowed until a non-zero
	 * device_number is assigned.
	 *
	 * Do not clear the INTSTAT0/1. While looping to enumerate devices on
	 * #0 there could be status changes on other devices - these must
	 * be kept in the INTSTAT so they can be handled when all #0 devices
	 * have been handled.
	 */

	device0_status = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
@@ -1016,8 +1025,7 @@ static void cdns_update_slave_status_work(struct work_struct *work)
		}
	}

	/* clear and unmask Slave interrupt now */
	cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_SLAVE_MASK);
	/* unmask Slave interrupt now */
	cdns_updatel(cdns, CDNS_MCP_INTMASK,
		     CDNS_MCP_INT_SLAVE_MASK, CDNS_MCP_INT_SLAVE_MASK);

+27 −0
Original line number Diff line number Diff line
@@ -55,7 +55,26 @@ static const struct adr_remap dell_sku_0A3E[] = {
	{}
};

/*
 * The HP Omen 16-k0005TX does not expose the correct version of RT711 on link0
 * and does not expose a RT1316 on link3
 */
static const struct adr_remap hp_omen_16[] = {
	/* rt711-sdca on link0 */
	{
		0x000020025d071100ull,
		0x000030025d071101ull
	},
	/* rt1316-sdca on link3 */
	{
		0x000120025d071100ull,
		0x000330025d131601ull
	},
	{}
};

static const struct dmi_system_id adr_remap_quirk_table[] = {
	/* TGL devices */
	{
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
@@ -78,6 +97,14 @@ static const struct dmi_system_id adr_remap_quirk_table[] = {
		},
		.driver_data = (void *)dell_sku_0A3E,
	},
	/* ADL devices */
	{
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
			DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-k0xxx"),
		},
		.driver_data = (void *)hp_omen_16,
	},
	{}
};

+361 −373

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -306,7 +306,7 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)

	/* Check SNDWLCAP.LCOUNT */
	caps = ioread32(ctx->mmio_base + ctx->shim_base + SDW_SHIM_LCAP);
	caps &= GENMASK(2, 0);
	caps &= SDW_SHIM_LCAP_LCOUNT_MASK;

	/* Check HW supported vs property value */
	if (caps < ctx->count) {
Loading