brintos

brintos / linux-shallow public Read only

0
0
Text · 50.3 KiB · 05652e9 Raw
1927 lines · c
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)2// Copyright(c) 2015-17 Intel Corporation.3 4/*5 * Cadence SoundWire Master module6 * Used by Master driver7 */8 9#include <linux/cleanup.h>10#include <linux/delay.h>11#include <linux/device.h>12#include <linux/debugfs.h>13#include <linux/interrupt.h>14#include <linux/io.h>15#include <linux/module.h>16#include <linux/mod_devicetable.h>17#include <linux/pm_runtime.h>18#include <linux/soundwire/sdw_registers.h>19#include <linux/soundwire/sdw.h>20#include <sound/pcm_params.h>21#include <sound/soc.h>22#include <linux/workqueue.h>23#include "bus.h"24#include "cadence_master.h"25 26static int interrupt_mask;27module_param_named(cnds_mcp_int_mask, interrupt_mask, int, 0444);28MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask");29 30#define CDNS_MCP_CONFIG				0x031#define CDNS_MCP_CONFIG_BUS_REL			BIT(6)32 33#define CDNS_IP_MCP_CONFIG			0x0 /* IP offset added at run-time */34 35#define CDNS_IP_MCP_CONFIG_MCMD_RETRY		GENMASK(27, 24)36#define CDNS_IP_MCP_CONFIG_MPREQ_DELAY		GENMASK(20, 16)37#define CDNS_IP_MCP_CONFIG_MMASTER		BIT(7)38#define CDNS_IP_MCP_CONFIG_SNIFFER		BIT(5)39#define CDNS_IP_MCP_CONFIG_CMD			BIT(3)40#define CDNS_IP_MCP_CONFIG_OP			GENMASK(2, 0)41#define CDNS_IP_MCP_CONFIG_OP_NORMAL		042 43#define CDNS_MCP_CONTROL			0x444 45#define CDNS_MCP_CONTROL_CMD_RST		BIT(7)46#define CDNS_MCP_CONTROL_SOFT_RST		BIT(6)47#define CDNS_MCP_CONTROL_HW_RST			BIT(4)48#define CDNS_MCP_CONTROL_CLK_STOP_CLR		BIT(2)49 50#define CDNS_IP_MCP_CONTROL			0x4  /* IP offset added at run-time */51 52#define CDNS_IP_MCP_CONTROL_RST_DELAY		GENMASK(10, 8)53#define CDNS_IP_MCP_CONTROL_SW_RST		BIT(5)54#define CDNS_IP_MCP_CONTROL_CLK_PAUSE		BIT(3)55#define CDNS_IP_MCP_CONTROL_CMD_ACCEPT		BIT(1)56#define CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP	BIT(0)57 58#define CDNS_IP_MCP_CMDCTRL			0x8 /* IP offset added at run-time */59 60#define CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR	BIT(2)61 62#define CDNS_MCP_SSPSTAT			0xC63#define CDNS_MCP_FRAME_SHAPE			0x1064#define CDNS_MCP_FRAME_SHAPE_INIT		0x1465#define CDNS_MCP_FRAME_SHAPE_COL_MASK		GENMASK(2, 0)66#define CDNS_MCP_FRAME_SHAPE_ROW_MASK		GENMASK(7, 3)67 68#define CDNS_MCP_CONFIG_UPDATE			0x1869#define CDNS_MCP_CONFIG_UPDATE_BIT		BIT(0)70 71#define CDNS_MCP_PHYCTRL			0x1C72#define CDNS_MCP_SSP_CTRL0			0x2073#define CDNS_MCP_SSP_CTRL1			0x2874#define CDNS_MCP_CLK_CTRL0			0x3075#define CDNS_MCP_CLK_CTRL1			0x3876#define CDNS_MCP_CLK_MCLKD_MASK		GENMASK(7, 0)77 78#define CDNS_MCP_STAT				0x4079 80#define CDNS_MCP_STAT_ACTIVE_BANK		BIT(20)81#define CDNS_MCP_STAT_CLK_STOP			BIT(16)82 83#define CDNS_MCP_INTSTAT			0x4484#define CDNS_MCP_INTMASK			0x4885 86#define CDNS_MCP_INT_IRQ			BIT(31)87#define CDNS_MCP_INT_RESERVED1			GENMASK(30, 17)88#define CDNS_MCP_INT_WAKEUP			BIT(16)89#define CDNS_MCP_INT_SLAVE_RSVD			BIT(15)90#define CDNS_MCP_INT_SLAVE_ALERT		BIT(14)91#define CDNS_MCP_INT_SLAVE_ATTACH		BIT(13)92#define CDNS_MCP_INT_SLAVE_NATTACH		BIT(12)93#define CDNS_MCP_INT_SLAVE_MASK			GENMASK(15, 12)94#define CDNS_MCP_INT_DPINT			BIT(11)95#define CDNS_MCP_INT_CTRL_CLASH			BIT(10)96#define CDNS_MCP_INT_DATA_CLASH			BIT(9)97#define CDNS_MCP_INT_PARITY			BIT(8)98#define CDNS_MCP_INT_CMD_ERR			BIT(7)99#define CDNS_MCP_INT_RESERVED2			GENMASK(6, 4)100#define CDNS_MCP_INT_RX_NE			BIT(3)101#define CDNS_MCP_INT_RX_WL			BIT(2)102#define CDNS_MCP_INT_TXE			BIT(1)103#define CDNS_MCP_INT_TXF			BIT(0)104#define CDNS_MCP_INT_RESERVED (CDNS_MCP_INT_RESERVED1 | CDNS_MCP_INT_RESERVED2)105 106#define CDNS_MCP_INTSET				0x4C107 108#define CDNS_MCP_SLAVE_STAT			0x50109#define CDNS_MCP_SLAVE_STAT_MASK		GENMASK(1, 0)110 111#define CDNS_MCP_SLAVE_INTSTAT0			0x54112#define CDNS_MCP_SLAVE_INTSTAT1			0x58113#define CDNS_MCP_SLAVE_INTSTAT_NPRESENT		BIT(0)114#define CDNS_MCP_SLAVE_INTSTAT_ATTACHED		BIT(1)115#define CDNS_MCP_SLAVE_INTSTAT_ALERT		BIT(2)116#define CDNS_MCP_SLAVE_INTSTAT_RESERVED		BIT(3)117#define CDNS_MCP_SLAVE_STATUS_BITS		GENMASK(3, 0)118#define CDNS_MCP_SLAVE_STATUS_NUM		4119 120#define CDNS_MCP_SLAVE_INTMASK0			0x5C121#define CDNS_MCP_SLAVE_INTMASK1			0x60122 123#define CDNS_MCP_SLAVE_INTMASK0_MASK		GENMASK(31, 0)124#define CDNS_MCP_SLAVE_INTMASK1_MASK		GENMASK(15, 0)125 126#define CDNS_MCP_PORT_INTSTAT			0x64127#define CDNS_MCP_PDI_STAT			0x6C128 129#define CDNS_MCP_FIFOLEVEL			0x78130#define CDNS_MCP_FIFOSTAT			0x7C131#define CDNS_MCP_RX_FIFO_AVAIL			GENMASK(5, 0)132 133#define CDNS_IP_MCP_CMD_BASE			0x80 /* IP offset added at run-time */134#define CDNS_IP_MCP_RESP_BASE			0x80 /* IP offset added at run-time */135/* FIFO can hold 8 commands */136#define CDNS_MCP_CMD_LEN			8137#define CDNS_MCP_CMD_WORD_LEN			0x4138 139#define CDNS_MCP_CMD_SSP_TAG			BIT(31)140#define CDNS_MCP_CMD_COMMAND			GENMASK(30, 28)141#define CDNS_MCP_CMD_DEV_ADDR			GENMASK(27, 24)142#define CDNS_MCP_CMD_REG_ADDR			GENMASK(23, 8)143#define CDNS_MCP_CMD_REG_DATA			GENMASK(7, 0)144 145#define CDNS_MCP_CMD_READ			2146#define CDNS_MCP_CMD_WRITE			3147 148#define CDNS_MCP_RESP_RDATA			GENMASK(15, 8)149#define CDNS_MCP_RESP_ACK			BIT(0)150#define CDNS_MCP_RESP_NACK			BIT(1)151 152#define CDNS_DP_SIZE				128153 154#define CDNS_DPN_B0_CONFIG(n)			(0x100 + CDNS_DP_SIZE * (n))155#define CDNS_DPN_B0_CH_EN(n)			(0x104 + CDNS_DP_SIZE * (n))156#define CDNS_DPN_B0_SAMPLE_CTRL(n)		(0x108 + CDNS_DP_SIZE * (n))157#define CDNS_DPN_B0_OFFSET_CTRL(n)		(0x10C + CDNS_DP_SIZE * (n))158#define CDNS_DPN_B0_HCTRL(n)			(0x110 + CDNS_DP_SIZE * (n))159#define CDNS_DPN_B0_ASYNC_CTRL(n)		(0x114 + CDNS_DP_SIZE * (n))160 161#define CDNS_DPN_B1_CONFIG(n)			(0x118 + CDNS_DP_SIZE * (n))162#define CDNS_DPN_B1_CH_EN(n)			(0x11C + CDNS_DP_SIZE * (n))163#define CDNS_DPN_B1_SAMPLE_CTRL(n)		(0x120 + CDNS_DP_SIZE * (n))164#define CDNS_DPN_B1_OFFSET_CTRL(n)		(0x124 + CDNS_DP_SIZE * (n))165#define CDNS_DPN_B1_HCTRL(n)			(0x128 + CDNS_DP_SIZE * (n))166#define CDNS_DPN_B1_ASYNC_CTRL(n)		(0x12C + CDNS_DP_SIZE * (n))167 168#define CDNS_DPN_CONFIG_BPM			BIT(18)169#define CDNS_DPN_CONFIG_BGC			GENMASK(17, 16)170#define CDNS_DPN_CONFIG_WL			GENMASK(12, 8)171#define CDNS_DPN_CONFIG_PORT_DAT		GENMASK(3, 2)172#define CDNS_DPN_CONFIG_PORT_FLOW		GENMASK(1, 0)173 174#define CDNS_DPN_SAMPLE_CTRL_SI			GENMASK(15, 0)175 176#define CDNS_DPN_OFFSET_CTRL_1			GENMASK(7, 0)177#define CDNS_DPN_OFFSET_CTRL_2			GENMASK(15, 8)178 179#define CDNS_DPN_HCTRL_HSTOP			GENMASK(3, 0)180#define CDNS_DPN_HCTRL_HSTART			GENMASK(7, 4)181#define CDNS_DPN_HCTRL_LCTRL			GENMASK(10, 8)182 183#define CDNS_PORTCTRL				0x130184#define CDNS_PORTCTRL_TEST_FAILED		BIT(1)185#define CDNS_PORTCTRL_DIRN			BIT(7)186#define CDNS_PORTCTRL_BANK_INVERT		BIT(8)187 188#define CDNS_PORT_OFFSET			0x80189 190#define CDNS_PDI_CONFIG(n)			(0x1100 + (n) * 16)191 192#define CDNS_PDI_CONFIG_SOFT_RESET		BIT(24)193#define CDNS_PDI_CONFIG_CHANNEL			GENMASK(15, 8)194#define CDNS_PDI_CONFIG_PORT			GENMASK(4, 0)195 196/* Driver defaults */197#define CDNS_TX_TIMEOUT				500198 199#define CDNS_SCP_RX_FIFOLEVEL			0x2200 201/*202 * register accessor helpers203 */204static inline u32 cdns_readl(struct sdw_cdns *cdns, int offset)205{206	return readl(cdns->registers + offset);207}208 209static inline void cdns_writel(struct sdw_cdns *cdns, int offset, u32 value)210{211	writel(value, cdns->registers + offset);212}213 214static inline u32 cdns_ip_readl(struct sdw_cdns *cdns, int offset)215{216	return cdns_readl(cdns, cdns->ip_offset + offset);217}218 219static inline void cdns_ip_writel(struct sdw_cdns *cdns, int offset, u32 value)220{221	return cdns_writel(cdns, cdns->ip_offset + offset, value);222}223 224static inline void cdns_updatel(struct sdw_cdns *cdns,225				int offset, u32 mask, u32 val)226{227	u32 tmp;228 229	tmp = cdns_readl(cdns, offset);230	tmp = (tmp & ~mask) | val;231	cdns_writel(cdns, offset, tmp);232}233 234static inline void cdns_ip_updatel(struct sdw_cdns *cdns,235				   int offset, u32 mask, u32 val)236{237	cdns_updatel(cdns, cdns->ip_offset + offset, mask, val);238}239 240static int cdns_set_wait(struct sdw_cdns *cdns, int offset, u32 mask, u32 value)241{242	int timeout = 10;243	u32 reg_read;244 245	/* Wait for bit to be set */246	do {247		reg_read = readl(cdns->registers + offset);248		if ((reg_read & mask) == value)249			return 0;250 251		timeout--;252		usleep_range(50, 100);253	} while (timeout != 0);254 255	return -ETIMEDOUT;256}257 258static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value)259{260	writel(value, cdns->registers + offset);261 262	/* Wait for bit to be self cleared */263	return cdns_set_wait(cdns, offset, value, 0);264}265 266/*267 * all changes to the MCP_CONFIG, MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL268 * need to be confirmed with a write to MCP_CONFIG_UPDATE269 */270static int cdns_config_update(struct sdw_cdns *cdns)271{272	int ret;273 274	if (sdw_cdns_is_clock_stop(cdns)) {275		dev_err(cdns->dev, "Cannot program MCP_CONFIG_UPDATE in ClockStopMode\n");276		return -EINVAL;277	}278 279	ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,280			     CDNS_MCP_CONFIG_UPDATE_BIT);281	if (ret < 0)282		dev_err(cdns->dev, "Config update timedout\n");283 284	return ret;285}286 287/**288 * sdw_cdns_config_update() - Update configurations289 * @cdns: Cadence instance290 */291void sdw_cdns_config_update(struct sdw_cdns *cdns)292{293	/* commit changes */294	cdns_writel(cdns, CDNS_MCP_CONFIG_UPDATE, CDNS_MCP_CONFIG_UPDATE_BIT);295}296EXPORT_SYMBOL(sdw_cdns_config_update);297 298/**299 * sdw_cdns_config_update_set_wait() - wait until configuration update bit is self-cleared300 * @cdns: Cadence instance301 */302int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns)303{304	/* the hardware recommendation is to wait at least 300us */305	return cdns_set_wait(cdns, CDNS_MCP_CONFIG_UPDATE,306			     CDNS_MCP_CONFIG_UPDATE_BIT, 0);307}308EXPORT_SYMBOL(sdw_cdns_config_update_set_wait);309 310/*311 * debugfs312 */313#ifdef CONFIG_DEBUG_FS314 315#define RD_BUF (2 * PAGE_SIZE)316 317static ssize_t cdns_sprintf(struct sdw_cdns *cdns,318			    char *buf, size_t pos, unsigned int reg)319{320	return scnprintf(buf + pos, RD_BUF - pos,321			 "%4x\t%8x\n", reg, cdns_readl(cdns, reg));322}323 324static int cdns_reg_show(struct seq_file *s, void *data)325{326	struct sdw_cdns *cdns = s->private;327	ssize_t ret;328	int num_ports;329	int i, j;330 331	char *buf __free(kfree) = kzalloc(RD_BUF, GFP_KERNEL);332	if (!buf)333		return -ENOMEM;334 335	ret = scnprintf(buf, RD_BUF, "Register  Value\n");336	ret += scnprintf(buf + ret, RD_BUF - ret, "\nMCP Registers\n");337	/* 8 MCP registers */338	for (i = CDNS_MCP_CONFIG; i <= CDNS_MCP_PHYCTRL; i += sizeof(u32))339		ret += cdns_sprintf(cdns, buf, ret, i);340 341	ret += scnprintf(buf + ret, RD_BUF - ret,342			 "\nStatus & Intr Registers\n");343	/* 13 Status & Intr registers (offsets 0x70 and 0x74 not defined) */344	for (i = CDNS_MCP_STAT; i <=  CDNS_MCP_FIFOSTAT; i += sizeof(u32))345		ret += cdns_sprintf(cdns, buf, ret, i);346 347	ret += scnprintf(buf + ret, RD_BUF - ret,348			 "\nSSP & Clk ctrl Registers\n");349	ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL0);350	ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL1);351	ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL0);352	ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL1);353 354	ret += scnprintf(buf + ret, RD_BUF - ret,355			 "\nDPn B0 Registers\n");356 357	num_ports = cdns->num_ports;358 359	for (i = 0; i < num_ports; i++) {360		ret += scnprintf(buf + ret, RD_BUF - ret,361				 "\nDP-%d\n", i);362		for (j = CDNS_DPN_B0_CONFIG(i);363		     j < CDNS_DPN_B0_ASYNC_CTRL(i); j += sizeof(u32))364			ret += cdns_sprintf(cdns, buf, ret, j);365	}366 367	ret += scnprintf(buf + ret, RD_BUF - ret,368			 "\nDPn B1 Registers\n");369	for (i = 0; i < num_ports; i++) {370		ret += scnprintf(buf + ret, RD_BUF - ret,371				 "\nDP-%d\n", i);372 373		for (j = CDNS_DPN_B1_CONFIG(i);374		     j < CDNS_DPN_B1_ASYNC_CTRL(i); j += sizeof(u32))375			ret += cdns_sprintf(cdns, buf, ret, j);376	}377 378	ret += scnprintf(buf + ret, RD_BUF - ret,379			 "\nDPn Control Registers\n");380	for (i = 0; i < num_ports; i++)381		ret += cdns_sprintf(cdns, buf, ret,382				CDNS_PORTCTRL + i * CDNS_PORT_OFFSET);383 384	ret += scnprintf(buf + ret, RD_BUF - ret,385			 "\nPDIn Config Registers\n");386 387	/* number of PDI and ports is interchangeable */388	for (i = 0; i < num_ports; i++)389		ret += cdns_sprintf(cdns, buf, ret, CDNS_PDI_CONFIG(i));390 391	seq_printf(s, "%s", buf);392 393	return 0;394}395DEFINE_SHOW_ATTRIBUTE(cdns_reg);396 397static int cdns_hw_reset(void *data, u64 value)398{399	struct sdw_cdns *cdns = data;400	int ret;401 402	if (value != 1)403		return -EINVAL;404 405	/* Userspace changed the hardware state behind the kernel's back */406	add_taint(TAINT_USER, LOCKDEP_STILL_OK);407 408	ret = sdw_cdns_exit_reset(cdns);409 410	dev_dbg(cdns->dev, "link hw_reset done: %d\n", ret);411 412	return ret;413}414 415DEFINE_DEBUGFS_ATTRIBUTE(cdns_hw_reset_fops, NULL, cdns_hw_reset, "%llu\n");416 417static int cdns_parity_error_injection(void *data, u64 value)418{419	struct sdw_cdns *cdns = data;420	struct sdw_bus *bus;421	int ret;422 423	if (value != 1)424		return -EINVAL;425 426	bus = &cdns->bus;427 428	/*429	 * Resume Master device. If this results in a bus reset, the430	 * Slave devices will re-attach and be re-enumerated.431	 */432	ret = pm_runtime_resume_and_get(bus->dev);433	if (ret < 0 && ret != -EACCES) {434		dev_err_ratelimited(cdns->dev,435				    "pm_runtime_resume_and_get failed in %s, ret %d\n",436				    __func__, ret);437		return ret;438	}439 440	/*441	 * wait long enough for Slave(s) to be in steady state. This442	 * does not need to be super precise.443	 */444	msleep(200);445 446	/*447	 * Take the bus lock here to make sure that any bus transactions448	 * will be queued while we inject a parity error on a dummy read449	 */450	mutex_lock(&bus->bus_lock);451 452	/* program hardware to inject parity error */453	cdns_ip_updatel(cdns, CDNS_IP_MCP_CMDCTRL,454			CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR,455			CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR);456 457	/* commit changes */458	ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE, CDNS_MCP_CONFIG_UPDATE_BIT);459	if (ret < 0)460		goto unlock;461 462	/* do a broadcast dummy read to avoid bus clashes */463	ret = sdw_bread_no_pm_unlocked(&cdns->bus, 0xf, SDW_SCP_DEVID_0);464	dev_info(cdns->dev, "parity error injection, read: %d\n", ret);465 466	/* program hardware to disable parity error */467	cdns_ip_updatel(cdns, CDNS_IP_MCP_CMDCTRL,468			CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR,469			0);470 471	/* commit changes */472	ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE, CDNS_MCP_CONFIG_UPDATE_BIT);473	if (ret < 0)474		goto unlock;475 476	/* Userspace changed the hardware state behind the kernel's back */477	add_taint(TAINT_USER, LOCKDEP_STILL_OK);478 479unlock:480	/* Continue bus operation with parity error injection disabled */481	mutex_unlock(&bus->bus_lock);482 483	/*484	 * allow Master device to enter pm_runtime suspend. This may485	 * also result in Slave devices suspending.486	 */487	pm_runtime_mark_last_busy(bus->dev);488	pm_runtime_put_autosuspend(bus->dev);489 490	return 0;491}492 493DEFINE_DEBUGFS_ATTRIBUTE(cdns_parity_error_fops, NULL,494			 cdns_parity_error_injection, "%llu\n");495 496static int cdns_set_pdi_loopback_source(void *data, u64 value)497{498	struct sdw_cdns *cdns = data;499	unsigned int pdi_out_num = cdns->pcm.num_bd + cdns->pcm.num_out;500 501	if (value > pdi_out_num)502		return -EINVAL;503 504	/* Userspace changed the hardware state behind the kernel's back */505	add_taint(TAINT_USER, LOCKDEP_STILL_OK);506 507	cdns->pdi_loopback_source = value;508 509	return 0;510}511DEFINE_DEBUGFS_ATTRIBUTE(cdns_pdi_loopback_source_fops, NULL, cdns_set_pdi_loopback_source, "%llu\n");512 513static int cdns_set_pdi_loopback_target(void *data, u64 value)514{515	struct sdw_cdns *cdns = data;516	unsigned int pdi_in_num = cdns->pcm.num_bd + cdns->pcm.num_in;517 518	if (value > pdi_in_num)519		return -EINVAL;520 521	/* Userspace changed the hardware state behind the kernel's back */522	add_taint(TAINT_USER, LOCKDEP_STILL_OK);523 524	cdns->pdi_loopback_target = value;525 526	return 0;527}528DEFINE_DEBUGFS_ATTRIBUTE(cdns_pdi_loopback_target_fops, NULL, cdns_set_pdi_loopback_target, "%llu\n");529 530/**531 * sdw_cdns_debugfs_init() - Cadence debugfs init532 * @cdns: Cadence instance533 * @root: debugfs root534 */535void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root)536{537	debugfs_create_file("cdns-registers", 0400, root, cdns, &cdns_reg_fops);538 539	debugfs_create_file("cdns-hw-reset", 0200, root, cdns,540			    &cdns_hw_reset_fops);541 542	debugfs_create_file("cdns-parity-error-injection", 0200, root, cdns,543			    &cdns_parity_error_fops);544 545	cdns->pdi_loopback_source = -1;546	cdns->pdi_loopback_target = -1;547 548	debugfs_create_file("cdns-pdi-loopback-source", 0200, root, cdns,549			    &cdns_pdi_loopback_source_fops);550 551	debugfs_create_file("cdns-pdi-loopback-target", 0200, root, cdns,552			    &cdns_pdi_loopback_target_fops);553 554}555EXPORT_SYMBOL_GPL(sdw_cdns_debugfs_init);556 557#endif /* CONFIG_DEBUG_FS */558 559/*560 * IO Calls561 */562static enum sdw_command_response563cdns_fill_msg_resp(struct sdw_cdns *cdns,564		   struct sdw_msg *msg, int count, int offset)565{566	int nack = 0, no_ack = 0;567	int i;568 569	/* check message response */570	for (i = 0; i < count; i++) {571		if (!(cdns->response_buf[i] & CDNS_MCP_RESP_ACK)) {572			no_ack = 1;573			dev_vdbg(cdns->dev, "Msg Ack not received, cmd %d\n", i);574		}575		if (cdns->response_buf[i] & CDNS_MCP_RESP_NACK) {576			nack = 1;577			dev_err_ratelimited(cdns->dev, "Msg NACK received, cmd %d\n", i);578		}579	}580 581	if (nack) {582		dev_err_ratelimited(cdns->dev, "Msg NACKed for Slave %d\n", msg->dev_num);583		return SDW_CMD_FAIL;584	}585 586	if (no_ack) {587		dev_dbg_ratelimited(cdns->dev, "Msg ignored for Slave %d\n", msg->dev_num);588		return SDW_CMD_IGNORED;589	}590 591	if (msg->flags == SDW_MSG_FLAG_READ) {592		/* fill response */593		for (i = 0; i < count; i++)594			msg->buf[i + offset] = FIELD_GET(CDNS_MCP_RESP_RDATA,595							 cdns->response_buf[i]);596	}597 598	return SDW_CMD_OK;599}600 601static void cdns_read_response(struct sdw_cdns *cdns)602{603	u32 num_resp, cmd_base;604	int i;605 606	/* RX_FIFO_AVAIL can be 2 entries more than the FIFO size */607	BUILD_BUG_ON(ARRAY_SIZE(cdns->response_buf) < CDNS_MCP_CMD_LEN + 2);608 609	num_resp = cdns_readl(cdns, CDNS_MCP_FIFOSTAT);610	num_resp &= CDNS_MCP_RX_FIFO_AVAIL;611	if (num_resp > ARRAY_SIZE(cdns->response_buf)) {612		dev_warn(cdns->dev, "RX AVAIL %d too long\n", num_resp);613		num_resp = ARRAY_SIZE(cdns->response_buf);614	}615 616	cmd_base = CDNS_IP_MCP_CMD_BASE;617 618	for (i = 0; i < num_resp; i++) {619		cdns->response_buf[i] = cdns_ip_readl(cdns, cmd_base);620		cmd_base += CDNS_MCP_CMD_WORD_LEN;621	}622}623 624static enum sdw_command_response625_cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,626	       int offset, int count, bool defer)627{628	unsigned long time;629	u32 base, i, data;630	u16 addr;631 632	/* Program the watermark level for RX FIFO */633	if (cdns->msg_count != count) {634		cdns_writel(cdns, CDNS_MCP_FIFOLEVEL, count);635		cdns->msg_count = count;636	}637 638	base = CDNS_IP_MCP_CMD_BASE;639	addr = msg->addr + offset;640 641	for (i = 0; i < count; i++) {642		data = FIELD_PREP(CDNS_MCP_CMD_DEV_ADDR, msg->dev_num);643		data |= FIELD_PREP(CDNS_MCP_CMD_COMMAND, cmd);644		data |= FIELD_PREP(CDNS_MCP_CMD_REG_ADDR, addr);645		addr++;646 647		if (msg->flags == SDW_MSG_FLAG_WRITE)648			data |= msg->buf[i + offset];649 650		data |= FIELD_PREP(CDNS_MCP_CMD_SSP_TAG, msg->ssp_sync);651		cdns_ip_writel(cdns, base, data);652		base += CDNS_MCP_CMD_WORD_LEN;653	}654 655	if (defer)656		return SDW_CMD_OK;657 658	/* wait for timeout or response */659	time = wait_for_completion_timeout(&cdns->tx_complete,660					   msecs_to_jiffies(CDNS_TX_TIMEOUT));661	if (!time) {662		dev_err(cdns->dev, "IO transfer timed out, cmd %d device %d addr %x len %d\n",663			cmd, msg->dev_num, msg->addr, msg->len);664		msg->len = 0;665 666		/* Drain anything in the RX_FIFO */667		cdns_read_response(cdns);668 669		return SDW_CMD_TIMEOUT;670	}671 672	return cdns_fill_msg_resp(cdns, msg, count, offset);673}674 675static enum sdw_command_response676cdns_program_scp_addr(struct sdw_cdns *cdns, struct sdw_msg *msg)677{678	int nack = 0, no_ack = 0;679	unsigned long time;680	u32 data[2], base;681	int i;682 683	/* Program the watermark level for RX FIFO */684	if (cdns->msg_count != CDNS_SCP_RX_FIFOLEVEL) {685		cdns_writel(cdns, CDNS_MCP_FIFOLEVEL, CDNS_SCP_RX_FIFOLEVEL);686		cdns->msg_count = CDNS_SCP_RX_FIFOLEVEL;687	}688 689	data[0] = FIELD_PREP(CDNS_MCP_CMD_DEV_ADDR, msg->dev_num);690	data[0] |= FIELD_PREP(CDNS_MCP_CMD_COMMAND, 0x3);691	data[1] = data[0];692 693	data[0] |= FIELD_PREP(CDNS_MCP_CMD_REG_ADDR, SDW_SCP_ADDRPAGE1);694	data[1] |= FIELD_PREP(CDNS_MCP_CMD_REG_ADDR, SDW_SCP_ADDRPAGE2);695 696	data[0] |= msg->addr_page1;697	data[1] |= msg->addr_page2;698 699	base = CDNS_IP_MCP_CMD_BASE;700	cdns_ip_writel(cdns, base, data[0]);701	base += CDNS_MCP_CMD_WORD_LEN;702	cdns_ip_writel(cdns, base, data[1]);703 704	time = wait_for_completion_timeout(&cdns->tx_complete,705					   msecs_to_jiffies(CDNS_TX_TIMEOUT));706	if (!time) {707		dev_err(cdns->dev, "SCP Msg trf timed out\n");708		msg->len = 0;709		return SDW_CMD_TIMEOUT;710	}711 712	/* check response the writes */713	for (i = 0; i < 2; i++) {714		if (!(cdns->response_buf[i] & CDNS_MCP_RESP_ACK)) {715			no_ack = 1;716			dev_err(cdns->dev, "Program SCP Ack not received\n");717			if (cdns->response_buf[i] & CDNS_MCP_RESP_NACK) {718				nack = 1;719				dev_err(cdns->dev, "Program SCP NACK received\n");720			}721		}722	}723 724	/* For NACK, NO ack, don't return err if we are in Broadcast mode */725	if (nack) {726		dev_err_ratelimited(cdns->dev,727				    "SCP_addrpage NACKed for Slave %d\n", msg->dev_num);728		return SDW_CMD_FAIL;729	}730 731	if (no_ack) {732		dev_dbg_ratelimited(cdns->dev,733				    "SCP_addrpage ignored for Slave %d\n", msg->dev_num);734		return SDW_CMD_IGNORED;735	}736 737	return SDW_CMD_OK;738}739 740static int cdns_prep_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int *cmd)741{742	int ret;743 744	if (msg->page) {745		ret = cdns_program_scp_addr(cdns, msg);746		if (ret) {747			msg->len = 0;748			return ret;749		}750	}751 752	switch (msg->flags) {753	case SDW_MSG_FLAG_READ:754		*cmd = CDNS_MCP_CMD_READ;755		break;756 757	case SDW_MSG_FLAG_WRITE:758		*cmd = CDNS_MCP_CMD_WRITE;759		break;760 761	default:762		dev_err(cdns->dev, "Invalid msg cmd: %d\n", msg->flags);763		return -EINVAL;764	}765 766	return 0;767}768 769enum sdw_command_response770cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg)771{772	struct sdw_cdns *cdns = bus_to_cdns(bus);773	int cmd = 0, ret, i;774 775	ret = cdns_prep_msg(cdns, msg, &cmd);776	if (ret)777		return SDW_CMD_FAIL_OTHER;778 779	for (i = 0; i < msg->len / CDNS_MCP_CMD_LEN; i++) {780		ret = _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN,781				     CDNS_MCP_CMD_LEN, false);782		if (ret != SDW_CMD_OK)783			return ret;784	}785 786	if (!(msg->len % CDNS_MCP_CMD_LEN))787		return SDW_CMD_OK;788 789	return _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN,790			      msg->len % CDNS_MCP_CMD_LEN, false);791}792EXPORT_SYMBOL(cdns_xfer_msg);793 794enum sdw_command_response795cdns_xfer_msg_defer(struct sdw_bus *bus)796{797	struct sdw_cdns *cdns = bus_to_cdns(bus);798	struct sdw_defer *defer = &bus->defer_msg;799	struct sdw_msg *msg = defer->msg;800	int cmd = 0, ret;801 802	/* for defer only 1 message is supported */803	if (msg->len > 1)804		return -ENOTSUPP;805 806	ret = cdns_prep_msg(cdns, msg, &cmd);807	if (ret)808		return SDW_CMD_FAIL_OTHER;809 810	return _cdns_xfer_msg(cdns, msg, cmd, 0, msg->len, true);811}812EXPORT_SYMBOL(cdns_xfer_msg_defer);813 814u32 cdns_read_ping_status(struct sdw_bus *bus)815{816	struct sdw_cdns *cdns = bus_to_cdns(bus);817 818	return cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);819}820EXPORT_SYMBOL(cdns_read_ping_status);821 822/*823 * IRQ handling824 */825 826static int cdns_update_slave_status(struct sdw_cdns *cdns,827				    u64 slave_intstat)828{829	enum sdw_slave_status status[SDW_MAX_DEVICES + 1];830	bool is_slave = false;831	u32 mask;832	u32 val;833	int i, set_status;834 835	memset(status, 0, sizeof(status));836 837	for (i = 0; i <= SDW_MAX_DEVICES; i++) {838		mask = (slave_intstat >> (i * CDNS_MCP_SLAVE_STATUS_NUM)) &839			CDNS_MCP_SLAVE_STATUS_BITS;840 841		set_status = 0;842 843		if (mask) {844			is_slave = true;845 846			if (mask & CDNS_MCP_SLAVE_INTSTAT_RESERVED) {847				status[i] = SDW_SLAVE_RESERVED;848				set_status++;849			}850 851			if (mask & CDNS_MCP_SLAVE_INTSTAT_ATTACHED) {852				status[i] = SDW_SLAVE_ATTACHED;853				set_status++;854			}855 856			if (mask & CDNS_MCP_SLAVE_INTSTAT_ALERT) {857				status[i] = SDW_SLAVE_ALERT;858				set_status++;859			}860 861			if (mask & CDNS_MCP_SLAVE_INTSTAT_NPRESENT) {862				status[i] = SDW_SLAVE_UNATTACHED;863				set_status++;864			}865		}866 867		/*868		 * check that there was a single reported Slave status and when869		 * there is not use the latest status extracted from PING commands870		 */871		if (set_status != 1) {872			val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);873			val >>= (i * 2);874 875			switch (val & 0x3) {876			case 0:877				status[i] = SDW_SLAVE_UNATTACHED;878				break;879			case 1:880				status[i] = SDW_SLAVE_ATTACHED;881				break;882			case 2:883				status[i] = SDW_SLAVE_ALERT;884				break;885			case 3:886			default:887				status[i] = SDW_SLAVE_RESERVED;888				break;889			}890		}891	}892 893	if (is_slave) {894		int ret;895 896		mutex_lock(&cdns->status_update_lock);897		ret = sdw_handle_slave_status(&cdns->bus, status);898		mutex_unlock(&cdns->status_update_lock);899		return ret;900	}901 902	return 0;903}904 905/**906 * sdw_cdns_irq() - Cadence interrupt handler907 * @irq: irq number908 * @dev_id: irq context909 */910irqreturn_t sdw_cdns_irq(int irq, void *dev_id)911{912	struct sdw_cdns *cdns = dev_id;913	u32 int_status;914 915	/* Check if the link is up */916	if (!cdns->link_up)917		return IRQ_NONE;918 919	int_status = cdns_readl(cdns, CDNS_MCP_INTSTAT);920 921	/* check for reserved values read as zero */922	if (int_status & CDNS_MCP_INT_RESERVED)923		return IRQ_NONE;924 925	if (!(int_status & CDNS_MCP_INT_IRQ))926		return IRQ_NONE;927 928	if (int_status & CDNS_MCP_INT_RX_WL) {929		struct sdw_bus *bus = &cdns->bus;930		struct sdw_defer *defer = &bus->defer_msg;931 932		cdns_read_response(cdns);933 934		if (defer && defer->msg) {935			cdns_fill_msg_resp(cdns, defer->msg,936					   defer->length, 0);937			complete(&defer->complete);938		} else {939			complete(&cdns->tx_complete);940		}941	}942 943	if (int_status & CDNS_MCP_INT_PARITY) {944		/* Parity error detected by Master */945		dev_err_ratelimited(cdns->dev, "Parity error\n");946	}947 948	if (int_status & CDNS_MCP_INT_CTRL_CLASH) {949		/* Slave is driving bit slot during control word */950		dev_err_ratelimited(cdns->dev, "Bus clash for control word\n");951	}952 953	if (int_status & CDNS_MCP_INT_DATA_CLASH) {954		/*955		 * Multiple slaves trying to drive bit slot, or issue with956		 * ownership of data bits or Slave gone bonkers957		 */958		dev_err_ratelimited(cdns->dev, "Bus clash for data word\n");959	}960 961	if (cdns->bus.params.m_data_mode != SDW_PORT_DATA_MODE_NORMAL &&962	    int_status & CDNS_MCP_INT_DPINT) {963		u32 port_intstat;964 965		/* just log which ports report an error */966		port_intstat = cdns_readl(cdns, CDNS_MCP_PORT_INTSTAT);967		dev_err_ratelimited(cdns->dev, "DP interrupt: PortIntStat %8x\n",968				    port_intstat);969 970		/* clear status w/ write1 */971		cdns_writel(cdns, CDNS_MCP_PORT_INTSTAT, port_intstat);972	}973 974	if (int_status & CDNS_MCP_INT_SLAVE_MASK) {975		/* Mask the Slave interrupt and wake thread */976		cdns_updatel(cdns, CDNS_MCP_INTMASK,977			     CDNS_MCP_INT_SLAVE_MASK, 0);978 979		int_status &= ~CDNS_MCP_INT_SLAVE_MASK;980 981		/*982		 * Deal with possible race condition between interrupt983		 * handling and disabling interrupts on suspend.984		 *985		 * If the master is in the process of disabling986		 * interrupts, don't schedule a workqueue987		 */988		if (cdns->interrupt_enabled)989			schedule_work(&cdns->work);990	}991 992	cdns_writel(cdns, CDNS_MCP_INTSTAT, int_status);993	return IRQ_HANDLED;994}995EXPORT_SYMBOL(sdw_cdns_irq);996 997static void cdns_check_attached_status_dwork(struct work_struct *work)998{999	struct sdw_cdns *cdns =1000		container_of(work, struct sdw_cdns, attach_dwork.work);1001	enum sdw_slave_status status[SDW_MAX_DEVICES + 1];1002	u32 val;1003	int ret;1004	int i;1005 1006	val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);1007 1008	for (i = 0; i <= SDW_MAX_DEVICES; i++) {1009		status[i] = val & 0x3;1010		if (status[i])1011			dev_dbg(cdns->dev, "Peripheral %d status: %d\n", i, status[i]);1012		val >>= 2;1013	}1014 1015	mutex_lock(&cdns->status_update_lock);1016	ret = sdw_handle_slave_status(&cdns->bus, status);1017	mutex_unlock(&cdns->status_update_lock);1018	if (ret < 0)1019		dev_err(cdns->dev, "%s: sdw_handle_slave_status failed: %d\n", __func__, ret);1020}1021 1022/**1023 * cdns_update_slave_status_work - update slave status in a work since we will need to handle1024 * other interrupts eg. CDNS_MCP_INT_RX_WL during the update slave1025 * process.1026 * @work: cdns worker thread1027 */1028static void cdns_update_slave_status_work(struct work_struct *work)1029{1030	struct sdw_cdns *cdns =1031		container_of(work, struct sdw_cdns, work);1032	u32 slave0, slave1;1033	u64 slave_intstat;1034	u32 device0_status;1035	int retry_count = 0;1036 1037	/*1038	 * Clear main interrupt first so we don't lose any assertions1039	 * that happen during this function.1040	 */1041	cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_SLAVE_MASK);1042 1043	slave0 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0);1044	slave1 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);1045 1046	/*1047	 * Clear the bits before handling so we don't lose any1048	 * bits that re-assert.1049	 */1050	cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave0);1051	cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave1);1052 1053	/* combine the two status */1054	slave_intstat = ((u64)slave1 << 32) | slave0;1055 1056	dev_dbg_ratelimited(cdns->dev, "Slave status change: 0x%llx\n", slave_intstat);1057 1058update_status:1059	cdns_update_slave_status(cdns, slave_intstat);1060 1061	/*1062	 * When there is more than one peripheral per link, it's1063	 * possible that a deviceB becomes attached after we deal with1064	 * the attachment of deviceA. Since the hardware does a1065	 * logical AND, the attachment of the second device does not1066	 * change the status seen by the driver.1067	 *1068	 * In that case, clearing the registers above would result in1069	 * the deviceB never being detected - until a change of status1070	 * is observed on the bus.1071	 *1072	 * To avoid this race condition, re-check if any device0 needs1073	 * attention with PING commands. There is no need to check for1074	 * ALERTS since they are not allowed until a non-zero1075	 * device_number is assigned.1076	 *1077	 * Do not clear the INTSTAT0/1. While looping to enumerate devices on1078	 * #0 there could be status changes on other devices - these must1079	 * be kept in the INTSTAT so they can be handled when all #0 devices1080	 * have been handled.1081	 */1082 1083	device0_status = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);1084	device0_status &= 3;1085 1086	if (device0_status == SDW_SLAVE_ATTACHED) {1087		if (retry_count++ < SDW_MAX_DEVICES) {1088			dev_dbg_ratelimited(cdns->dev,1089					    "Device0 detected after clearing status, iteration %d\n",1090					    retry_count);1091			slave_intstat = CDNS_MCP_SLAVE_INTSTAT_ATTACHED;1092			goto update_status;1093		} else {1094			dev_err_ratelimited(cdns->dev,1095					    "Device0 detected after %d iterations\n",1096					    retry_count);1097		}1098	}1099 1100	/* unmask Slave interrupt now */1101	cdns_updatel(cdns, CDNS_MCP_INTMASK,1102		     CDNS_MCP_INT_SLAVE_MASK, CDNS_MCP_INT_SLAVE_MASK);1103 1104}1105 1106/* paranoia check to make sure self-cleared bits are indeed cleared */1107void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string,1108				       bool initial_delay, int reset_iterations)1109{1110	u32 ip_mcp_control;1111	u32 mcp_control;1112	u32 mcp_config_update;1113	int i;1114 1115	if (initial_delay)1116		usleep_range(1000, 1500);1117 1118	ip_mcp_control = cdns_ip_readl(cdns, CDNS_IP_MCP_CONTROL);1119 1120	/* the following bits should be cleared immediately */1121	if (ip_mcp_control & CDNS_IP_MCP_CONTROL_SW_RST)1122		dev_err(cdns->dev, "%s failed: IP_MCP_CONTROL_SW_RST is not cleared\n", string);1123 1124	mcp_control = cdns_readl(cdns, CDNS_MCP_CONTROL);1125 1126	/* the following bits should be cleared immediately */1127	if (mcp_control & CDNS_MCP_CONTROL_CMD_RST)1128		dev_err(cdns->dev, "%s failed: MCP_CONTROL_CMD_RST is not cleared\n", string);1129	if (mcp_control & CDNS_MCP_CONTROL_SOFT_RST)1130		dev_err(cdns->dev, "%s failed: MCP_CONTROL_SOFT_RST is not cleared\n", string);1131	if (mcp_control & CDNS_MCP_CONTROL_CLK_STOP_CLR)1132		dev_err(cdns->dev, "%s failed: MCP_CONTROL_CLK_STOP_CLR is not cleared\n", string);1133 1134	mcp_config_update = cdns_readl(cdns, CDNS_MCP_CONFIG_UPDATE);1135	if (mcp_config_update & CDNS_MCP_CONFIG_UPDATE_BIT)1136		dev_err(cdns->dev, "%s failed: MCP_CONFIG_UPDATE_BIT is not cleared\n", string);1137 1138	i = 0;1139	while (mcp_control & CDNS_MCP_CONTROL_HW_RST) {1140		if (i == reset_iterations) {1141			dev_err(cdns->dev, "%s failed: MCP_CONTROL_HW_RST is not cleared\n", string);1142			break;1143		}1144 1145		dev_dbg(cdns->dev, "%s: MCP_CONTROL_HW_RST is not cleared at iteration %d\n", string, i);1146		i++;1147 1148		usleep_range(1000, 1500);1149		mcp_control = cdns_readl(cdns, CDNS_MCP_CONTROL);1150	}1151 1152}1153EXPORT_SYMBOL(sdw_cdns_check_self_clearing_bits);1154 1155/*1156 * init routines1157 */1158 1159/**1160 * sdw_cdns_exit_reset() - Program reset parameters and start bus operations1161 * @cdns: Cadence instance1162 */1163int sdw_cdns_exit_reset(struct sdw_cdns *cdns)1164{1165	/* keep reset delay unchanged to 4096 cycles */1166 1167	/* use hardware generated reset */1168	cdns_updatel(cdns, CDNS_MCP_CONTROL,1169		     CDNS_MCP_CONTROL_HW_RST,1170		     CDNS_MCP_CONTROL_HW_RST);1171 1172	/* commit changes */1173	return cdns_config_update(cdns);1174}1175EXPORT_SYMBOL(sdw_cdns_exit_reset);1176 1177/**1178 * cdns_enable_slave_interrupts() - Enable SDW slave interrupts1179 * @cdns: Cadence instance1180 * @state: boolean for true/false1181 */1182static void cdns_enable_slave_interrupts(struct sdw_cdns *cdns, bool state)1183{1184	u32 mask;1185 1186	mask = cdns_readl(cdns, CDNS_MCP_INTMASK);1187	if (state)1188		mask |= CDNS_MCP_INT_SLAVE_MASK;1189	else1190		mask &= ~CDNS_MCP_INT_SLAVE_MASK;1191 1192	cdns_writel(cdns, CDNS_MCP_INTMASK, mask);1193}1194 1195/**1196 * sdw_cdns_enable_interrupt() - Enable SDW interrupts1197 * @cdns: Cadence instance1198 * @state: True if we are trying to enable interrupt.1199 */1200int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state)1201{1202	u32 slave_intmask0 = 0;1203	u32 slave_intmask1 = 0;1204	u32 mask = 0;1205 1206	if (!state)1207		goto update_masks;1208 1209	slave_intmask0 = CDNS_MCP_SLAVE_INTMASK0_MASK;1210	slave_intmask1 = CDNS_MCP_SLAVE_INTMASK1_MASK;1211 1212	/* enable detection of all slave state changes */1213	mask = CDNS_MCP_INT_SLAVE_MASK;1214 1215	/* enable detection of bus issues */1216	mask |= CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |1217		CDNS_MCP_INT_PARITY;1218 1219	/* port interrupt limited to test modes for now */1220	if (cdns->bus.params.m_data_mode != SDW_PORT_DATA_MODE_NORMAL)1221		mask |= CDNS_MCP_INT_DPINT;1222 1223	/* enable detection of RX fifo level */1224	mask |= CDNS_MCP_INT_RX_WL;1225 1226	/*1227	 * CDNS_MCP_INT_IRQ needs to be set otherwise all previous1228	 * settings are irrelevant1229	 */1230	mask |= CDNS_MCP_INT_IRQ;1231 1232	if (interrupt_mask) /* parameter override */1233		mask = interrupt_mask;1234 1235update_masks:1236	/* clear slave interrupt status before enabling interrupt */1237	if (state) {1238		u32 slave_state;1239 1240		slave_state = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0);1241		cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave_state);1242		slave_state = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);1243		cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave_state);1244	}1245	cdns->interrupt_enabled = state;1246 1247	/*1248	 * Complete any on-going status updates before updating masks,1249	 * and cancel queued status updates.1250	 *1251	 * There could be a race with a new interrupt thrown before1252	 * the 3 mask updates below are complete, so in the interrupt1253	 * we use the 'interrupt_enabled' status to prevent new work1254	 * from being queued.1255	 */1256	if (!state)1257		cancel_work_sync(&cdns->work);1258 1259	cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0, slave_intmask0);1260	cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1, slave_intmask1);1261	cdns_writel(cdns, CDNS_MCP_INTMASK, mask);1262 1263	return 0;1264}1265EXPORT_SYMBOL(sdw_cdns_enable_interrupt);1266 1267static int cdns_allocate_pdi(struct sdw_cdns *cdns,1268			     struct sdw_cdns_pdi **stream,1269			     u32 num)1270{1271	struct sdw_cdns_pdi *pdi;1272	int i;1273 1274	if (!num)1275		return 0;1276 1277	pdi = devm_kcalloc(cdns->dev, num, sizeof(*pdi), GFP_KERNEL);1278	if (!pdi)1279		return -ENOMEM;1280 1281	for (i = 0; i < num; i++) {1282		pdi[i].num = i;1283	}1284 1285	*stream = pdi;1286	return 0;1287}1288 1289/**1290 * sdw_cdns_pdi_init() - PDI initialization routine1291 *1292 * @cdns: Cadence instance1293 * @config: Stream configurations1294 */1295int sdw_cdns_pdi_init(struct sdw_cdns *cdns,1296		      struct sdw_cdns_stream_config config)1297{1298	struct sdw_cdns_streams *stream;1299	int ret;1300 1301	cdns->pcm.num_bd = config.pcm_bd;1302	cdns->pcm.num_in = config.pcm_in;1303	cdns->pcm.num_out = config.pcm_out;1304 1305	/* Allocate PDIs for PCMs */1306	stream = &cdns->pcm;1307 1308	/* we allocate PDI0 and PDI1 which are used for Bulk */1309	ret = cdns_allocate_pdi(cdns, &stream->bd, stream->num_bd);1310	if (ret)1311		return ret;1312 1313	ret = cdns_allocate_pdi(cdns, &stream->in, stream->num_in);1314	if (ret)1315		return ret;1316 1317	ret = cdns_allocate_pdi(cdns, &stream->out, stream->num_out);1318	if (ret)1319		return ret;1320 1321	/* Update total number of PCM PDIs */1322	stream->num_pdi = stream->num_bd + stream->num_in + stream->num_out;1323	cdns->num_ports = stream->num_pdi;1324 1325	return 0;1326}1327EXPORT_SYMBOL(sdw_cdns_pdi_init);1328 1329static u32 cdns_set_initial_frame_shape(int n_rows, int n_cols)1330{1331	u32 val;1332	int c;1333	int r;1334 1335	r = sdw_find_row_index(n_rows);1336	c = sdw_find_col_index(n_cols);1337 1338	val = FIELD_PREP(CDNS_MCP_FRAME_SHAPE_ROW_MASK, r);1339	val |= FIELD_PREP(CDNS_MCP_FRAME_SHAPE_COL_MASK, c);1340 1341	return val;1342}1343 1344static void cdns_init_clock_ctrl(struct sdw_cdns *cdns)1345{1346	struct sdw_bus *bus = &cdns->bus;1347	struct sdw_master_prop *prop = &bus->prop;1348	u32 val;1349	u32 ssp_interval;1350	int divider;1351 1352	dev_dbg(cdns->dev, "mclk %d max %d row %d col %d\n",1353		prop->mclk_freq,1354		prop->max_clk_freq,1355		prop->default_row,1356		prop->default_col);1357 1358	/* Set clock divider */1359	divider	= (prop->mclk_freq / prop->max_clk_freq) - 1;1360 1361	cdns_updatel(cdns, CDNS_MCP_CLK_CTRL0,1362		     CDNS_MCP_CLK_MCLKD_MASK, divider);1363	cdns_updatel(cdns, CDNS_MCP_CLK_CTRL1,1364		     CDNS_MCP_CLK_MCLKD_MASK, divider);1365 1366	/*1367	 * Frame shape changes after initialization have to be done1368	 * with the bank switch mechanism1369	 */1370	val = cdns_set_initial_frame_shape(prop->default_row,1371					   prop->default_col);1372	cdns_writel(cdns, CDNS_MCP_FRAME_SHAPE_INIT, val);1373 1374	/* Set SSP interval to default value */1375	ssp_interval = prop->default_frame_rate / SDW_CADENCE_GSYNC_HZ;1376	cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, ssp_interval);1377	cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, ssp_interval);1378}1379 1380/**1381 * sdw_cdns_init() - Cadence initialization1382 * @cdns: Cadence instance1383 */1384int sdw_cdns_init(struct sdw_cdns *cdns)1385{1386	u32 val;1387 1388	cdns_init_clock_ctrl(cdns);1389 1390	sdw_cdns_check_self_clearing_bits(cdns, __func__, false, 0);1391 1392	/* reset msg_count to default value of FIFOLEVEL */1393	cdns->msg_count = cdns_readl(cdns, CDNS_MCP_FIFOLEVEL);1394 1395	/* flush command FIFOs */1396	cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_RST,1397		     CDNS_MCP_CONTROL_CMD_RST);1398 1399	/* Set cmd accept mode */1400	cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, CDNS_IP_MCP_CONTROL_CMD_ACCEPT,1401			CDNS_IP_MCP_CONTROL_CMD_ACCEPT);1402 1403	/* Configure mcp config */1404	val = cdns_readl(cdns, CDNS_MCP_CONFIG);1405 1406	/* Disable auto bus release */1407	val &= ~CDNS_MCP_CONFIG_BUS_REL;1408 1409	cdns_writel(cdns, CDNS_MCP_CONFIG, val);1410 1411	/* Configure IP mcp config */1412	val = cdns_ip_readl(cdns, CDNS_IP_MCP_CONFIG);1413 1414	/* enable bus operations with clock and data */1415	val &= ~CDNS_IP_MCP_CONFIG_OP;1416	val |= CDNS_IP_MCP_CONFIG_OP_NORMAL;1417 1418	/* Set cmd mode for Tx and Rx cmds */1419	val &= ~CDNS_IP_MCP_CONFIG_CMD;1420 1421	/* Disable sniffer mode */1422	val &= ~CDNS_IP_MCP_CONFIG_SNIFFER;1423 1424	if (cdns->bus.multi_link)1425		/* Set Multi-master mode to take gsync into account */1426		val |= CDNS_IP_MCP_CONFIG_MMASTER;1427 1428	/* leave frame delay to hardware default of 0x1F */1429 1430	/* leave command retry to hardware default of 0 */1431 1432	cdns_ip_writel(cdns, CDNS_IP_MCP_CONFIG, val);1433 1434	/* changes will be committed later */1435	return 0;1436}1437EXPORT_SYMBOL(sdw_cdns_init);1438 1439int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)1440{1441	struct sdw_master_prop *prop = &bus->prop;1442	struct sdw_cdns *cdns = bus_to_cdns(bus);1443	int mcp_clkctrl_off;1444	int divider;1445 1446	if (!params->curr_dr_freq) {1447		dev_err(cdns->dev, "NULL curr_dr_freq\n");1448		return -EINVAL;1449	}1450 1451	divider	= prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR /1452		params->curr_dr_freq;1453	divider--; /* divider is 1/(N+1) */1454 1455	if (params->next_bank)1456		mcp_clkctrl_off = CDNS_MCP_CLK_CTRL1;1457	else1458		mcp_clkctrl_off = CDNS_MCP_CLK_CTRL0;1459 1460	cdns_updatel(cdns, mcp_clkctrl_off, CDNS_MCP_CLK_MCLKD_MASK, divider);1461 1462	return 0;1463}1464EXPORT_SYMBOL(cdns_bus_conf);1465 1466static int cdns_port_params(struct sdw_bus *bus,1467			    struct sdw_port_params *p_params, unsigned int bank)1468{1469	struct sdw_cdns *cdns = bus_to_cdns(bus);1470	int dpn_config_off_source;1471	int dpn_config_off_target;1472	int target_num = p_params->num;1473	int source_num = p_params->num;1474	bool override = false;1475	int dpn_config;1476 1477	if (target_num == cdns->pdi_loopback_target &&1478	    cdns->pdi_loopback_source != -1) {1479		source_num = cdns->pdi_loopback_source;1480		override = true;1481	}1482 1483	if (bank) {1484		dpn_config_off_source = CDNS_DPN_B1_CONFIG(source_num);1485		dpn_config_off_target = CDNS_DPN_B1_CONFIG(target_num);1486	} else {1487		dpn_config_off_source = CDNS_DPN_B0_CONFIG(source_num);1488		dpn_config_off_target = CDNS_DPN_B0_CONFIG(target_num);1489	}1490 1491	dpn_config = cdns_readl(cdns, dpn_config_off_source);1492 1493	/* use port params if there is no loopback, otherwise use source as is */1494	if (!override) {1495		u32p_replace_bits(&dpn_config, p_params->bps - 1, CDNS_DPN_CONFIG_WL);1496		u32p_replace_bits(&dpn_config, p_params->flow_mode, CDNS_DPN_CONFIG_PORT_FLOW);1497		u32p_replace_bits(&dpn_config, p_params->data_mode, CDNS_DPN_CONFIG_PORT_DAT);1498	}1499 1500	cdns_writel(cdns, dpn_config_off_target, dpn_config);1501 1502	return 0;1503}1504 1505static int cdns_transport_params(struct sdw_bus *bus,1506				 struct sdw_transport_params *t_params,1507				 enum sdw_reg_bank bank)1508{1509	struct sdw_cdns *cdns = bus_to_cdns(bus);1510	int dpn_config;1511	int dpn_config_off_source;1512	int dpn_config_off_target;1513	int dpn_hctrl;1514	int dpn_hctrl_off_source;1515	int dpn_hctrl_off_target;1516	int dpn_offsetctrl;1517	int dpn_offsetctrl_off_source;1518	int dpn_offsetctrl_off_target;1519	int dpn_samplectrl;1520	int dpn_samplectrl_off_source;1521	int dpn_samplectrl_off_target;1522	int source_num = t_params->port_num;1523	int target_num = t_params->port_num;1524	bool override = false;1525 1526	if (target_num == cdns->pdi_loopback_target &&1527	    cdns->pdi_loopback_source != -1) {1528		source_num = cdns->pdi_loopback_source;1529		override = true;1530	}1531 1532	/*1533	 * Note: Only full data port is supported on the Master side for1534	 * both PCM and PDM ports.1535	 */1536 1537	if (bank) {1538		dpn_config_off_source = CDNS_DPN_B1_CONFIG(source_num);1539		dpn_hctrl_off_source = CDNS_DPN_B1_HCTRL(source_num);1540		dpn_offsetctrl_off_source = CDNS_DPN_B1_OFFSET_CTRL(source_num);1541		dpn_samplectrl_off_source = CDNS_DPN_B1_SAMPLE_CTRL(source_num);1542 1543		dpn_config_off_target = CDNS_DPN_B1_CONFIG(target_num);1544		dpn_hctrl_off_target = CDNS_DPN_B1_HCTRL(target_num);1545		dpn_offsetctrl_off_target = CDNS_DPN_B1_OFFSET_CTRL(target_num);1546		dpn_samplectrl_off_target = CDNS_DPN_B1_SAMPLE_CTRL(target_num);1547 1548	} else {1549		dpn_config_off_source = CDNS_DPN_B0_CONFIG(source_num);1550		dpn_hctrl_off_source = CDNS_DPN_B0_HCTRL(source_num);1551		dpn_offsetctrl_off_source = CDNS_DPN_B0_OFFSET_CTRL(source_num);1552		dpn_samplectrl_off_source = CDNS_DPN_B0_SAMPLE_CTRL(source_num);1553 1554		dpn_config_off_target = CDNS_DPN_B0_CONFIG(target_num);1555		dpn_hctrl_off_target = CDNS_DPN_B0_HCTRL(target_num);1556		dpn_offsetctrl_off_target = CDNS_DPN_B0_OFFSET_CTRL(target_num);1557		dpn_samplectrl_off_target = CDNS_DPN_B0_SAMPLE_CTRL(target_num);1558	}1559 1560	dpn_config = cdns_readl(cdns, dpn_config_off_source);1561	if (!override) {1562		u32p_replace_bits(&dpn_config, t_params->blk_grp_ctrl, CDNS_DPN_CONFIG_BGC);1563		u32p_replace_bits(&dpn_config, t_params->blk_pkg_mode, CDNS_DPN_CONFIG_BPM);1564	}1565	cdns_writel(cdns, dpn_config_off_target, dpn_config);1566 1567	if (!override) {1568		dpn_offsetctrl = 0;1569		u32p_replace_bits(&dpn_offsetctrl, t_params->offset1, CDNS_DPN_OFFSET_CTRL_1);1570		u32p_replace_bits(&dpn_offsetctrl, t_params->offset2, CDNS_DPN_OFFSET_CTRL_2);1571	} else {1572		dpn_offsetctrl = cdns_readl(cdns, dpn_offsetctrl_off_source);1573	}1574	cdns_writel(cdns, dpn_offsetctrl_off_target,  dpn_offsetctrl);1575 1576	if (!override) {1577		dpn_hctrl = 0;1578		u32p_replace_bits(&dpn_hctrl, t_params->hstart, CDNS_DPN_HCTRL_HSTART);1579		u32p_replace_bits(&dpn_hctrl, t_params->hstop, CDNS_DPN_HCTRL_HSTOP);1580		u32p_replace_bits(&dpn_hctrl, t_params->lane_ctrl, CDNS_DPN_HCTRL_LCTRL);1581	} else {1582		dpn_hctrl = cdns_readl(cdns, dpn_hctrl_off_source);1583	}1584	cdns_writel(cdns, dpn_hctrl_off_target, dpn_hctrl);1585 1586	if (!override)1587		dpn_samplectrl = t_params->sample_interval - 1;1588	else1589		dpn_samplectrl = cdns_readl(cdns, dpn_samplectrl_off_source);1590	cdns_writel(cdns, dpn_samplectrl_off_target, dpn_samplectrl);1591 1592	return 0;1593}1594 1595static int cdns_port_enable(struct sdw_bus *bus,1596			    struct sdw_enable_ch *enable_ch, unsigned int bank)1597{1598	struct sdw_cdns *cdns = bus_to_cdns(bus);1599	int dpn_chnen_off, ch_mask;1600 1601	if (bank)1602		dpn_chnen_off = CDNS_DPN_B1_CH_EN(enable_ch->port_num);1603	else1604		dpn_chnen_off = CDNS_DPN_B0_CH_EN(enable_ch->port_num);1605 1606	ch_mask = enable_ch->ch_mask * enable_ch->enable;1607	cdns_writel(cdns, dpn_chnen_off, ch_mask);1608 1609	return 0;1610}1611 1612static const struct sdw_master_port_ops cdns_port_ops = {1613	.dpn_set_port_params = cdns_port_params,1614	.dpn_set_port_transport_params = cdns_transport_params,1615	.dpn_port_enable_ch = cdns_port_enable,1616};1617 1618/**1619 * sdw_cdns_is_clock_stop: Check clock status1620 *1621 * @cdns: Cadence instance1622 */1623bool sdw_cdns_is_clock_stop(struct sdw_cdns *cdns)1624{1625	return !!(cdns_readl(cdns, CDNS_MCP_STAT) & CDNS_MCP_STAT_CLK_STOP);1626}1627EXPORT_SYMBOL(sdw_cdns_is_clock_stop);1628 1629/**1630 * sdw_cdns_clock_stop: Cadence clock stop configuration routine1631 *1632 * @cdns: Cadence instance1633 * @block_wake: prevent wakes if required by the platform1634 */1635int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake)1636{1637	bool slave_present = false;1638	struct sdw_slave *slave;1639	int ret;1640 1641	sdw_cdns_check_self_clearing_bits(cdns, __func__, false, 0);1642 1643	/* Check suspend status */1644	if (sdw_cdns_is_clock_stop(cdns)) {1645		dev_dbg(cdns->dev, "Clock is already stopped\n");1646		return 0;1647	}1648 1649	/*1650	 * Before entering clock stop we mask the Slave1651	 * interrupts. This helps avoid having to deal with e.g. a1652	 * Slave becoming UNATTACHED while the clock is being stopped1653	 */1654	cdns_enable_slave_interrupts(cdns, false);1655 1656	/*1657	 * For specific platforms, it is required to be able to put1658	 * master into a state in which it ignores wake-up trials1659	 * in clock stop state1660	 */1661	if (block_wake)1662		cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL,1663				CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP,1664				CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP);1665 1666	list_for_each_entry(slave, &cdns->bus.slaves, node) {1667		if (slave->status == SDW_SLAVE_ATTACHED ||1668		    slave->status == SDW_SLAVE_ALERT) {1669			slave_present = true;1670			break;1671		}1672	}1673 1674	/* commit changes */1675	ret = cdns_config_update(cdns);1676	if (ret < 0) {1677		dev_err(cdns->dev, "%s: config_update failed\n", __func__);1678		return ret;1679	}1680 1681	/* Prepare slaves for clock stop */1682	if (slave_present) {1683		ret = sdw_bus_prep_clk_stop(&cdns->bus);1684		if (ret < 0 && ret != -ENODATA) {1685			dev_err(cdns->dev, "prepare clock stop failed %d\n", ret);1686			return ret;1687		}1688	}1689 1690	/*1691	 * Enter clock stop mode and only report errors if there are1692	 * Slave devices present (ALERT or ATTACHED)1693	 */1694	ret = sdw_bus_clk_stop(&cdns->bus);1695	if (ret < 0 && slave_present && ret != -ENODATA) {1696		dev_err(cdns->dev, "bus clock stop failed %d\n", ret);1697		return ret;1698	}1699 1700	ret = cdns_set_wait(cdns, CDNS_MCP_STAT,1701			    CDNS_MCP_STAT_CLK_STOP,1702			    CDNS_MCP_STAT_CLK_STOP);1703	if (ret < 0)1704		dev_err(cdns->dev, "Clock stop failed %d\n", ret);1705 1706	return ret;1707}1708EXPORT_SYMBOL(sdw_cdns_clock_stop);1709 1710/**1711 * sdw_cdns_clock_restart: Cadence PM clock restart configuration routine1712 *1713 * @cdns: Cadence instance1714 * @bus_reset: context may be lost while in low power modes and the bus1715 * may require a Severe Reset and re-enumeration after a wake.1716 */1717int sdw_cdns_clock_restart(struct sdw_cdns *cdns, bool bus_reset)1718{1719	int ret;1720 1721	/* unmask Slave interrupts that were masked when stopping the clock */1722	cdns_enable_slave_interrupts(cdns, true);1723 1724	ret = cdns_clear_bit(cdns, CDNS_MCP_CONTROL,1725			     CDNS_MCP_CONTROL_CLK_STOP_CLR);1726	if (ret < 0) {1727		dev_err(cdns->dev, "Couldn't exit from clock stop\n");1728		return ret;1729	}1730 1731	ret = cdns_set_wait(cdns, CDNS_MCP_STAT, CDNS_MCP_STAT_CLK_STOP, 0);1732	if (ret < 0) {1733		dev_err(cdns->dev, "clock stop exit failed %d\n", ret);1734		return ret;1735	}1736 1737	cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL,1738			CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP, 0);1739 1740	cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, CDNS_IP_MCP_CONTROL_CMD_ACCEPT,1741			CDNS_IP_MCP_CONTROL_CMD_ACCEPT);1742 1743	if (!bus_reset) {1744 1745		/* enable bus operations with clock and data */1746		cdns_ip_updatel(cdns, CDNS_IP_MCP_CONFIG,1747				CDNS_IP_MCP_CONFIG_OP,1748				CDNS_IP_MCP_CONFIG_OP_NORMAL);1749 1750		ret = cdns_config_update(cdns);1751		if (ret < 0) {1752			dev_err(cdns->dev, "%s: config_update failed\n", __func__);1753			return ret;1754		}1755 1756		ret = sdw_bus_exit_clk_stop(&cdns->bus);1757		if (ret < 0)1758			dev_err(cdns->dev, "bus failed to exit clock stop %d\n", ret);1759	}1760 1761	return ret;1762}1763EXPORT_SYMBOL(sdw_cdns_clock_restart);1764 1765/**1766 * sdw_cdns_probe() - Cadence probe routine1767 * @cdns: Cadence instance1768 */1769int sdw_cdns_probe(struct sdw_cdns *cdns)1770{1771	init_completion(&cdns->tx_complete);1772	cdns->bus.port_ops = &cdns_port_ops;1773 1774	mutex_init(&cdns->status_update_lock);1775 1776	INIT_WORK(&cdns->work, cdns_update_slave_status_work);1777	INIT_DELAYED_WORK(&cdns->attach_dwork, cdns_check_attached_status_dwork);1778 1779	return 0;1780}1781EXPORT_SYMBOL(sdw_cdns_probe);1782 1783int cdns_set_sdw_stream(struct snd_soc_dai *dai,1784			void *stream, int direction)1785{1786	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);1787	struct sdw_cdns_dai_runtime *dai_runtime;1788 1789	dai_runtime = cdns->dai_runtime_array[dai->id];1790 1791	if (stream) {1792		/* first paranoia check */1793		if (dai_runtime) {1794			dev_err(dai->dev,1795				"dai_runtime already allocated for dai %s\n",1796				dai->name);1797			return -EINVAL;1798		}1799 1800		/* allocate and set dai_runtime info */1801		dai_runtime = kzalloc(sizeof(*dai_runtime), GFP_KERNEL);1802		if (!dai_runtime)1803			return -ENOMEM;1804 1805		dai_runtime->stream_type = SDW_STREAM_PCM;1806 1807		dai_runtime->bus = &cdns->bus;1808		dai_runtime->link_id = cdns->instance;1809 1810		dai_runtime->stream = stream;1811		dai_runtime->direction = direction;1812 1813		cdns->dai_runtime_array[dai->id] = dai_runtime;1814	} else {1815		/* second paranoia check */1816		if (!dai_runtime) {1817			dev_err(dai->dev,1818				"dai_runtime not allocated for dai %s\n",1819				dai->name);1820			return -EINVAL;1821		}1822 1823		/* for NULL stream we release allocated dai_runtime */1824		kfree(dai_runtime);1825		cdns->dai_runtime_array[dai->id] = NULL;1826	}1827	return 0;1828}1829EXPORT_SYMBOL(cdns_set_sdw_stream);1830 1831/**1832 * cdns_find_pdi() - Find a free PDI1833 *1834 * @cdns: Cadence instance1835 * @num: Number of PDIs1836 * @pdi: PDI instances1837 * @dai_id: DAI id1838 *1839 * Find a PDI for a given PDI array. The PDI num and dai_id are1840 * expected to match, return NULL otherwise.1841 */1842static struct sdw_cdns_pdi *cdns_find_pdi(struct sdw_cdns *cdns,1843					  unsigned int num,1844					  struct sdw_cdns_pdi *pdi,1845					  int dai_id)1846{1847	int i;1848 1849	for (i = 0; i < num; i++)1850		if (pdi[i].num == dai_id)1851			return &pdi[i];1852 1853	return NULL;1854}1855 1856/**1857 * sdw_cdns_config_stream: Configure a stream1858 *1859 * @cdns: Cadence instance1860 * @ch: Channel count1861 * @dir: Data direction1862 * @pdi: PDI to be used1863 */1864void sdw_cdns_config_stream(struct sdw_cdns *cdns,1865			    u32 ch, u32 dir, struct sdw_cdns_pdi *pdi)1866{1867	u32 offset, val = 0;1868 1869	if (dir == SDW_DATA_DIR_RX) {1870		val = CDNS_PORTCTRL_DIRN;1871 1872		if (cdns->bus.params.m_data_mode != SDW_PORT_DATA_MODE_NORMAL)1873			val |= CDNS_PORTCTRL_TEST_FAILED;1874	}1875	offset = CDNS_PORTCTRL + pdi->num * CDNS_PORT_OFFSET;1876	cdns_updatel(cdns, offset,1877		     CDNS_PORTCTRL_DIRN | CDNS_PORTCTRL_TEST_FAILED,1878		     val);1879 1880	val = pdi->num;1881	val |= CDNS_PDI_CONFIG_SOFT_RESET;1882	val |= FIELD_PREP(CDNS_PDI_CONFIG_CHANNEL, (1 << ch) - 1);1883	cdns_writel(cdns, CDNS_PDI_CONFIG(pdi->num), val);1884}1885EXPORT_SYMBOL(sdw_cdns_config_stream);1886 1887/**1888 * sdw_cdns_alloc_pdi() - Allocate a PDI1889 *1890 * @cdns: Cadence instance1891 * @stream: Stream to be allocated1892 * @ch: Channel count1893 * @dir: Data direction1894 * @dai_id: DAI id1895 */1896struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns,1897					struct sdw_cdns_streams *stream,1898					u32 ch, u32 dir, int dai_id)1899{1900	struct sdw_cdns_pdi *pdi = NULL;1901 1902	if (dir == SDW_DATA_DIR_RX)1903		pdi = cdns_find_pdi(cdns, stream->num_in, stream->in,1904				    dai_id);1905	else1906		pdi = cdns_find_pdi(cdns, stream->num_out, stream->out,1907				    dai_id);1908 1909	/* check if we found a PDI, else find in bi-directional */1910	if (!pdi)1911		pdi = cdns_find_pdi(cdns, stream->num_bd, stream->bd,1912				    dai_id);1913 1914	if (pdi) {1915		pdi->l_ch_num = 0;1916		pdi->h_ch_num = ch - 1;1917		pdi->dir = dir;1918		pdi->ch_count = ch;1919	}1920 1921	return pdi;1922}1923EXPORT_SYMBOL(sdw_cdns_alloc_pdi);1924 1925MODULE_LICENSE("Dual BSD/GPL");1926MODULE_DESCRIPTION("Cadence Soundwire Library");1927