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

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

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

Vinod writes:

soundwire updates for v5.5-rc1

This round we have bunch of core and Intel driver updates spearheaded
by Pierre

Details
 - Update unique id checks in core and ACPI helpers
 - Improvements to to Intel driver and cadence lib

* tag 'soundwire-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire:
  soundwire: ignore uniqueID when irrelevant
  soundwire: slave: add helper to extract slave ID
  soundwire: remove bitfield for unique_id, use u8
  soundwire: intel: fix PDI/stream mapping for Bulk
  soundwire: cadence_master: make clock stop exit configurable on init
  soundwire: intel/cadence: add flag for interrupt enable
  soundwire: intel: add helper for initialization
  soundwire: cadence_master: add hw_reset capability in debugfs
  soundwire: intel/cadence: fix startup sequence
  soundwire: intel: use correct header for io calls
  soundwire: cadence_master: improve PDI allocation
  soundwire: intel: don't filter out PDI0/1
  soundwire: cadence/intel: simplify PDI/port mapping
  soundwire: intel: remove playback/capture stream_name
  soundwire: remove DAI_ID_RANGE definitions
  soundwire: intel: remove X86 dependency
  soundwire: intel: add missing headers for cross-compilation
parents bce92136 2e8c4ad1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ config SOUNDWIRE_CADENCE
config SOUNDWIRE_INTEL
	tristate "Intel SoundWire Master driver"
	select SOUNDWIRE_CADENCE
	depends on X86 && ACPI && SND_SOC
	depends on ACPI && SND_SOC
	help
	  SoundWire Intel Master driver.
	  If you have an Intel platform which has a SoundWire Master then
+4 −3
Original line number Diff line number Diff line
@@ -422,10 +422,11 @@ static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, int i)

static int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id)
{
	if (slave->id.unique_id != id.unique_id ||
	    slave->id.mfg_id != id.mfg_id ||
	if (slave->id.mfg_id != id.mfg_id ||
	    slave->id.part_id != id.part_id ||
	    slave->id.class_id != id.class_id)
	    slave->id.class_id != id.class_id ||
	    (slave->id.unique_id != SDW_IGNORED_UNIQUE_ID &&
	     slave->id.unique_id != id.unique_id))
		return -ENODEV;

	return 0;
+135 −157
Original line number Diff line number Diff line
@@ -183,9 +183,6 @@ MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask");
#define CDNS_DEFAULT_SSP_INTERVAL		0x18
#define CDNS_TX_TIMEOUT				2000

#define CDNS_PCM_PDI_OFFSET			0x2
#define CDNS_PDM_PDI_OFFSET			0x6

#define CDNS_SCP_RX_FIFOLEVEL			0x2

/*
@@ -231,6 +228,22 @@ static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value)
	return -EAGAIN;
}

/*
 * all changes to the MCP_CONFIG, MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL
 * need to be confirmed with a write to MCP_CONFIG_UPDATE
 */
static int cdns_update_config(struct sdw_cdns *cdns)
{
	int ret;

	ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
			     CDNS_MCP_CONFIG_UPDATE_BIT);
	if (ret < 0)
		dev_err(cdns->dev, "Config update timedout\n");

	return ret;
}

/*
 * debugfs
 */
@@ -279,11 +292,7 @@ static int cdns_reg_show(struct seq_file *s, void *data)
	ret += scnprintf(buf + ret, RD_BUF - ret,
			 "\nDPn B0 Registers\n");

	/*
	 * in sdw_cdns_pdi_init() we filter out the Bulk PDIs,
	 * so the indices need to be corrected again
	 */
	num_ports = cdns->num_ports + CDNS_PCM_PDI_OFFSET;
	num_ports = cdns->num_ports;

	for (i = 0; i < num_ports; i++) {
		ret += scnprintf(buf + ret, RD_BUF - ret,
@@ -324,6 +333,26 @@ static int cdns_reg_show(struct seq_file *s, void *data)
}
DEFINE_SHOW_ATTRIBUTE(cdns_reg);

static int cdns_hw_reset(void *data, u64 value)
{
	struct sdw_cdns *cdns = data;
	int ret;

	if (value != 1)
		return -EINVAL;

	/* Userspace changed the hardware state behind the kernel's back */
	add_taint(TAINT_USER, LOCKDEP_STILL_OK);

	ret = sdw_cdns_exit_reset(cdns);

	dev_dbg(cdns->dev, "link hw_reset done: %d\n", ret);

	return ret;
}

DEFINE_DEBUGFS_ATTRIBUTE(cdns_hw_reset_fops, NULL, cdns_hw_reset, "%llu\n");

/**
 * sdw_cdns_debugfs_init() - Cadence debugfs init
 * @cdns: Cadence instance
@@ -332,6 +361,9 @@ DEFINE_SHOW_ATTRIBUTE(cdns_reg);
void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root)
{
	debugfs_create_file("cdns-registers", 0400, root, cdns, &cdns_reg_fops);

	debugfs_create_file("cdns-hw-reset", 0200, root, cdns,
			    &cdns_hw_reset_fops);
}
EXPORT_SYMBOL_GPL(sdw_cdns_debugfs_init);

@@ -752,14 +784,48 @@ EXPORT_SYMBOL(sdw_cdns_thread);
/*
 * init routines
 */
static int _cdns_enable_interrupt(struct sdw_cdns *cdns)

/**
 * sdw_cdns_exit_reset() - Program reset parameters and start bus operations
 * @cdns: Cadence instance
 */
int sdw_cdns_exit_reset(struct sdw_cdns *cdns)
{
	u32 mask;
	/* program maximum length reset to be safe */
	cdns_updatel(cdns, CDNS_MCP_CONTROL,
		     CDNS_MCP_CONTROL_RST_DELAY,
		     CDNS_MCP_CONTROL_RST_DELAY);

	/* use hardware generated reset */
	cdns_updatel(cdns, CDNS_MCP_CONTROL,
		     CDNS_MCP_CONTROL_HW_RST,
		     CDNS_MCP_CONTROL_HW_RST);

	/* enable bus operations with clock and data */
	cdns_updatel(cdns, CDNS_MCP_CONFIG,
		     CDNS_MCP_CONFIG_OP,
		     CDNS_MCP_CONFIG_OP_NORMAL);

	/* commit changes */
	return cdns_update_config(cdns);
}
EXPORT_SYMBOL(sdw_cdns_exit_reset);

/**
 * sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
 * @cdns: Cadence instance
 */
int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state)
{
	u32 slave_intmask0 = 0;
	u32 slave_intmask1 = 0;
	u32 mask = 0;

	if (!state)
		goto update_masks;

	cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0,
		    CDNS_MCP_SLAVE_INTMASK0_MASK);
	cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1,
		    CDNS_MCP_SLAVE_INTMASK1_MASK);
	slave_intmask0 = CDNS_MCP_SLAVE_INTMASK0_MASK;
	slave_intmask1 = CDNS_MCP_SLAVE_INTMASK1_MASK;

	/* enable detection of all slave state changes */
	mask = CDNS_MCP_INT_SLAVE_MASK;
@@ -782,26 +848,13 @@ static int _cdns_enable_interrupt(struct sdw_cdns *cdns)
	if (interrupt_mask) /* parameter override */
		mask = interrupt_mask;

update_masks:
	cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0, slave_intmask0);
	cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1, slave_intmask1);
	cdns_writel(cdns, CDNS_MCP_INTMASK, mask);

	return 0;
}

/**
 * sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
 * @cdns: Cadence instance
 */
int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
{
	int ret;

	_cdns_enable_interrupt(cdns);
	ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
			     CDNS_MCP_CONFIG_UPDATE_BIT);
	if (ret < 0)
		dev_err(cdns->dev, "Config update timedout\n");

	return ret;
	/* commit changes */
	return cdns_update_config(cdns);
}
EXPORT_SYMBOL(sdw_cdns_enable_interrupt);

@@ -821,7 +874,6 @@ static int cdns_allocate_pdi(struct sdw_cdns *cdns,

	for (i = 0; i < num; i++) {
		pdi[i].num = i + pdi_offset;
		pdi[i].assigned = false;
	}

	*stream = pdi;
@@ -838,7 +890,8 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
		      struct sdw_cdns_stream_config config)
{
	struct sdw_cdns_streams *stream;
	int offset, i, ret;
	int offset;
	int ret;

	cdns->pcm.num_bd = config.pcm_bd;
	cdns->pcm.num_in = config.pcm_in;
@@ -850,11 +903,8 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
	/* Allocate PDIs for PCMs */
	stream = &cdns->pcm;

	/* First two PDIs are reserved for bulk transfers */
	if (stream->num_bd < CDNS_PCM_PDI_OFFSET)
		return -EINVAL;
	stream->num_bd -= CDNS_PCM_PDI_OFFSET;
	offset = CDNS_PCM_PDI_OFFSET;
	/* we allocate PDI0 and PDI1 which are used for Bulk */
	offset = 0;

	ret = cdns_allocate_pdi(cdns, &stream->bd,
				stream->num_bd, offset);
@@ -881,7 +931,6 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,

	/* Allocate PDIs for PDMs */
	stream = &cdns->pdm;
	offset = CDNS_PDM_PDI_OFFSET;
	ret = cdns_allocate_pdi(cdns, &stream->bd,
				stream->num_bd, offset);
	if (ret)
@@ -898,6 +947,9 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,

	ret = cdns_allocate_pdi(cdns, &stream->out,
				stream->num_out, offset);

	offset += stream->num_out;

	if (ret)
		return ret;

@@ -905,18 +957,6 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
	stream->num_pdi = stream->num_bd + stream->num_in + stream->num_out;
	cdns->num_ports += stream->num_pdi;

	cdns->ports = devm_kcalloc(cdns->dev, cdns->num_ports,
				   sizeof(*cdns->ports), GFP_KERNEL);
	if (!cdns->ports) {
		ret = -ENOMEM;
		return ret;
	}

	for (i = 0; i < cdns->num_ports; i++) {
		cdns->ports[i].assigned = false;
		cdns->ports[i].num = i + 1; /* Port 0 reserved for bulk */
	}

	return 0;
}
EXPORT_SYMBOL(sdw_cdns_pdi_init);
@@ -939,7 +979,7 @@ static u32 cdns_set_initial_frame_shape(int n_rows, int n_cols)
 * sdw_cdns_init() - Cadence initialization
 * @cdns: Cadence instance
 */
int sdw_cdns_init(struct sdw_cdns *cdns)
int sdw_cdns_init(struct sdw_cdns *cdns, bool clock_stop_exit)
{
	struct sdw_bus *bus = &cdns->bus;
	struct sdw_master_prop *prop = &bus->prop;
@@ -947,13 +987,14 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
	int divider;
	int ret;

	/* Exit clock stop */
	if (clock_stop_exit) {
		ret = cdns_clear_bit(cdns, CDNS_MCP_CONTROL,
				     CDNS_MCP_CONTROL_CLK_STOP_CLR);
		if (ret < 0) {
			dev_err(cdns->dev, "Couldn't exit from clock stop\n");
			return ret;
		}
	}

	/* Set clock divider */
	divider	= (prop->mclk_freq / prop->max_clk_freq) - 1;
@@ -975,6 +1016,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
	cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, CDNS_DEFAULT_SSP_INTERVAL);
	cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, CDNS_DEFAULT_SSP_INTERVAL);

	/* flush command FIFOs */
	cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_RST,
		     CDNS_MCP_CONTROL_CMD_RST);

	/* Set cmd accept mode */
	cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT,
		     CDNS_MCP_CONTROL_CMD_ACCEPT);
@@ -997,13 +1042,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
	/* Set cmd mode for Tx and Rx cmds */
	val &= ~CDNS_MCP_CONFIG_CMD;

	/* Set operation to normal */
	val &= ~CDNS_MCP_CONFIG_OP;
	val |= CDNS_MCP_CONFIG_OP_NORMAL;

	cdns_writel(cdns, CDNS_MCP_CONFIG, val);

	return 0;
	/* commit changes */
	return cdns_update_config(cdns);
}
EXPORT_SYMBOL(sdw_cdns_init);

@@ -1185,20 +1227,20 @@ EXPORT_SYMBOL(cdns_set_sdw_stream);
 * @num: Number of PDIs
 * @pdi: PDI instances
 *
 * Find and return a free PDI for a given PDI array
 * Find a PDI for a given PDI array. The PDI num and dai_id are
 * expected to match, return NULL otherwise.
 */
static struct sdw_cdns_pdi *cdns_find_pdi(struct sdw_cdns *cdns,
					  unsigned int offset,
					  unsigned int num,
					  struct sdw_cdns_pdi *pdi)
					  struct sdw_cdns_pdi *pdi,
					  int dai_id)
{
	int i;

	for (i = 0; i < num; i++) {
		if (pdi[i].assigned)
			continue;
		pdi[i].assigned = true;
	for (i = offset; i < offset + num; i++)
		if (pdi[i].num == dai_id)
			return &pdi[i];
	}

	return NULL;
}
@@ -1207,13 +1249,11 @@ static struct sdw_cdns_pdi *cdns_find_pdi(struct sdw_cdns *cdns,
 * sdw_cdns_config_stream: Configure a stream
 *
 * @cdns: Cadence instance
 * @port: Cadence data port
 * @ch: Channel count
 * @dir: Data direction
 * @pdi: PDI to be used
 */
void sdw_cdns_config_stream(struct sdw_cdns *cdns,
			    struct sdw_cdns_port *port,
			    u32 ch, u32 dir, struct sdw_cdns_pdi *pdi)
{
	u32 offset, val = 0;
@@ -1221,113 +1261,51 @@ void sdw_cdns_config_stream(struct sdw_cdns *cdns,
	if (dir == SDW_DATA_DIR_RX)
		val = CDNS_PORTCTRL_DIRN;

	offset = CDNS_PORTCTRL + port->num * CDNS_PORT_OFFSET;
	offset = CDNS_PORTCTRL + pdi->num * CDNS_PORT_OFFSET;
	cdns_updatel(cdns, offset, CDNS_PORTCTRL_DIRN, val);

	val = port->num;
	val = pdi->num;
	val |= ((1 << ch) - 1) << SDW_REG_SHIFT(CDNS_PDI_CONFIG_CHANNEL);
	cdns_writel(cdns, CDNS_PDI_CONFIG(pdi->num), val);
}
EXPORT_SYMBOL(sdw_cdns_config_stream);

/**
 * cdns_get_num_pdi() - Get number of PDIs required
 *
 * @cdns: Cadence instance
 * @pdi: PDI to be used
 * @num: Number of PDIs
 * @ch_count: Channel count
 */
static int cdns_get_num_pdi(struct sdw_cdns *cdns,
			    struct sdw_cdns_pdi *pdi,
			    unsigned int num, u32 ch_count)
{
	int i, pdis = 0;

	for (i = 0; i < num; i++) {
		if (pdi[i].assigned)
			continue;

		if (pdi[i].ch_count < ch_count)
			ch_count -= pdi[i].ch_count;
		else
			ch_count = 0;

		pdis++;

		if (!ch_count)
			break;
	}

	if (ch_count)
		return 0;

	return pdis;
}

/**
 * sdw_cdns_get_stream() - Get stream information
 *
 * @cdns: Cadence instance
 * @stream: Stream to be allocated
 * @ch: Channel count
 * @dir: Data direction
 */
int sdw_cdns_get_stream(struct sdw_cdns *cdns,
			struct sdw_cdns_streams *stream,
			u32 ch, u32 dir)
{
	int pdis = 0;

	if (dir == SDW_DATA_DIR_RX)
		pdis = cdns_get_num_pdi(cdns, stream->in, stream->num_in, ch);
	else
		pdis = cdns_get_num_pdi(cdns, stream->out, stream->num_out, ch);

	/* check if we found PDI, else find in bi-directional */
	if (!pdis)
		pdis = cdns_get_num_pdi(cdns, stream->bd, stream->num_bd, ch);

	return pdis;
}
EXPORT_SYMBOL(sdw_cdns_get_stream);

/**
 * sdw_cdns_alloc_stream() - Allocate a stream
 * sdw_cdns_alloc_pdi() - Allocate a PDI
 *
 * @cdns: Cadence instance
 * @stream: Stream to be allocated
 * @port: Cadence data port
 * @ch: Channel count
 * @dir: Data direction
 */
int sdw_cdns_alloc_stream(struct sdw_cdns *cdns,
struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns,
					struct sdw_cdns_streams *stream,
			  struct sdw_cdns_port *port, u32 ch, u32 dir)
					u32 ch, u32 dir, int dai_id)
{
	struct sdw_cdns_pdi *pdi = NULL;

	if (dir == SDW_DATA_DIR_RX)
		pdi = cdns_find_pdi(cdns, stream->num_in, stream->in);
		pdi = cdns_find_pdi(cdns, 0, stream->num_in, stream->in,
				    dai_id);
	else
		pdi = cdns_find_pdi(cdns, stream->num_out, stream->out);
		pdi = cdns_find_pdi(cdns, 0, stream->num_out, stream->out,
				    dai_id);

	/* check if we found a PDI, else find in bi-directional */
	if (!pdi)
		pdi = cdns_find_pdi(cdns, stream->num_bd, stream->bd);
		pdi = cdns_find_pdi(cdns, 2, stream->num_bd, stream->bd,
				    dai_id);

	if (!pdi)
		return -EIO;

	port->pdi = pdi;
	if (pdi) {
		pdi->l_ch_num = 0;
		pdi->h_ch_num = ch - 1;
		pdi->dir = dir;
		pdi->ch_count = ch;
	}

	return 0;
	return pdi;
}
EXPORT_SYMBOL(sdw_cdns_alloc_stream);
EXPORT_SYMBOL(sdw_cdns_alloc_pdi);

MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("Cadence Soundwire Library");
+10 −29
Original line number Diff line number Diff line
@@ -8,7 +8,6 @@
/**
 * struct sdw_cdns_pdi: PDI (Physical Data Interface) instance
 *
 * @assigned: pdi assigned
 * @num: pdi number
 * @intel_alh_id: link identifier
 * @l_ch_num: low channel for PDI
@@ -18,7 +17,6 @@
 * @type: stream type, PDM or PCM
 */
struct sdw_cdns_pdi {
	bool assigned;
	int num;
	int intel_alh_id;
	int l_ch_num;
@@ -28,23 +26,6 @@ struct sdw_cdns_pdi {
	enum sdw_stream_type type;
};

/**
 * struct sdw_cdns_port: Cadence port structure
 *
 * @num: port number
 * @assigned: port assigned
 * @ch: channel count
 * @direction: data port direction
 * @pdi: pdi for this port
 */
struct sdw_cdns_port {
	unsigned int num;
	bool assigned;
	unsigned int ch;
	enum sdw_data_direction direction;
	struct sdw_cdns_pdi *pdi;
};

/**
 * struct sdw_cdns_streams: Cadence stream data structure
 *
@@ -95,8 +76,8 @@ struct sdw_cdns_stream_config {
 * struct sdw_cdns_dma_data: Cadence DMA data
 *
 * @name: SoundWire stream name
 * @nr_ports: Number of ports
 * @port: Ports
 * @stream: stream runtime
 * @pdi: PDI used for this dai
 * @bus: Bus handle
 * @stream_type: Stream type
 * @link_id: Master link id
@@ -104,8 +85,7 @@ struct sdw_cdns_stream_config {
struct sdw_cdns_dma_data {
	char *name;
	struct sdw_stream_runtime *stream;
	int nr_ports;
	struct sdw_cdns_port **port;
	struct sdw_cdns_pdi *pdi;
	struct sdw_bus *bus;
	enum sdw_stream_type stream_type;
	int link_id;
@@ -158,10 +138,11 @@ extern struct sdw_master_ops sdw_cdns_master_ops;
irqreturn_t sdw_cdns_irq(int irq, void *dev_id);
irqreturn_t sdw_cdns_thread(int irq, void *dev_id);

int sdw_cdns_init(struct sdw_cdns *cdns);
int sdw_cdns_init(struct sdw_cdns *cdns, bool clock_stop_exit);
int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
		      struct sdw_cdns_stream_config config);
int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
int sdw_cdns_exit_reset(struct sdw_cdns *cdns);
int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state);

#ifdef CONFIG_DEBUG_FS
void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
@@ -170,10 +151,10 @@ void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
int sdw_cdns_get_stream(struct sdw_cdns *cdns,
			struct sdw_cdns_streams *stream,
			u32 ch, u32 dir);
int sdw_cdns_alloc_stream(struct sdw_cdns *cdns,
struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns,
					struct sdw_cdns_streams *stream,
			  struct sdw_cdns_port *port, u32 ch, u32 dir);
void sdw_cdns_config_stream(struct sdw_cdns *cdns, struct sdw_cdns_port *port,
					u32 ch, u32 dir, int dai_id);
void sdw_cdns_config_stream(struct sdw_cdns *cdns,
			    u32 ch, u32 dir, struct sdw_cdns_pdi *pdi);

int sdw_cdns_pcm_set_stream(struct snd_soc_dai *dai,
+64 −137
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -479,7 +480,10 @@ intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
	unsigned int link_id = sdw->instance;
	int pdi_conf = 0;

	pdi->intel_alh_id = (link_id * 16) + pdi->num + 5;
	/* the Bulk and PCM streams are not contiguous */
	pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
	if (pdi->num >= 2)
		pdi->intel_alh_id += 2;

	/*
	 * Program stream parameters to stream SHIM register
@@ -508,7 +512,10 @@ intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
	unsigned int link_id = sdw->instance;
	unsigned int conf;

	pdi->intel_alh_id = (link_id * 16) + pdi->num + 5;
	/* the Bulk and PCM streams are not contiguous */
	pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
	if (pdi->num >= 2)
		pdi->intel_alh_id += 2;

	/* Program Stream config ALH register */
	conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id));
@@ -603,66 +610,6 @@ static int intel_post_bank_switch(struct sdw_bus *bus)
 * DAI routines
 */

static struct sdw_cdns_port *intel_alloc_port(struct sdw_intel *sdw,
					      u32 ch, u32 dir, bool pcm)
{
	struct sdw_cdns *cdns = &sdw->cdns;
	struct sdw_cdns_port *port = NULL;
	int i, ret = 0;

	for (i = 0; i < cdns->num_ports; i++) {
		if (cdns->ports[i].assigned)
			continue;

		port = &cdns->ports[i];
		port->assigned = true;
		port->direction = dir;
		port->ch = ch;
		break;
	}

	if (!port) {
		dev_err(cdns->dev, "Unable to find a free port\n");
		return NULL;
	}

	if (pcm) {
		ret = sdw_cdns_alloc_stream(cdns, &cdns->pcm, port, ch, dir);
		if (ret)
			goto out;

		intel_pdi_shim_configure(sdw, port->pdi);
		sdw_cdns_config_stream(cdns, port, ch, dir, port->pdi);

		intel_pdi_alh_configure(sdw, port->pdi);

	} else {
		ret = sdw_cdns_alloc_stream(cdns, &cdns->pdm, port, ch, dir);
	}

out:
	if (ret) {
		port->assigned = false;
		port = NULL;
	}

	return port;
}

static void intel_port_cleanup(struct sdw_cdns_dma_data *dma)
{
	int i;

	for (i = 0; i < dma->nr_ports; i++) {
		if (dma->port[i]) {
			dma->port[i]->pdi->assigned = false;
			dma->port[i]->pdi = NULL;
			dma->port[i]->assigned = false;
			dma->port[i] = NULL;
		}
	}
}

static int intel_hw_params(struct snd_pcm_substream *substream,
			   struct snd_pcm_hw_params *params,
			   struct snd_soc_dai *dai)
@@ -670,9 +617,11 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
	struct sdw_intel *sdw = cdns_to_intel(cdns);
	struct sdw_cdns_dma_data *dma;
	struct sdw_cdns_pdi *pdi;
	struct sdw_stream_config sconfig;
	struct sdw_port_config *pconfig;
	int ret, i, ch, dir;
	int ch, dir;
	int ret;
	bool pcm = true;

	dma = snd_soc_dai_get_dma_data(dai, substream);
@@ -685,38 +634,30 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
	else
		dir = SDW_DATA_DIR_TX;

	if (dma->stream_type == SDW_STREAM_PDM) {
		/* TODO: Check whether PDM decimator is already in use */
		dma->nr_ports = sdw_cdns_get_stream(cdns, &cdns->pdm, ch, dir);
	if (dma->stream_type == SDW_STREAM_PDM)
		pcm = false;
	} else {
		dma->nr_ports = sdw_cdns_get_stream(cdns, &cdns->pcm, ch, dir);
	}

	if (!dma->nr_ports) {
		dev_err(dai->dev, "ports/resources not available\n");
		return -EINVAL;
	}

	dma->port = kcalloc(dma->nr_ports, sizeof(*dma->port), GFP_KERNEL);
	if (!dma->port)
		return -ENOMEM;
	if (pcm)
		pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
	else
		pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pdm, ch, dir, dai->id);

	for (i = 0; i < dma->nr_ports; i++) {
		dma->port[i] = intel_alloc_port(sdw, ch, dir, pcm);
		if (!dma->port[i]) {
	if (!pdi) {
		ret = -EINVAL;
			goto port_error;
		}
		goto error;
	}

	/* do run-time configurations for SHIM, ALH and PDI/PORT */
	intel_pdi_shim_configure(sdw, pdi);
	intel_pdi_alh_configure(sdw, pdi);
	sdw_cdns_config_stream(cdns, ch, dir, pdi);


	/* Inform DSP about PDI stream number */
	for (i = 0; i < dma->nr_ports; i++) {
	ret = intel_config_stream(sdw, substream, dai, params,
					  dma->port[i]->pdi->intel_alh_id);
				  pdi->intel_alh_id);
	if (ret)
			goto port_error;
	}
		goto error;

	sconfig.direction = dir;
	sconfig.ch_count = ch;
@@ -731,32 +672,22 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
	}

	/* Port configuration */
	pconfig = kcalloc(dma->nr_ports, sizeof(*pconfig), GFP_KERNEL);
	pconfig = kcalloc(1, sizeof(*pconfig), GFP_KERNEL);
	if (!pconfig) {
		ret =  -ENOMEM;
		goto port_error;
		goto error;
	}

	for (i = 0; i < dma->nr_ports; i++) {
		pconfig[i].num = dma->port[i]->num;
		pconfig[i].ch_mask = (1 << ch) - 1;
	}
	pconfig->num = pdi->num;
	pconfig->ch_mask = (1 << ch) - 1;

	ret = sdw_stream_add_master(&cdns->bus, &sconfig,
				    pconfig, dma->nr_ports, dma->stream);
	if (ret) {
				    pconfig, 1, dma->stream);
	if (ret)
		dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
		goto stream_error;
	}

	kfree(pconfig);
	return ret;

stream_error:
	kfree(pconfig);
port_error:
	intel_port_cleanup(dma);
	kfree(dma->port);
error:
	return ret;
}

@@ -776,8 +707,6 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
		dev_err(dai->dev, "remove master from stream %s failed: %d\n",
			dma->stream->name, ret);

	intel_port_cleanup(dma);
	kfree(dma->port);
	return ret;
}

@@ -842,14 +771,6 @@ static int intel_create_dai(struct sdw_cdns *cdns,
			return -ENOMEM;

		if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) {
			dais[i].playback.stream_name =
				kasprintf(GFP_KERNEL, "SDW%d Tx%d",
					  cdns->instance, i);
			if (!dais[i].playback.stream_name) {
				kfree(dais[i].name);
				return -ENOMEM;
			}

			dais[i].playback.channels_min = 1;
			dais[i].playback.channels_max = max_ch;
			dais[i].playback.rates = SNDRV_PCM_RATE_48000;
@@ -857,23 +778,12 @@ static int intel_create_dai(struct sdw_cdns *cdns,
		}

		if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) {
			dais[i].capture.stream_name =
				kasprintf(GFP_KERNEL, "SDW%d Rx%d",
					  cdns->instance, i);
			if (!dais[i].capture.stream_name) {
				kfree(dais[i].name);
				kfree(dais[i].playback.stream_name);
				return -ENOMEM;
			}

			dais[i].capture.channels_min = 1;
			dais[i].capture.channels_max = max_ch;
			dais[i].capture.rates = SNDRV_PCM_RATE_48000;
			dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
		}

		dais[i].id = SDW_DAI_ID_RANGE_START + i;

		if (pcm)
			dais[i].ops = &intel_pcm_dai_ops;
		else
@@ -993,6 +903,15 @@ static struct sdw_master_ops sdw_intel_ops = {
	.post_bank_switch = intel_post_bank_switch,
};

static int intel_init(struct sdw_intel *sdw)
{
	/* Initialize shim and controller */
	intel_link_power_up(sdw);
	intel_shim_init(sdw);

	return sdw_cdns_init(&sdw->cdns, false);
}

/*
 * probe and init
 */
@@ -1026,7 +945,7 @@ static int intel_probe(struct platform_device *pdev)
	ret = sdw_add_bus_master(&sdw->cdns.bus);
	if (ret) {
		dev_err(&pdev->dev, "sdw_add_bus_master fail: %d\n", ret);
		goto err_master_reg;
		return ret;
	}

	if (sdw->cdns.bus.prop.hw_disabled) {
@@ -1035,16 +954,11 @@ static int intel_probe(struct platform_device *pdev)
		return 0;
	}

	/* Initialize shim and controller */
	intel_link_power_up(sdw);
	intel_shim_init(sdw);

	ret = sdw_cdns_init(&sdw->cdns);
	/* Initialize shim, controller and Cadence IP */
	ret = intel_init(sdw);
	if (ret)
		goto err_init;

	ret = sdw_cdns_enable_interrupt(&sdw->cdns);

	/* Read the PDI config and initialize cadence PDI */
	intel_pdi_init(sdw, &config);
	ret = sdw_cdns_pdi_init(&sdw->cdns, config);
@@ -1062,23 +976,35 @@ static int intel_probe(struct platform_device *pdev)
		goto err_init;
	}

	ret = sdw_cdns_enable_interrupt(&sdw->cdns, true);
	if (ret < 0) {
		dev_err(sdw->cdns.dev, "cannot enable interrupts\n");
		goto err_init;
	}

	ret = sdw_cdns_exit_reset(&sdw->cdns);
	if (ret < 0) {
		dev_err(sdw->cdns.dev, "unable to exit bus reset sequence\n");
		goto err_interrupt;
	}

	/* Register DAIs */
	ret = intel_register_dai(sdw);
	if (ret) {
		dev_err(sdw->cdns.dev, "DAI registration failed: %d\n", ret);
		snd_soc_unregister_component(sdw->cdns.dev);
		goto err_dai;
		goto err_interrupt;
	}

	intel_debugfs_init(sdw);

	return 0;

err_dai:
err_interrupt:
	sdw_cdns_enable_interrupt(&sdw->cdns, false);
	free_irq(sdw->res->irq, sdw);
err_init:
	sdw_delete_bus_master(&sdw->cdns.bus);
err_master_reg:
	return ret;
}

@@ -1090,6 +1016,7 @@ static int intel_remove(struct platform_device *pdev)

	if (!sdw->cdns.bus.prop.hw_disabled) {
		intel_debugfs_exit(sdw);
		sdw_cdns_enable_interrupt(&sdw->cdns, false);
		free_irq(sdw->res->irq, sdw);
		snd_soc_unregister_component(sdw->cdns.dev);
	}
Loading