Commit 4cb1a880 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'soundwire-5.10-rc1' of...

Merge tag 'soundwire-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire into char-misc-next

Vinod writes:

soundwire updates for 5.10-rc1

This round of update includes:
 - Generic bandwidth allocation algorithm from Intel folks
 - PM support for Intel chipsets
 - Updates to Intel drivers which makes sdw usable on latest laptops
 - Support for MMIO SDW controllers found in QC chipsets
 - Update to subsystem to use helpers in bitfield.h to manage register
   bits

* tag 'soundwire-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: (66 commits)
  soundwire: sysfs: add slave status and device number before probe
  soundwire: bus: add enumerated Slave device to device list
  soundwire: remove an unnecessary NULL check
  soundwire: cadence: add data port test fail interrupt
  soundwire: intel: enable test modes
  soundwire: enable Data Port test modes
  soundwire: intel: use {u32|u16}p_replace_bits
  soundwire: cadence: use u32p_replace_bits
  soundwire: qcom: get max rows and cols info from compatible
  soundwire: qcom: add support to block packing mode
  soundwire: qcom: clear BIT FIELDs before value set.
  soundwire: Add generic bandwidth allocation algorithm
  soundwire: cadence: add parity error injection through debugfs
  soundwire: bus: export broadcast read/write capability for tests
  ASoC: codecs: realtek-soundwire: ignore initial PARITY errors
  soundwire: bus: use quirk to filter out invalid parity errors
  soundwire: slave: add first_interrupt_done status
  soundwire: bus: filter-out unwanted interrupt reports
  ASoC/soundwire: bus: use property to set interrupt masks
  soundwire: qcom: fix SLIBMUS/SLIMBUS typo
  ...
parents c471bf4b 0173f525
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
What:		/sys/bus/soundwire/devices/sdw:.../status
		/sys/bus/soundwire/devices/sdw:.../device_number

Date:		September 2020

Contact:	Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
		Bard Liao <yung-chuan.liao@linux.intel.com>
		Vinod Koul <vkoul@kernel.org>

Description:	SoundWire Slave status

		These properties report the Slave status, e.g. if it
		is UNATTACHED or not, and in the latter case show the
		device_number. This status information is useful to
		detect devices exposed by platform firmware but not
		physically present on the bus, and conversely devices
		not exposed in platform firmware but enumerated.

What:		/sys/bus/soundwire/devices/sdw:.../dev-properties/mipi_revision
		/sys/bus/soundwire/devices/sdw:.../dev-properties/wake_capable
		/sys/bus/soundwire/devices/sdw:.../dev-properties/test_mode_capable
+1 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ board specific bus parameters.
		    Example:
			"qcom,soundwire-v1.3.0"
			"qcom,soundwire-v1.5.0"
			"qcom,soundwire-v1.5.1"
			"qcom,soundwire-v1.6.0"
- reg:
	Usage: required
+6 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ config SOUNDWIRE_CADENCE
config SOUNDWIRE_INTEL
	tristate "Intel SoundWire Master driver"
	select SOUNDWIRE_CADENCE
	select SOUNDWIRE_GENERIC_ALLOCATION
	depends on ACPI && SND_SOC
	help
	  SoundWire Intel Master driver.
@@ -33,11 +34,15 @@ config SOUNDWIRE_INTEL

config SOUNDWIRE_QCOM
	tristate "Qualcomm SoundWire Master driver"
	depends on SLIMBUS
	imply SLIMBUS
	depends on SND_SOC
	help
	  SoundWire Qualcomm Master driver.
	  If you have an Qualcomm platform which has a SoundWire Master then
	  enable this config option to get the SoundWire support for that
	  device

config SOUNDWIRE_GENERIC_ALLOCATION
	tristate

endif
+3 −0
Original line number Diff line number Diff line
@@ -8,6 +8,9 @@ soundwire-bus-y := bus_type.o bus.o master.o slave.o mipi_disco.o stream.o \
			sysfs_slave.o sysfs_slave_dpn.o
obj-$(CONFIG_SOUNDWIRE) += soundwire-bus.o

soundwire-generic-allocation-objs := generic_bandwidth_allocation.o
obj-$(CONFIG_SOUNDWIRE_GENERIC_ALLOCATION) += soundwire-generic-allocation.o

ifdef CONFIG_DEBUG_FS
soundwire-bus-y += debugfs.o
endif
+99 −21
Original line number Diff line number Diff line
@@ -61,6 +61,12 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
		return -EINVAL;
	}

	if (!bus->compute_params) {
		dev_err(bus->dev,
			"Bandwidth allocation not configured, compute_params no set\n");
		return -EINVAL;
	}

	mutex_init(&bus->msg_lock);
	mutex_init(&bus->bus_lock);
	INIT_LIST_HEAD(&bus->slaves);
@@ -255,6 +261,21 @@ static int sdw_reset_page(struct sdw_bus *bus, u16 dev_num)
	return ret;
}

static int sdw_transfer_unlocked(struct sdw_bus *bus, struct sdw_msg *msg)
{
	int ret;

	ret = do_transfer(bus, msg);
	if (ret != 0 && ret != -ENODATA)
		dev_err(bus->dev, "trf on Slave %d failed:%d\n",
			msg->dev_num, ret);

	if (msg->page)
		sdw_reset_page(bus, msg->dev_num);

	return ret;
}

/**
 * sdw_transfer() - Synchronous transfer message to a SDW Slave device
 * @bus: SDW bus
@@ -266,13 +287,7 @@ int sdw_transfer(struct sdw_bus *bus, struct sdw_msg *msg)

	mutex_lock(&bus->msg_lock);

	ret = do_transfer(bus, msg);
	if (ret != 0 && ret != -ENODATA)
		dev_err(bus->dev, "trf on Slave %d failed:%d\n",
			msg->dev_num, ret);

	if (msg->page)
		sdw_reset_page(bus, msg->dev_num);
	ret = sdw_transfer_unlocked(bus, msg);

	mutex_unlock(&bus->msg_lock);

@@ -347,8 +362,8 @@ int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave,
		return -EINVAL;
	}

	msg->addr_page1 = (addr >> SDW_REG_SHIFT(SDW_SCP_ADDRPAGE1_MASK));
	msg->addr_page2 = (addr >> SDW_REG_SHIFT(SDW_SCP_ADDRPAGE2_MASK));
	msg->addr_page1 = FIELD_GET(SDW_SCP_ADDRPAGE1_MASK, addr);
	msg->addr_page2 = FIELD_GET(SDW_SCP_ADDRPAGE2_MASK, addr);
	msg->addr |= BIT(15);
	msg->page = true;

@@ -428,6 +443,39 @@ sdw_bwrite_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value)
	return sdw_transfer(bus, &msg);
}

int sdw_bread_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr)
{
	struct sdw_msg msg;
	u8 buf;
	int ret;

	ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num,
			   SDW_MSG_FLAG_READ, &buf);
	if (ret)
		return ret;

	ret = sdw_transfer_unlocked(bus, &msg);
	if (ret < 0)
		return ret;

	return buf;
}
EXPORT_SYMBOL(sdw_bread_no_pm_unlocked);

int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value)
{
	struct sdw_msg msg;
	int ret;

	ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num,
			   SDW_MSG_FLAG_WRITE, &value);
	if (ret)
		return ret;

	return sdw_transfer_unlocked(bus, &msg);
}
EXPORT_SYMBOL(sdw_bwrite_no_pm_unlocked);

static int
sdw_read_no_pm(struct sdw_slave *slave, u32 addr)
{
@@ -699,6 +747,15 @@ static int sdw_program_device_num(struct sdw_bus *bus)

		if (!found) {
			/* TODO: Park this device in Group 13 */

			/*
			 * add Slave device even if there is no platform
			 * firmware description. There will be no driver probe
			 * but the user/integration will be able to see the
			 * device, enumeration status and device number in sysfs
			 */
			sdw_slave_add(bus, &id, NULL);

			dev_err(bus->dev, "Slave Entry not found\n");
		}

@@ -1051,6 +1108,12 @@ int sdw_configure_dpn_intr(struct sdw_slave *slave,
	int ret;
	u8 val = 0;

	if (slave->bus->params.s_data_mode != SDW_PORT_DATA_MODE_NORMAL) {
		dev_dbg(&slave->dev, "TEST FAIL interrupt %s\n",
			enable ? "on" : "off");
		mask |= SDW_DPN_INT_TEST_FAIL;
	}

	addr = SDW_DPN_INTMASK(port);

	/* Set/Clear port ready interrupt mask */
@@ -1184,13 +1247,13 @@ static int sdw_initialize_slave(struct sdw_slave *slave)
		return ret;

	/*
	 * Set bus clash, parity and SCP implementation
	 * defined interrupt mask
	 * TODO: Read implementation defined interrupt mask
	 * from Slave property
	 * Set SCP_INT1_MASK register, typically bus clash and
	 * implementation-defined interrupt mask. The Parity detection
	 * may not always be correct on startup so its use is
	 * device-dependent, it might e.g. only be enabled in
	 * steady-state after a couple of frames.
	 */
	val = SDW_SCP_INT1_IMPL_DEF | SDW_SCP_INT1_BUS_CLASH |
					SDW_SCP_INT1_PARITY;
	val = slave->prop.scp_int1_mask;

	/* Enable SCP interrupts */
	ret = sdw_update(slave, SDW_SCP_INTMASK1, val, val);
@@ -1362,6 +1425,8 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
	unsigned long port;
	bool slave_notify = false;
	u8 buf, buf2[2], _buf, _buf2[2];
	bool parity_check;
	bool parity_quirk;

	sdw_modify_slave_status(slave, SDW_SLAVE_ALERT);

@@ -1394,12 +1459,18 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
		 * interrupt
		 */
		if (buf & SDW_SCP_INT1_PARITY) {
			parity_check = slave->prop.scp_int1_mask & SDW_SCP_INT1_PARITY;
			parity_quirk = !slave->first_interrupt_done &&
				(slave->prop.quirks & SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY);

			if (parity_check && !parity_quirk)
				dev_err(&slave->dev, "Parity error detected\n");
			clear |= SDW_SCP_INT1_PARITY;
		}

		if (buf & SDW_SCP_INT1_BUS_CLASH) {
			dev_err(&slave->dev, "Bus clash error detected\n");
			if (slave->prop.scp_int1_mask & SDW_SCP_INT1_BUS_CLASH)
				dev_err(&slave->dev, "Bus clash detected\n");
			clear |= SDW_SCP_INT1_BUS_CLASH;
		}

@@ -1411,16 +1482,18 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
		 */

		if (buf & SDW_SCP_INT1_IMPL_DEF) {
			if (slave->prop.scp_int1_mask & SDW_SCP_INT1_IMPL_DEF) {
				dev_dbg(&slave->dev, "Slave impl defined interrupt\n");
			clear |= SDW_SCP_INT1_IMPL_DEF;
				slave_notify = true;
			}
			clear |= SDW_SCP_INT1_IMPL_DEF;
		}

		/* Check port 0 - 3 interrupts */
		port = buf & SDW_SCP_INT1_PORT0_3;

		/* To get port number corresponding to bits, shift it */
		port = port >> SDW_REG_SHIFT(SDW_SCP_INT1_PORT0_3);
		port = FIELD_GET(SDW_SCP_INT1_PORT0_3, port);
		for_each_set_bit(bit, &port, 8) {
			sdw_handle_port_interrupt(slave, bit,
						  &port_status[bit]);
@@ -1468,6 +1541,9 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
			goto io_err;
		}

		/* at this point all initial interrupt sources were handled */
		slave->first_interrupt_done = true;

		/*
		 * Read status again to ensure no new interrupts arrived
		 * while servicing interrupts.
@@ -1670,8 +1746,10 @@ void sdw_clear_slave_status(struct sdw_bus *bus, u32 request)
		if (!slave)
			continue;

		if (slave->status != SDW_SLAVE_UNATTACHED)
		if (slave->status != SDW_SLAVE_UNATTACHED) {
			sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED);
			slave->first_interrupt_done = false;
		}

		/* keep track of request, used in pm_runtime resume */
		slave->unattach_request = request;
Loading