Commit 595fa4e3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull soundwire updates from Vinod Koul:
 "This is a small update which features a bit of core changes and driver
  updates in Intel and cadence driver.

  Core:

   - sdw_transfer_defer() API change to drop an argument

   - Reset page address rework

   - Export sdw_nwrite_no_pm and sdw_nread_no_pm APIs

  Drivers:

   - Cadence and related intel driver updates for FIFO handling and low
     level msg transfers"

* tag 'soundwire-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire:
  soundwire: cadence: further simplify low-level xfer_msg_defer() callback
  soundwire: cadence: use directly bus sdw_defer structure
  soundwire: bus: remove sdw_defer argument in sdw_transfer_defer()
  soundwire: stream: use consistent pattern for freeing buffers
  soundwire: bus: Remove unused reset_page_addr() callback
  soundwire: bus: Don't zero page registers after every transaction
  soundwire: bus_type: Avoid lockdep assert in sdw_drv_probe()
  soundwire: stream: Move remaining register accesses over to no_pm
  soundwire: debugfs: Switch to sdw_read_no_pm
  soundwire: Provide build stubs for common functions
  soundwire: bus: export sdw_nwrite_no_pm and sdw_nread_no_pm functions
  soundwire: cadence: remove unused sdw_cdns_master_ops declaration
  soundwire: enable optional clock registers for SoundWire 1.2 devices
  ASoC/soundwire: remove is_sdca boolean property
  soundwire: cadence: Drain the RX FIFO after an IO timeout
  soundwire: cadence: Remove wasted space in response_buf
  soundwire: cadence: Don't overflow the command FIFOs
  soundwire: intel: remove DAI startup/shutdown
parents 8ff99ad0 66f95de7
Loading
Loading
Loading
Loading
+16 −40
Original line number Original line Diff line number Diff line
@@ -225,9 +225,9 @@ static inline int do_transfer(struct sdw_bus *bus, struct sdw_msg *msg)
}
}


static inline int do_transfer_defer(struct sdw_bus *bus,
static inline int do_transfer_defer(struct sdw_bus *bus,
				    struct sdw_msg *msg,
				    struct sdw_msg *msg)
				    struct sdw_defer *defer)
{
{
	struct sdw_defer *defer = &bus->defer_msg;
	int retry = bus->prop.err_threshold;
	int retry = bus->prop.err_threshold;
	enum sdw_command_response resp;
	enum sdw_command_response resp;
	int ret = 0, i;
	int ret = 0, i;
@@ -237,24 +237,7 @@ static inline int do_transfer_defer(struct sdw_bus *bus,
	init_completion(&defer->complete);
	init_completion(&defer->complete);


	for (i = 0; i <= retry; i++) {
	for (i = 0; i <= retry; i++) {
		resp = bus->ops->xfer_msg_defer(bus, msg, defer);
		resp = bus->ops->xfer_msg_defer(bus);
		ret = find_response_code(resp);
		/* if cmd is ok or ignored return */
		if (ret == 0 || ret == -ENODATA)
			return ret;
	}

	return ret;
}

static int sdw_reset_page(struct sdw_bus *bus, u16 dev_num)
{
	int retry = bus->prop.err_threshold;
	enum sdw_command_response resp;
	int ret = 0, i;

	for (i = 0; i <= retry; i++) {
		resp = bus->ops->reset_page_addr(bus, dev_num);
		ret = find_response_code(resp);
		ret = find_response_code(resp);
		/* if cmd is ok or ignored return */
		/* if cmd is ok or ignored return */
		if (ret == 0 || ret == -ENODATA)
		if (ret == 0 || ret == -ENODATA)
@@ -275,9 +258,6 @@ static int sdw_transfer_unlocked(struct sdw_bus *bus, struct sdw_msg *msg)
			(msg->flags & SDW_MSG_FLAG_WRITE) ? "write" : "read",
			(msg->flags & SDW_MSG_FLAG_WRITE) ? "write" : "read",
			msg->addr, msg->len);
			msg->addr, msg->len);


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

	return ret;
	return ret;
}
}


@@ -335,26 +315,21 @@ EXPORT_SYMBOL(sdw_show_ping_status);
 * sdw_transfer_defer() - Asynchronously transfer message to a SDW Slave device
 * sdw_transfer_defer() - Asynchronously transfer message to a SDW Slave device
 * @bus: SDW bus
 * @bus: SDW bus
 * @msg: SDW message to be xfered
 * @msg: SDW message to be xfered
 * @defer: Defer block for signal completion
 *
 *
 * Caller needs to hold the msg_lock lock while calling this
 * Caller needs to hold the msg_lock lock while calling this
 */
 */
int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg,
int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg)
		       struct sdw_defer *defer)
{
{
	int ret;
	int ret;


	if (!bus->ops->xfer_msg_defer)
	if (!bus->ops->xfer_msg_defer)
		return -ENOTSUPP;
		return -ENOTSUPP;


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


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

	return ret;
	return ret;
}
}


@@ -414,8 +389,7 @@ int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave,
 * all clients need to use the pm versions
 * all clients need to use the pm versions
 */
 */


static int
int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
{
{
	struct sdw_msg msg;
	struct sdw_msg msg;
	int ret;
	int ret;
@@ -430,9 +404,9 @@ sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
		ret = 0;
		ret = 0;
	return ret;
	return ret;
}
}
EXPORT_SYMBOL(sdw_nread_no_pm);


static int
int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
{
{
	struct sdw_msg msg;
	struct sdw_msg msg;
	int ret;
	int ret;
@@ -447,6 +421,7 @@ sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
		ret = 0;
		ret = 0;
	return ret;
	return ret;
}
}
EXPORT_SYMBOL(sdw_nwrite_no_pm);


int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value)
int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value)
{
{
@@ -1214,7 +1189,7 @@ int sdw_configure_dpn_intr(struct sdw_slave *slave,
		val &= ~SDW_DPN_INT_PORT_READY;
		val &= ~SDW_DPN_INT_PORT_READY;
	}
	}


	ret = sdw_update(slave, addr, (mask | SDW_DPN_INT_PORT_READY), val);
	ret = sdw_update_no_pm(slave, addr, (mask | SDW_DPN_INT_PORT_READY), val);
	if (ret < 0)
	if (ret < 0)
		dev_err(&slave->dev,
		dev_err(&slave->dev,
			"SDW_DPN_INTMASK write failed:%d\n", val);
			"SDW_DPN_INTMASK write failed:%d\n", val);
@@ -1233,10 +1208,11 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave)


	/*
	/*
	 * frequency base and scale registers are required for SDCA
	 * frequency base and scale registers are required for SDCA
	 * devices. They may also be used for 1.2+/non-SDCA devices,
	 * devices. They may also be used for 1.2+/non-SDCA devices.
	 * but we will need a DisCo property to cover this case
	 * Driver can set the property, we will need a DisCo property
	 * to discover this case from platform firmware.
	 */
	 */
	if (!slave->id.class_id)
	if (!slave->id.class_id && !slave->prop.clock_reg_supported)
		return 0;
		return 0;


	if (!mclk_freq) {
	if (!mclk_freq) {
@@ -1587,7 +1563,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
		goto io_err;
		goto io_err;
	}
	}


	if (slave->prop.is_sdca) {
	if (slave->id.class_id) {
		ret = sdw_read_no_pm(slave, SDW_DP0_INT);
		ret = sdw_read_no_pm(slave, SDW_DP0_INT);
		if (ret < 0) {
		if (ret < 0) {
			dev_err(&slave->dev,
			dev_err(&slave->dev,
@@ -1724,7 +1700,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
			goto io_err;
			goto io_err;
		}
		}


		if (slave->prop.is_sdca) {
		if (slave->id.class_id) {
			ret = sdw_read_no_pm(slave, SDW_DP0_INT);
			ret = sdw_read_no_pm(slave, SDW_DP0_INT);
			if (ret < 0) {
			if (ret < 0) {
				dev_err(&slave->dev,
				dev_err(&slave->dev,
+1 −2
Original line number Original line Diff line number Diff line
@@ -151,8 +151,7 @@ int sdw_configure_dpn_intr(struct sdw_slave *slave, int port,
			   bool enable, int mask);
			   bool enable, int mask);


int sdw_transfer(struct sdw_bus *bus, struct sdw_msg *msg);
int sdw_transfer(struct sdw_bus *bus, struct sdw_msg *msg);
int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg,
int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg);
		       struct sdw_defer *defer);


#define SDW_READ_INTR_CLEAR_RETRY	10
#define SDW_READ_INTR_CLEAR_RETRY	10


+3 −6
Original line number Original line Diff line number Diff line
@@ -105,20 +105,19 @@ static int sdw_drv_probe(struct device *dev)
	if (ret)
	if (ret)
		return ret;
		return ret;


	mutex_lock(&slave->sdw_dev_lock);

	ret = drv->probe(slave, id);
	ret = drv->probe(slave, id);
	if (ret) {
	if (ret) {
		name = drv->name;
		name = drv->name;
		if (!name)
		if (!name)
			name = drv->driver.name;
			name = drv->driver.name;
		mutex_unlock(&slave->sdw_dev_lock);


		dev_err(dev, "Probe of %s failed: %d\n", name, ret);
		dev_err(dev, "Probe of %s failed: %d\n", name, ret);
		dev_pm_domain_detach(dev, false);
		dev_pm_domain_detach(dev, false);
		return ret;
		return ret;
	}
	}


	mutex_lock(&slave->sdw_dev_lock);

	/* device is probed so let's read the properties now */
	/* device is probed so let's read the properties now */
	if (drv->ops && drv->ops->read_prop)
	if (drv->ops && drv->ops->read_prop)
		drv->ops->read_prop(slave);
		drv->ops->read_prop(slave);
@@ -167,14 +166,12 @@ static int sdw_drv_remove(struct device *dev)
	int ret = 0;
	int ret = 0;


	mutex_lock(&slave->sdw_dev_lock);
	mutex_lock(&slave->sdw_dev_lock);

	slave->probed = false;
	slave->probed = false;
	mutex_unlock(&slave->sdw_dev_lock);


	if (drv->remove)
	if (drv->remove)
		ret = drv->remove(slave);
		ret = drv->remove(slave);


	mutex_unlock(&slave->sdw_dev_lock);

	dev_pm_domain_detach(dev, false);
	dev_pm_domain_detach(dev, false);


	return ret;
	return ret;
+39 −41
Original line number Original line Diff line number Diff line
@@ -127,7 +127,8 @@ MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask");


#define CDNS_MCP_CMD_BASE			0x80
#define CDNS_MCP_CMD_BASE			0x80
#define CDNS_MCP_RESP_BASE			0x80
#define CDNS_MCP_RESP_BASE			0x80
#define CDNS_MCP_CMD_LEN			0x20
/* FIFO can hold 8 commands */
#define CDNS_MCP_CMD_LEN			8
#define CDNS_MCP_CMD_WORD_LEN			0x4
#define CDNS_MCP_CMD_WORD_LEN			0x4


#define CDNS_MCP_CMD_SSP_TAG			BIT(31)
#define CDNS_MCP_CMD_SSP_TAG			BIT(31)
@@ -554,6 +555,29 @@ cdns_fill_msg_resp(struct sdw_cdns *cdns,
	return SDW_CMD_OK;
	return SDW_CMD_OK;
}
}


static void cdns_read_response(struct sdw_cdns *cdns)
{
	u32 num_resp, cmd_base;
	int i;

	/* RX_FIFO_AVAIL can be 2 entries more than the FIFO size */
	BUILD_BUG_ON(ARRAY_SIZE(cdns->response_buf) < CDNS_MCP_CMD_LEN + 2);

	num_resp = cdns_readl(cdns, CDNS_MCP_FIFOSTAT);
	num_resp &= CDNS_MCP_RX_FIFO_AVAIL;
	if (num_resp > ARRAY_SIZE(cdns->response_buf)) {
		dev_warn(cdns->dev, "RX AVAIL %d too long\n", num_resp);
		num_resp = ARRAY_SIZE(cdns->response_buf);
	}

	cmd_base = CDNS_MCP_CMD_BASE;

	for (i = 0; i < num_resp; i++) {
		cdns->response_buf[i] = cdns_readl(cdns, cmd_base);
		cmd_base += CDNS_MCP_CMD_WORD_LEN;
	}
}

static enum sdw_command_response
static enum sdw_command_response
_cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,
_cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,
	       int offset, int count, bool defer)
	       int offset, int count, bool defer)
@@ -595,6 +619,10 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,
		dev_err(cdns->dev, "IO transfer timed out, cmd %d device %d addr %x len %d\n",
		dev_err(cdns->dev, "IO transfer timed out, cmd %d device %d addr %x len %d\n",
			cmd, msg->dev_num, msg->addr, msg->len);
			cmd, msg->dev_num, msg->addr, msg->len);
		msg->len = 0;
		msg->len = 0;

		/* Drain anything in the RX_FIFO */
		cdns_read_response(cdns);

		return SDW_CMD_TIMEOUT;
		return SDW_CMD_TIMEOUT;
	}
	}


@@ -721,10 +749,11 @@ cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg)
EXPORT_SYMBOL(cdns_xfer_msg);
EXPORT_SYMBOL(cdns_xfer_msg);


enum sdw_command_response
enum sdw_command_response
cdns_xfer_msg_defer(struct sdw_bus *bus,
cdns_xfer_msg_defer(struct sdw_bus *bus)
		    struct sdw_msg *msg, struct sdw_defer *defer)
{
{
	struct sdw_cdns *cdns = bus_to_cdns(bus);
	struct sdw_cdns *cdns = bus_to_cdns(bus);
	struct sdw_defer *defer = &bus->defer_msg;
	struct sdw_msg *msg = defer->msg;
	int cmd = 0, ret;
	int cmd = 0, ret;


	/* for defer only 1 message is supported */
	/* for defer only 1 message is supported */
@@ -735,27 +764,10 @@ cdns_xfer_msg_defer(struct sdw_bus *bus,
	if (ret)
	if (ret)
		return SDW_CMD_FAIL_OTHER;
		return SDW_CMD_FAIL_OTHER;


	cdns->defer = defer;
	cdns->defer->length = msg->len;

	return _cdns_xfer_msg(cdns, msg, cmd, 0, msg->len, true);
	return _cdns_xfer_msg(cdns, msg, cmd, 0, msg->len, true);
}
}
EXPORT_SYMBOL(cdns_xfer_msg_defer);
EXPORT_SYMBOL(cdns_xfer_msg_defer);


enum sdw_command_response
cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num)
{
	struct sdw_cdns *cdns = bus_to_cdns(bus);
	struct sdw_msg msg;

	/* Create dummy message with valid device number */
	memset(&msg, 0, sizeof(msg));
	msg.dev_num = dev_num;

	return cdns_program_scp_addr(cdns, &msg);
}
EXPORT_SYMBOL(cdns_reset_page_addr);

u32 cdns_read_ping_status(struct sdw_bus *bus)
u32 cdns_read_ping_status(struct sdw_bus *bus)
{
{
	struct sdw_cdns *cdns = bus_to_cdns(bus);
	struct sdw_cdns *cdns = bus_to_cdns(bus);
@@ -768,22 +780,6 @@ EXPORT_SYMBOL(cdns_read_ping_status);
 * IRQ handling
 * IRQ handling
 */
 */


static void cdns_read_response(struct sdw_cdns *cdns)
{
	u32 num_resp, cmd_base;
	int i;

	num_resp = cdns_readl(cdns, CDNS_MCP_FIFOSTAT);
	num_resp &= CDNS_MCP_RX_FIFO_AVAIL;

	cmd_base = CDNS_MCP_CMD_BASE;

	for (i = 0; i < num_resp; i++) {
		cdns->response_buf[i] = cdns_readl(cdns, cmd_base);
		cmd_base += CDNS_MCP_CMD_WORD_LEN;
	}
}

static int cdns_update_slave_status(struct sdw_cdns *cdns,
static int cdns_update_slave_status(struct sdw_cdns *cdns,
				    u64 slave_intstat)
				    u64 slave_intstat)
{
{
@@ -881,13 +877,15 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
		return IRQ_NONE;
		return IRQ_NONE;


	if (int_status & CDNS_MCP_INT_RX_WL) {
	if (int_status & CDNS_MCP_INT_RX_WL) {
		struct sdw_bus *bus = &cdns->bus;
		struct sdw_defer *defer = &bus->defer_msg;

		cdns_read_response(cdns);
		cdns_read_response(cdns);


		if (cdns->defer) {
		if (defer && defer->msg) {
			cdns_fill_msg_resp(cdns, cdns->defer->msg,
			cdns_fill_msg_resp(cdns, defer->msg,
					   cdns->defer->length, 0);
					   defer->length, 0);
			complete(&cdns->defer->complete);
			complete(&defer->complete);
			cdns->defer = NULL;
		} else {
		} else {
			complete(&cdns->tx_complete);
			complete(&cdns->tx_complete);
		}
		}
+13 −9
Original line number Original line Diff line number Diff line
@@ -8,6 +8,12 @@
#define SDW_CADENCE_GSYNC_KHZ		4 /* 4 kHz */
#define SDW_CADENCE_GSYNC_KHZ		4 /* 4 kHz */
#define SDW_CADENCE_GSYNC_HZ		(SDW_CADENCE_GSYNC_KHZ * 1000)
#define SDW_CADENCE_GSYNC_HZ		(SDW_CADENCE_GSYNC_KHZ * 1000)


/*
 * The Cadence IP supports up to 32 entries in the FIFO, though implementations
 * can configure the IP to have a smaller FIFO.
 */
#define CDNS_MCP_IP_MAX_CMD_LEN		32

/**
/**
 * struct sdw_cdns_pdi: PDI (Physical Data Interface) instance
 * struct sdw_cdns_pdi: PDI (Physical Data Interface) instance
 *
 *
@@ -103,7 +109,6 @@ struct sdw_cdns_dai_runtime {
 * @instance: instance number
 * @instance: instance number
 * @response_buf: SoundWire response buffer
 * @response_buf: SoundWire response buffer
 * @tx_complete: Tx completion
 * @tx_complete: Tx completion
 * @defer: Defer pointer
 * @ports: Data ports
 * @ports: Data ports
 * @num_ports: Total number of data ports
 * @num_ports: Total number of data ports
 * @pcm: PCM streams
 * @pcm: PCM streams
@@ -117,9 +122,13 @@ struct sdw_cdns {
	struct sdw_bus bus;
	struct sdw_bus bus;
	unsigned int instance;
	unsigned int instance;


	u32 response_buf[0x80];
	/*
	 * The datasheet says the RX FIFO AVAIL can be 2 entries more
	 * than the FIFO capacity, so allow for this.
	 */
	u32 response_buf[CDNS_MCP_IP_MAX_CMD_LEN + 2];

	struct completion tx_complete;
	struct completion tx_complete;
	struct sdw_defer *defer;


	struct sdw_cdns_port *ports;
	struct sdw_cdns_port *ports;
	int num_ports;
	int num_ports;
@@ -147,7 +156,6 @@ struct sdw_cdns {
/* Exported symbols */
/* Exported symbols */


int sdw_cdns_probe(struct sdw_cdns *cdns);
int sdw_cdns_probe(struct sdw_cdns *cdns);
extern struct sdw_master_ops sdw_cdns_master_ops;


irqreturn_t sdw_cdns_irq(int irq, void *dev_id);
irqreturn_t sdw_cdns_irq(int irq, void *dev_id);
irqreturn_t sdw_cdns_thread(int irq, void *dev_id);
irqreturn_t sdw_cdns_thread(int irq, void *dev_id);
@@ -172,15 +180,11 @@ struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns,
void sdw_cdns_config_stream(struct sdw_cdns *cdns,
void sdw_cdns_config_stream(struct sdw_cdns *cdns,
			    u32 ch, u32 dir, struct sdw_cdns_pdi *pdi);
			    u32 ch, u32 dir, struct sdw_cdns_pdi *pdi);


enum sdw_command_response
cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num);

enum sdw_command_response
enum sdw_command_response
cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg);
cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg);


enum sdw_command_response
enum sdw_command_response
cdns_xfer_msg_defer(struct sdw_bus *bus,
cdns_xfer_msg_defer(struct sdw_bus *bus);
		    struct sdw_msg *msg, struct sdw_defer *defer);


u32 cdns_read_ping_status(struct sdw_bus *bus);
u32 cdns_read_ping_status(struct sdw_bus *bus);


Loading