xref: /openbmc/linux/drivers/soundwire/intel.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
171bb8a1bSVinod Koul // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
271bb8a1bSVinod Koul // Copyright(c) 2015-17 Intel Corporation.
371bb8a1bSVinod Koul 
471bb8a1bSVinod Koul /*
571bb8a1bSVinod Koul  * Soundwire Intel Master Driver
671bb8a1bSVinod Koul  */
771bb8a1bSVinod Koul 
871bb8a1bSVinod Koul #include <linux/acpi.h>
979ee6631SPierre-Louis Bossart #include <linux/debugfs.h>
1071bb8a1bSVinod Koul #include <linux/delay.h>
11df72b719SPierre-Louis Bossart #include <linux/io.h>
1237a2d22bSVinod Koul #include <sound/pcm_params.h>
13ab2c9132SRander Wang #include <linux/pm_runtime.h>
1437a2d22bSVinod Koul #include <sound/soc.h>
1571bb8a1bSVinod Koul #include <linux/soundwire/sdw_registers.h>
1671bb8a1bSVinod Koul #include <linux/soundwire/sdw.h>
1771bb8a1bSVinod Koul #include <linux/soundwire/sdw_intel.h>
1871bb8a1bSVinod Koul #include "cadence_master.h"
1979ee6631SPierre-Louis Bossart #include "bus.h"
2071bb8a1bSVinod Koul #include "intel.h"
2171bb8a1bSVinod Koul 
intel_wait_bit(void __iomem * base,int offset,u32 mask,u32 target)227d2845d5SPierre-Louis Bossart static int intel_wait_bit(void __iomem *base, int offset, u32 mask, u32 target)
2371bb8a1bSVinod Koul {
2471bb8a1bSVinod Koul 	int timeout = 10;
2571bb8a1bSVinod Koul 	u32 reg_read;
2671bb8a1bSVinod Koul 
2771bb8a1bSVinod Koul 	do {
2871bb8a1bSVinod Koul 		reg_read = readl(base + offset);
297d2845d5SPierre-Louis Bossart 		if ((reg_read & mask) == target)
3071bb8a1bSVinod Koul 			return 0;
3171bb8a1bSVinod Koul 
3271bb8a1bSVinod Koul 		timeout--;
337d2845d5SPierre-Louis Bossart 		usleep_range(50, 100);
3471bb8a1bSVinod Koul 	} while (timeout != 0);
3571bb8a1bSVinod Koul 
3671bb8a1bSVinod Koul 	return -EAGAIN;
3771bb8a1bSVinod Koul }
3871bb8a1bSVinod Koul 
intel_clear_bit(void __iomem * base,int offset,u32 value,u32 mask)397d2845d5SPierre-Louis Bossart static int intel_clear_bit(void __iomem *base, int offset, u32 value, u32 mask)
407d2845d5SPierre-Louis Bossart {
417d2845d5SPierre-Louis Bossart 	writel(value, base + offset);
427d2845d5SPierre-Louis Bossart 	return intel_wait_bit(base, offset, mask, 0);
437d2845d5SPierre-Louis Bossart }
447d2845d5SPierre-Louis Bossart 
intel_set_bit(void __iomem * base,int offset,u32 value,u32 mask)4571bb8a1bSVinod Koul static int intel_set_bit(void __iomem *base, int offset, u32 value, u32 mask)
4671bb8a1bSVinod Koul {
4771bb8a1bSVinod Koul 	writel(value, base + offset);
487d2845d5SPierre-Louis Bossart 	return intel_wait_bit(base, offset, mask, mask);
4971bb8a1bSVinod Koul }
5071bb8a1bSVinod Koul 
5171bb8a1bSVinod Koul /*
5279ee6631SPierre-Louis Bossart  * debugfs
5379ee6631SPierre-Louis Bossart  */
5479ee6631SPierre-Louis Bossart #ifdef CONFIG_DEBUG_FS
5579ee6631SPierre-Louis Bossart 
5679ee6631SPierre-Louis Bossart #define RD_BUF (2 * PAGE_SIZE)
5779ee6631SPierre-Louis Bossart 
intel_sprintf(void __iomem * mem,bool l,char * buf,size_t pos,unsigned int reg)5879ee6631SPierre-Louis Bossart static ssize_t intel_sprintf(void __iomem *mem, bool l,
5979ee6631SPierre-Louis Bossart 			     char *buf, size_t pos, unsigned int reg)
6079ee6631SPierre-Louis Bossart {
6179ee6631SPierre-Louis Bossart 	int value;
6279ee6631SPierre-Louis Bossart 
6379ee6631SPierre-Louis Bossart 	if (l)
6479ee6631SPierre-Louis Bossart 		value = intel_readl(mem, reg);
6579ee6631SPierre-Louis Bossart 	else
6679ee6631SPierre-Louis Bossart 		value = intel_readw(mem, reg);
6779ee6631SPierre-Louis Bossart 
6879ee6631SPierre-Louis Bossart 	return scnprintf(buf + pos, RD_BUF - pos, "%4x\t%4x\n", reg, value);
6979ee6631SPierre-Louis Bossart }
7079ee6631SPierre-Louis Bossart 
intel_reg_show(struct seq_file * s_file,void * data)7179ee6631SPierre-Louis Bossart static int intel_reg_show(struct seq_file *s_file, void *data)
7279ee6631SPierre-Louis Bossart {
7379ee6631SPierre-Louis Bossart 	struct sdw_intel *sdw = s_file->private;
742523486bSPierre-Louis Bossart 	void __iomem *s = sdw->link_res->shim;
752523486bSPierre-Louis Bossart 	void __iomem *a = sdw->link_res->alh;
7679ee6631SPierre-Louis Bossart 	char *buf;
7779ee6631SPierre-Louis Bossart 	ssize_t ret;
7879ee6631SPierre-Louis Bossart 	int i, j;
7979ee6631SPierre-Louis Bossart 	unsigned int links, reg;
8079ee6631SPierre-Louis Bossart 
8179ee6631SPierre-Louis Bossart 	buf = kzalloc(RD_BUF, GFP_KERNEL);
8279ee6631SPierre-Louis Bossart 	if (!buf)
8379ee6631SPierre-Louis Bossart 		return -ENOMEM;
8479ee6631SPierre-Louis Bossart 
857f817068SPierre-Louis Bossart 	links = intel_readl(s, SDW_SHIM_LCAP) & SDW_SHIM_LCAP_LCOUNT_MASK;
8679ee6631SPierre-Louis Bossart 
8779ee6631SPierre-Louis Bossart 	ret = scnprintf(buf, RD_BUF, "Register  Value\n");
8879ee6631SPierre-Louis Bossart 	ret += scnprintf(buf + ret, RD_BUF - ret, "\nShim\n");
8979ee6631SPierre-Louis Bossart 
9079ee6631SPierre-Louis Bossart 	for (i = 0; i < links; i++) {
9179ee6631SPierre-Louis Bossart 		reg = SDW_SHIM_LCAP + i * 4;
9279ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, true, buf, ret, reg);
9379ee6631SPierre-Louis Bossart 	}
9479ee6631SPierre-Louis Bossart 
9579ee6631SPierre-Louis Bossart 	for (i = 0; i < links; i++) {
9679ee6631SPierre-Louis Bossart 		ret += scnprintf(buf + ret, RD_BUF - ret, "\nLink%d\n", i);
9779ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLSCAP(i));
9879ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS0CM(i));
9979ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS1CM(i));
10079ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS2CM(i));
10179ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS3CM(i));
10279ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PCMSCAP(i));
10379ee6631SPierre-Louis Bossart 
10479ee6631SPierre-Louis Bossart 		ret += scnprintf(buf + ret, RD_BUF - ret, "\n PCMSyCH registers\n");
10579ee6631SPierre-Louis Bossart 
10679ee6631SPierre-Louis Bossart 		/*
10779ee6631SPierre-Louis Bossart 		 * the value 10 is the number of PDIs. We will need a
10879ee6631SPierre-Louis Bossart 		 * cleanup to remove hard-coded Intel configurations
10979ee6631SPierre-Louis Bossart 		 * from cadence_master.c
11079ee6631SPierre-Louis Bossart 		 */
11179ee6631SPierre-Louis Bossart 		for (j = 0; j < 10; j++) {
11279ee6631SPierre-Louis Bossart 			ret += intel_sprintf(s, false, buf, ret,
11379ee6631SPierre-Louis Bossart 					SDW_SHIM_PCMSYCHM(i, j));
11479ee6631SPierre-Louis Bossart 			ret += intel_sprintf(s, false, buf, ret,
11579ee6631SPierre-Louis Bossart 					SDW_SHIM_PCMSYCHC(i, j));
11679ee6631SPierre-Louis Bossart 		}
117c27ce5c9SPierre-Louis Bossart 		ret += scnprintf(buf + ret, RD_BUF - ret, "\n IOCTL, CTMCTL\n");
11879ee6631SPierre-Louis Bossart 
11979ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_IOCTL(i));
12079ee6631SPierre-Louis Bossart 		ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTMCTL(i));
12179ee6631SPierre-Louis Bossart 	}
12279ee6631SPierre-Louis Bossart 
12379ee6631SPierre-Louis Bossart 	ret += scnprintf(buf + ret, RD_BUF - ret, "\nWake registers\n");
12479ee6631SPierre-Louis Bossart 	ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKEEN);
12579ee6631SPierre-Louis Bossart 	ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKESTS);
12679ee6631SPierre-Louis Bossart 
12779ee6631SPierre-Louis Bossart 	ret += scnprintf(buf + ret, RD_BUF - ret, "\nALH STRMzCFG\n");
12879ee6631SPierre-Louis Bossart 	for (i = 0; i < SDW_ALH_NUM_STREAMS; i++)
12979ee6631SPierre-Louis Bossart 		ret += intel_sprintf(a, true, buf, ret, SDW_ALH_STRMZCFG(i));
13079ee6631SPierre-Louis Bossart 
13179ee6631SPierre-Louis Bossart 	seq_printf(s_file, "%s", buf);
13279ee6631SPierre-Louis Bossart 	kfree(buf);
13379ee6631SPierre-Louis Bossart 
13479ee6631SPierre-Louis Bossart 	return 0;
13579ee6631SPierre-Louis Bossart }
13679ee6631SPierre-Louis Bossart DEFINE_SHOW_ATTRIBUTE(intel_reg);
13779ee6631SPierre-Louis Bossart 
intel_set_m_datamode(void * data,u64 value)1380f9138e7SPierre-Louis Bossart static int intel_set_m_datamode(void *data, u64 value)
1390f9138e7SPierre-Louis Bossart {
1400f9138e7SPierre-Louis Bossart 	struct sdw_intel *sdw = data;
1410f9138e7SPierre-Louis Bossart 	struct sdw_bus *bus = &sdw->cdns.bus;
1420f9138e7SPierre-Louis Bossart 
1430f9138e7SPierre-Louis Bossart 	if (value > SDW_PORT_DATA_MODE_STATIC_1)
1440f9138e7SPierre-Louis Bossart 		return -EINVAL;
1450f9138e7SPierre-Louis Bossart 
1460f9138e7SPierre-Louis Bossart 	/* Userspace changed the hardware state behind the kernel's back */
1470f9138e7SPierre-Louis Bossart 	add_taint(TAINT_USER, LOCKDEP_STILL_OK);
1480f9138e7SPierre-Louis Bossart 
1490f9138e7SPierre-Louis Bossart 	bus->params.m_data_mode = value;
1500f9138e7SPierre-Louis Bossart 
1510f9138e7SPierre-Louis Bossart 	return 0;
1520f9138e7SPierre-Louis Bossart }
1530f9138e7SPierre-Louis Bossart DEFINE_DEBUGFS_ATTRIBUTE(intel_set_m_datamode_fops, NULL,
1540f9138e7SPierre-Louis Bossart 			 intel_set_m_datamode, "%llu\n");
1550f9138e7SPierre-Louis Bossart 
intel_set_s_datamode(void * data,u64 value)1560f9138e7SPierre-Louis Bossart static int intel_set_s_datamode(void *data, u64 value)
1570f9138e7SPierre-Louis Bossart {
1580f9138e7SPierre-Louis Bossart 	struct sdw_intel *sdw = data;
1590f9138e7SPierre-Louis Bossart 	struct sdw_bus *bus = &sdw->cdns.bus;
1600f9138e7SPierre-Louis Bossart 
1610f9138e7SPierre-Louis Bossart 	if (value > SDW_PORT_DATA_MODE_STATIC_1)
1620f9138e7SPierre-Louis Bossart 		return -EINVAL;
1630f9138e7SPierre-Louis Bossart 
1640f9138e7SPierre-Louis Bossart 	/* Userspace changed the hardware state behind the kernel's back */
1650f9138e7SPierre-Louis Bossart 	add_taint(TAINT_USER, LOCKDEP_STILL_OK);
1660f9138e7SPierre-Louis Bossart 
1670f9138e7SPierre-Louis Bossart 	bus->params.s_data_mode = value;
1680f9138e7SPierre-Louis Bossart 
1690f9138e7SPierre-Louis Bossart 	return 0;
1700f9138e7SPierre-Louis Bossart }
1710f9138e7SPierre-Louis Bossart DEFINE_DEBUGFS_ATTRIBUTE(intel_set_s_datamode_fops, NULL,
1720f9138e7SPierre-Louis Bossart 			 intel_set_s_datamode, "%llu\n");
1730f9138e7SPierre-Louis Bossart 
intel_debugfs_init(struct sdw_intel * sdw)17479ee6631SPierre-Louis Bossart static void intel_debugfs_init(struct sdw_intel *sdw)
17579ee6631SPierre-Louis Bossart {
17679ee6631SPierre-Louis Bossart 	struct dentry *root = sdw->cdns.bus.debugfs;
17779ee6631SPierre-Louis Bossart 
17879ee6631SPierre-Louis Bossart 	if (!root)
17979ee6631SPierre-Louis Bossart 		return;
18079ee6631SPierre-Louis Bossart 
18179ee6631SPierre-Louis Bossart 	sdw->debugfs = debugfs_create_dir("intel-sdw", root);
18279ee6631SPierre-Louis Bossart 
18379ee6631SPierre-Louis Bossart 	debugfs_create_file("intel-registers", 0400, sdw->debugfs, sdw,
18479ee6631SPierre-Louis Bossart 			    &intel_reg_fops);
18579ee6631SPierre-Louis Bossart 
1860f9138e7SPierre-Louis Bossart 	debugfs_create_file("intel-m-datamode", 0200, sdw->debugfs, sdw,
1870f9138e7SPierre-Louis Bossart 			    &intel_set_m_datamode_fops);
1880f9138e7SPierre-Louis Bossart 
1890f9138e7SPierre-Louis Bossart 	debugfs_create_file("intel-s-datamode", 0200, sdw->debugfs, sdw,
1900f9138e7SPierre-Louis Bossart 			    &intel_set_s_datamode_fops);
1910f9138e7SPierre-Louis Bossart 
19279ee6631SPierre-Louis Bossart 	sdw_cdns_debugfs_init(&sdw->cdns, sdw->debugfs);
19379ee6631SPierre-Louis Bossart }
19479ee6631SPierre-Louis Bossart 
intel_debugfs_exit(struct sdw_intel * sdw)19579ee6631SPierre-Louis Bossart static void intel_debugfs_exit(struct sdw_intel *sdw)
19679ee6631SPierre-Louis Bossart {
19779ee6631SPierre-Louis Bossart 	debugfs_remove_recursive(sdw->debugfs);
19879ee6631SPierre-Louis Bossart }
19979ee6631SPierre-Louis Bossart #else
intel_debugfs_init(struct sdw_intel * sdw)20079ee6631SPierre-Louis Bossart static void intel_debugfs_init(struct sdw_intel *sdw) {}
intel_debugfs_exit(struct sdw_intel * sdw)20179ee6631SPierre-Louis Bossart static void intel_debugfs_exit(struct sdw_intel *sdw) {}
20279ee6631SPierre-Louis Bossart #endif /* CONFIG_DEBUG_FS */
20379ee6631SPierre-Louis Bossart 
20479ee6631SPierre-Louis Bossart /*
20571bb8a1bSVinod Koul  * shim ops
20671bb8a1bSVinod Koul  */
2074a17c441SPierre-Louis Bossart /* this needs to be called with shim_lock */
intel_shim_glue_to_master_ip(struct sdw_intel * sdw)2084a17c441SPierre-Louis Bossart static void intel_shim_glue_to_master_ip(struct sdw_intel *sdw)
20971bb8a1bSVinod Koul {
2102523486bSPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
21171bb8a1bSVinod Koul 	unsigned int link_id = sdw->instance;
2124a17c441SPierre-Louis Bossart 	u16 ioctl;
21371bb8a1bSVinod Koul 
21471bb8a1bSVinod Koul 	/* Switch to MIP from Glue logic */
21571bb8a1bSVinod Koul 	ioctl = intel_readw(shim,  SDW_SHIM_IOCTL(link_id));
21671bb8a1bSVinod Koul 
21771bb8a1bSVinod Koul 	ioctl &= ~(SDW_SHIM_IOCTL_DOE);
21871bb8a1bSVinod Koul 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
2194a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
22071bb8a1bSVinod Koul 
22171bb8a1bSVinod Koul 	ioctl &= ~(SDW_SHIM_IOCTL_DO);
22271bb8a1bSVinod Koul 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
2234a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
22471bb8a1bSVinod Koul 
22571bb8a1bSVinod Koul 	ioctl |= (SDW_SHIM_IOCTL_MIF);
22671bb8a1bSVinod Koul 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
2274a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
22871bb8a1bSVinod Koul 
22971bb8a1bSVinod Koul 	ioctl &= ~(SDW_SHIM_IOCTL_BKE);
23071bb8a1bSVinod Koul 	ioctl &= ~(SDW_SHIM_IOCTL_COE);
23171bb8a1bSVinod Koul 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
2324a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
2334a17c441SPierre-Louis Bossart 
2344a17c441SPierre-Louis Bossart 	/* at this point Master IP has full control of the I/Os */
2354a17c441SPierre-Louis Bossart }
2364a17c441SPierre-Louis Bossart 
2374a17c441SPierre-Louis Bossart /* this needs to be called with shim_lock */
intel_shim_master_ip_to_glue(struct sdw_intel * sdw)2384a17c441SPierre-Louis Bossart static void intel_shim_master_ip_to_glue(struct sdw_intel *sdw)
2394a17c441SPierre-Louis Bossart {
2404a17c441SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
2414a17c441SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
2424a17c441SPierre-Louis Bossart 	u16 ioctl;
2434a17c441SPierre-Louis Bossart 
2444a17c441SPierre-Louis Bossart 	/* Glue logic */
2454a17c441SPierre-Louis Bossart 	ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id));
2464a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_BKE;
2474a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_COE;
2484a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
2494a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
2504a17c441SPierre-Louis Bossart 
2514a17c441SPierre-Louis Bossart 	ioctl &= ~(SDW_SHIM_IOCTL_MIF);
2524a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
2534a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
2544a17c441SPierre-Louis Bossart 
2554a17c441SPierre-Louis Bossart 	/* at this point Integration Glue has full control of the I/Os */
2564a17c441SPierre-Louis Bossart }
2574a17c441SPierre-Louis Bossart 
258b81bcdb4SPierre-Louis Bossart /* this needs to be called with shim_lock */
intel_shim_init(struct sdw_intel * sdw)259b81bcdb4SPierre-Louis Bossart static void intel_shim_init(struct sdw_intel *sdw)
2604a17c441SPierre-Louis Bossart {
2614a17c441SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
2624a17c441SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
2634a17c441SPierre-Louis Bossart 	u16 ioctl = 0, act;
2644a17c441SPierre-Louis Bossart 
2654a17c441SPierre-Louis Bossart 	/* Initialize Shim */
2664a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_BKE;
2674a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
2684a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
2694a17c441SPierre-Louis Bossart 
2704a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_WPDD;
2714a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
2724a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
2734a17c441SPierre-Louis Bossart 
2744a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_DO;
2754a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
2764a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
2774a17c441SPierre-Louis Bossart 
2784a17c441SPierre-Louis Bossart 	ioctl |= SDW_SHIM_IOCTL_DOE;
2794a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
2804a17c441SPierre-Louis Bossart 	usleep_range(10, 15);
2814a17c441SPierre-Louis Bossart 
2824a17c441SPierre-Louis Bossart 	intel_shim_glue_to_master_ip(sdw);
28371bb8a1bSVinod Koul 
284f067c925SVinod Koul 	act = intel_readw(shim, SDW_SHIM_CTMCTL(link_id));
28571bb8a1bSVinod Koul 	u16p_replace_bits(&act, 0x1, SDW_SHIM_CTMCTL_DOAIS);
28671bb8a1bSVinod Koul 	act |= SDW_SHIM_CTMCTL_DACTQE;
28771bb8a1bSVinod Koul 	act |= SDW_SHIM_CTMCTL_DODS;
2884a17c441SPierre-Louis Bossart 	intel_writew(shim, SDW_SHIM_CTMCTL(link_id), act);
28971bb8a1bSVinod Koul 	usleep_range(10, 15);
29071bb8a1bSVinod Koul }
2910f3c54c2SPierre-Louis Bossart 
intel_shim_check_wake(struct sdw_intel * sdw)2920f3c54c2SPierre-Louis Bossart static int intel_shim_check_wake(struct sdw_intel *sdw)
2930f3c54c2SPierre-Louis Bossart {
2940f3c54c2SPierre-Louis Bossart 	void __iomem *shim;
29571bb8a1bSVinod Koul 	u16 wake_sts;
2960f3c54c2SPierre-Louis Bossart 
2970f3c54c2SPierre-Louis Bossart 	shim = sdw->link_res->shim;
2980f3c54c2SPierre-Louis Bossart 	wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);
2990f3c54c2SPierre-Louis Bossart 
30071bb8a1bSVinod Koul 	return wake_sts & BIT(sdw->instance);
30171bb8a1bSVinod Koul }
302ab2c9132SRander Wang 
intel_shim_wake(struct sdw_intel * sdw,bool wake_enable)3034a17c441SPierre-Louis Bossart static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
3044a17c441SPierre-Louis Bossart {
3054a17c441SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
3064a17c441SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
3074a17c441SPierre-Louis Bossart 	u16 wake_en, wake_sts;
3084a17c441SPierre-Louis Bossart 
3094a17c441SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
3104a17c441SPierre-Louis Bossart 	wake_en = intel_readw(shim, SDW_SHIM_WAKEEN);
3114a17c441SPierre-Louis Bossart 
3124a17c441SPierre-Louis Bossart 	if (wake_enable) {
3134a17c441SPierre-Louis Bossart 		/* Enable the wakeup */
3144a17c441SPierre-Louis Bossart 		wake_en |= (SDW_SHIM_WAKEEN_ENABLE << link_id);
3154a17c441SPierre-Louis Bossart 		intel_writew(shim, SDW_SHIM_WAKEEN, wake_en);
3164a17c441SPierre-Louis Bossart 	} else {
3174a17c441SPierre-Louis Bossart 		/* Disable the wake up interrupt */
3184a17c441SPierre-Louis Bossart 		wake_en &= ~(SDW_SHIM_WAKEEN_ENABLE << link_id);
3194a17c441SPierre-Louis Bossart 		intel_writew(shim, SDW_SHIM_WAKEEN, wake_en);
3204a17c441SPierre-Louis Bossart 
3214a17c441SPierre-Louis Bossart 		/* Clear wake status */
3223957db3aSLibin Yang 		wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);
3233957db3aSLibin Yang 		wake_sts |= (SDW_SHIM_WAKESTS_STATUS << link_id);
3244a17c441SPierre-Louis Bossart 		intel_writew(shim, SDW_SHIM_WAKESTS, wake_sts);
3254a17c441SPierre-Louis Bossart 	}
3264a17c441SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
3274a17c441SPierre-Louis Bossart }
3281e76de2eSPierre-Louis Bossart 
intel_check_cmdsync_unlocked(struct sdw_intel * sdw)3291e76de2eSPierre-Louis Bossart static bool intel_check_cmdsync_unlocked(struct sdw_intel *sdw)
3301e76de2eSPierre-Louis Bossart {
3311e76de2eSPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
3321e76de2eSPierre-Louis Bossart 	int sync_reg;
3331e76de2eSPierre-Louis Bossart 
3341e76de2eSPierre-Louis Bossart 	sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
3351e76de2eSPierre-Louis Bossart 	return !!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK);
3361e76de2eSPierre-Louis Bossart }
337bc872947SPierre-Louis Bossart 
intel_link_power_up(struct sdw_intel * sdw)338bc872947SPierre-Louis Bossart static int intel_link_power_up(struct sdw_intel *sdw)
339bc872947SPierre-Louis Bossart {
340bc872947SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
341bc872947SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
342bc872947SPierre-Louis Bossart 	u32 *shim_mask = sdw->link_res->shim_mask;
343bc872947SPierre-Louis Bossart 	struct sdw_bus *bus = &sdw->cdns.bus;
344bc872947SPierre-Louis Bossart 	struct sdw_master_prop *prop = &bus->prop;
345bc872947SPierre-Louis Bossart 	u32 spa_mask, cpa_mask;
346bc872947SPierre-Louis Bossart 	u32 link_control;
347bc872947SPierre-Louis Bossart 	int ret = 0;
348bc872947SPierre-Louis Bossart 	u32 syncprd;
349bc872947SPierre-Louis Bossart 	u32 sync_reg;
350bc872947SPierre-Louis Bossart 
351bc872947SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
352bc872947SPierre-Louis Bossart 
353bc872947SPierre-Louis Bossart 	/*
354bc872947SPierre-Louis Bossart 	 * The hardware relies on an internal counter, typically 4kHz,
355bc872947SPierre-Louis Bossart 	 * to generate the SoundWire SSP - which defines a 'safe'
356bc872947SPierre-Louis Bossart 	 * synchronization point between commands and audio transport
357bc872947SPierre-Louis Bossart 	 * and allows for multi link synchronization. The SYNCPRD value
358bc872947SPierre-Louis Bossart 	 * is only dependent on the oscillator clock provided to
359bc872947SPierre-Louis Bossart 	 * the IP, so adjust based on _DSD properties reported in DSDT
360bc872947SPierre-Louis Bossart 	 * tables. The values reported are based on either 24MHz
361bc872947SPierre-Louis Bossart 	 * (CNL/CML) or 38.4 MHz (ICL/TGL+).
362bc872947SPierre-Louis Bossart 	 */
363bc872947SPierre-Louis Bossart 	if (prop->mclk_freq % 6000000)
364bc872947SPierre-Louis Bossart 		syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
365bc872947SPierre-Louis Bossart 	else
366bc872947SPierre-Louis Bossart 		syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;
367bc872947SPierre-Louis Bossart 
368bc872947SPierre-Louis Bossart 	if (!*shim_mask) {
369bc872947SPierre-Louis Bossart 		dev_dbg(sdw->cdns.dev, "powering up all links\n");
370bc872947SPierre-Louis Bossart 
371bc872947SPierre-Louis Bossart 		/* we first need to program the SyncPRD/CPU registers */
372bc872947SPierre-Louis Bossart 		dev_dbg(sdw->cdns.dev,
373bc872947SPierre-Louis Bossart 			"first link up, programming SYNCPRD\n");
374bc872947SPierre-Louis Bossart 
375bc872947SPierre-Louis Bossart 		/* set SyncPRD period */
376bc872947SPierre-Louis Bossart 		sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
377bc872947SPierre-Louis Bossart 		u32p_replace_bits(&sync_reg, syncprd, SDW_SHIM_SYNC_SYNCPRD);
378bc872947SPierre-Louis Bossart 
379bc872947SPierre-Louis Bossart 		/* Set SyncCPU bit */
380bc872947SPierre-Louis Bossart 		sync_reg |= SDW_SHIM_SYNC_SYNCCPU;
381bc872947SPierre-Louis Bossart 		intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
382bc872947SPierre-Louis Bossart 
383bc872947SPierre-Louis Bossart 		/* Link power up sequence */
384bc872947SPierre-Louis Bossart 		link_control = intel_readl(shim, SDW_SHIM_LCTL);
385bc872947SPierre-Louis Bossart 
386bc872947SPierre-Louis Bossart 		/* only power-up enabled links */
387bc872947SPierre-Louis Bossart 		spa_mask = FIELD_PREP(SDW_SHIM_LCTL_SPA_MASK, sdw->link_res->link_mask);
388bc872947SPierre-Louis Bossart 		cpa_mask = FIELD_PREP(SDW_SHIM_LCTL_CPA_MASK, sdw->link_res->link_mask);
389bc872947SPierre-Louis Bossart 
390bc872947SPierre-Louis Bossart 		link_control |=  spa_mask;
391bc872947SPierre-Louis Bossart 
392bc872947SPierre-Louis Bossart 		ret = intel_set_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);
393bc872947SPierre-Louis Bossart 		if (ret < 0) {
394bc872947SPierre-Louis Bossart 			dev_err(sdw->cdns.dev, "Failed to power up link: %d\n", ret);
395bc872947SPierre-Louis Bossart 			goto out;
396bc872947SPierre-Louis Bossart 		}
397bc872947SPierre-Louis Bossart 
398bc872947SPierre-Louis Bossart 		/* SyncCPU will change once link is active */
399bc872947SPierre-Louis Bossart 		ret = intel_wait_bit(shim, SDW_SHIM_SYNC,
400bc872947SPierre-Louis Bossart 				     SDW_SHIM_SYNC_SYNCCPU, 0);
401bc872947SPierre-Louis Bossart 		if (ret < 0) {
402bc872947SPierre-Louis Bossart 			dev_err(sdw->cdns.dev,
403bc872947SPierre-Louis Bossart 				"Failed to set SHIM_SYNC: %d\n", ret);
404bc872947SPierre-Louis Bossart 			goto out;
405bc872947SPierre-Louis Bossart 		}
406bc872947SPierre-Louis Bossart 	}
407bc872947SPierre-Louis Bossart 
408bc872947SPierre-Louis Bossart 	*shim_mask |= BIT(link_id);
409bc872947SPierre-Louis Bossart 
410b81bcdb4SPierre-Louis Bossart 	sdw->cdns.link_up = true;
411b81bcdb4SPierre-Louis Bossart 
412b81bcdb4SPierre-Louis Bossart 	intel_shim_init(sdw);
413bc872947SPierre-Louis Bossart 
414bc872947SPierre-Louis Bossart out:
415bc872947SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
416bc872947SPierre-Louis Bossart 
417bc872947SPierre-Louis Bossart 	return ret;
418bc872947SPierre-Louis Bossart }
4199b3b4b3fSPierre-Louis Bossart 
intel_link_power_down(struct sdw_intel * sdw)4204a17c441SPierre-Louis Bossart static int intel_link_power_down(struct sdw_intel *sdw)
4215ee74eb2SPierre-Louis Bossart {
4224a17c441SPierre-Louis Bossart 	u32 link_control, spa_mask, cpa_mask;
4234a17c441SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
4244a17c441SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
4254a17c441SPierre-Louis Bossart 	u32 *shim_mask = sdw->link_res->shim_mask;
4264a17c441SPierre-Louis Bossart 	int ret = 0;
4274a17c441SPierre-Louis Bossart 
4284a17c441SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
4294a17c441SPierre-Louis Bossart 
4304a17c441SPierre-Louis Bossart 	if (!(*shim_mask & BIT(link_id)))
4314a17c441SPierre-Louis Bossart 		dev_err(sdw->cdns.dev,
4324a17c441SPierre-Louis Bossart 			"%s: Unbalanced power-up/down calls\n", __func__);
433ea6942daSPierre-Louis Bossart 
434ea6942daSPierre-Louis Bossart 	sdw->cdns.link_up = false;
435ea6942daSPierre-Louis Bossart 
436ea6942daSPierre-Louis Bossart 	intel_shim_master_ip_to_glue(sdw);
4374a17c441SPierre-Louis Bossart 
4384a17c441SPierre-Louis Bossart 	*shim_mask &= ~BIT(link_id);
4395ee74eb2SPierre-Louis Bossart 
4405ee74eb2SPierre-Louis Bossart 	if (!*shim_mask) {
44163198aaaSPierre-Louis Bossart 
4425ee74eb2SPierre-Louis Bossart 		dev_dbg(sdw->cdns.dev, "powering down all links\n");
4435ee74eb2SPierre-Louis Bossart 
4445ee74eb2SPierre-Louis Bossart 		/* Link power down sequence */
4455ee74eb2SPierre-Louis Bossart 		link_control = intel_readl(shim, SDW_SHIM_LCTL);
4465ee74eb2SPierre-Louis Bossart 
4473b4979caSVinod Koul 		/* only power-down enabled links */
4483b4979caSVinod Koul 		spa_mask = FIELD_PREP(SDW_SHIM_LCTL_SPA_MASK, ~sdw->link_res->link_mask);
4495ee74eb2SPierre-Louis Bossart 		cpa_mask = FIELD_PREP(SDW_SHIM_LCTL_CPA_MASK, sdw->link_res->link_mask);
4505ee74eb2SPierre-Louis Bossart 
4515ee74eb2SPierre-Louis Bossart 		link_control &=  spa_mask;
4525ee74eb2SPierre-Louis Bossart 
453ea6942daSPierre-Louis Bossart 		ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);
454ea6942daSPierre-Louis Bossart 		if (ret < 0) {
455ea6942daSPierre-Louis Bossart 			dev_err(sdw->cdns.dev, "%s: could not power down link\n", __func__);
456ea6942daSPierre-Louis Bossart 
457ea6942daSPierre-Louis Bossart 			/*
458ea6942daSPierre-Louis Bossart 			 * we leave the sdw->cdns.link_up flag as false since we've disabled
459ea6942daSPierre-Louis Bossart 			 * the link at this point and cannot handle interrupts any longer.
460ea6942daSPierre-Louis Bossart 			 */
4615ee74eb2SPierre-Louis Bossart 		}
4625ee74eb2SPierre-Louis Bossart 	}
4634a17c441SPierre-Louis Bossart 
4644a17c441SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
4654a17c441SPierre-Louis Bossart 
4665ee74eb2SPierre-Louis Bossart 	return ret;
4674a17c441SPierre-Louis Bossart }
46802629e45SPierre-Louis Bossart 
intel_shim_sync_arm(struct sdw_intel * sdw)46902629e45SPierre-Louis Bossart static void intel_shim_sync_arm(struct sdw_intel *sdw)
47002629e45SPierre-Louis Bossart {
47102629e45SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
47202629e45SPierre-Louis Bossart 	u32 sync_reg;
47302629e45SPierre-Louis Bossart 
47402629e45SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
47502629e45SPierre-Louis Bossart 
47602629e45SPierre-Louis Bossart 	/* update SYNC register */
47702629e45SPierre-Louis Bossart 	sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
47802629e45SPierre-Louis Bossart 	sync_reg |= (SDW_SHIM_SYNC_CMDSYNC << sdw->instance);
47902629e45SPierre-Louis Bossart 	intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
48002629e45SPierre-Louis Bossart 
48102629e45SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
48202629e45SPierre-Louis Bossart }
483437e3289SPierre-Louis Bossart 
intel_shim_sync_go_unlocked(struct sdw_intel * sdw)484437e3289SPierre-Louis Bossart static int intel_shim_sync_go_unlocked(struct sdw_intel *sdw)
485437e3289SPierre-Louis Bossart {
486437e3289SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
487437e3289SPierre-Louis Bossart 	u32 sync_reg;
488437e3289SPierre-Louis Bossart 
489437e3289SPierre-Louis Bossart 	/* Read SYNC register */
490437e3289SPierre-Louis Bossart 	sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
491437e3289SPierre-Louis Bossart 
492437e3289SPierre-Louis Bossart 	/*
493437e3289SPierre-Louis Bossart 	 * Set SyncGO bit to synchronously trigger a bank switch for
494437e3289SPierre-Louis Bossart 	 * all the masters. A write to SYNCGO bit clears CMDSYNC bit for all
495437e3289SPierre-Louis Bossart 	 * the Masters.
496437e3289SPierre-Louis Bossart 	 */
497437e3289SPierre-Louis Bossart 	sync_reg |= SDW_SHIM_SYNC_SYNCGO;
4989c49a4ddSPierre-Louis Bossart 
499437e3289SPierre-Louis Bossart 	intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
5009c49a4ddSPierre-Louis Bossart 
50171bb8a1bSVinod Koul 	return 0;
50271bb8a1bSVinod Koul }
503857a7c42SPierre-Louis Bossart 
intel_shim_sync_go(struct sdw_intel * sdw)504857a7c42SPierre-Louis Bossart static int intel_shim_sync_go(struct sdw_intel *sdw)
505857a7c42SPierre-Louis Bossart {
506857a7c42SPierre-Louis Bossart 	int ret;
507857a7c42SPierre-Louis Bossart 
508857a7c42SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
509857a7c42SPierre-Louis Bossart 
510857a7c42SPierre-Louis Bossart 	ret = intel_shim_sync_go_unlocked(sdw);
511857a7c42SPierre-Louis Bossart 
512857a7c42SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
513857a7c42SPierre-Louis Bossart 
514857a7c42SPierre-Louis Bossart 	return ret;
515857a7c42SPierre-Louis Bossart }
51637a2d22bSVinod Koul 
51737a2d22bSVinod Koul /*
51837a2d22bSVinod Koul  * PDI routines
51937a2d22bSVinod Koul  */
intel_pdi_init(struct sdw_intel * sdw,struct sdw_cdns_stream_config * config)52037a2d22bSVinod Koul static void intel_pdi_init(struct sdw_intel *sdw,
52137a2d22bSVinod Koul 			   struct sdw_cdns_stream_config *config)
5222523486bSPierre-Louis Bossart {
52337a2d22bSVinod Koul 	void __iomem *shim = sdw->link_res->shim;
52463a6aa96SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
52537a2d22bSVinod Koul 	int pcm_cap;
52637a2d22bSVinod Koul 
52737a2d22bSVinod Koul 	/* PCM Stream Capability */
52837a2d22bSVinod Koul 	pcm_cap = intel_readw(shim, SDW_SHIM_PCMSCAP(link_id));
5293b4979caSVinod Koul 
5303b4979caSVinod Koul 	config->pcm_bd = FIELD_GET(SDW_SHIM_PCMSCAP_BSS, pcm_cap);
5313b4979caSVinod Koul 	config->pcm_in = FIELD_GET(SDW_SHIM_PCMSCAP_ISS, pcm_cap);
53237a2d22bSVinod Koul 	config->pcm_out = FIELD_GET(SDW_SHIM_PCMSCAP_OSS, pcm_cap);
533121f4361SPierre-Louis Bossart 
534121f4361SPierre-Louis Bossart 	dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n",
53537a2d22bSVinod Koul 		config->pcm_bd, config->pcm_in, config->pcm_out);
53637a2d22bSVinod Koul }
53737a2d22bSVinod Koul 
53863a6aa96SPierre-Louis Bossart static int
intel_pdi_get_ch_cap(struct sdw_intel * sdw,unsigned int pdi_num)53937a2d22bSVinod Koul intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num)
5402523486bSPierre-Louis Bossart {
54137a2d22bSVinod Koul 	void __iomem *shim = sdw->link_res->shim;
54237a2d22bSVinod Koul 	unsigned int link_id = sdw->instance;
54337a2d22bSVinod Koul 	int count;
54437a2d22bSVinod Koul 
54518046335SPierre-Louis Bossart 	count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num));
54618046335SPierre-Louis Bossart 
54718046335SPierre-Louis Bossart 	/*
54818046335SPierre-Louis Bossart 	 * WORKAROUND: on all existing Intel controllers, pdi
54918046335SPierre-Louis Bossart 	 * number 2 reports channel count as 1 even though it
55018046335SPierre-Louis Bossart 	 * supports 8 channels. Performing hardcoding for pdi
55118046335SPierre-Louis Bossart 	 * number 2.
55218046335SPierre-Louis Bossart 	 */
55318046335SPierre-Louis Bossart 	if (pdi_num == 2)
55418046335SPierre-Louis Bossart 		count = 7;
55537a2d22bSVinod Koul 
55637a2d22bSVinod Koul 	/* zero based values for channel count in register */
55737a2d22bSVinod Koul 	count++;
55837a2d22bSVinod Koul 
55937a2d22bSVinod Koul 	return count;
56037a2d22bSVinod Koul }
56137a2d22bSVinod Koul 
intel_pdi_get_ch_update(struct sdw_intel * sdw,struct sdw_cdns_pdi * pdi,unsigned int num_pdi,unsigned int * num_ch)56237a2d22bSVinod Koul static int intel_pdi_get_ch_update(struct sdw_intel *sdw,
56337a2d22bSVinod Koul 				   struct sdw_cdns_pdi *pdi,
56463a6aa96SPierre-Louis Bossart 				   unsigned int num_pdi,
56537a2d22bSVinod Koul 				   unsigned int *num_ch)
56637a2d22bSVinod Koul {
56737a2d22bSVinod Koul 	int i, ch_count = 0;
56837a2d22bSVinod Koul 
56963a6aa96SPierre-Louis Bossart 	for (i = 0; i < num_pdi; i++) {
57037a2d22bSVinod Koul 		pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num);
57137a2d22bSVinod Koul 		ch_count += pdi->ch_count;
57237a2d22bSVinod Koul 		pdi++;
57337a2d22bSVinod Koul 	}
57437a2d22bSVinod Koul 
57537a2d22bSVinod Koul 	*num_ch = ch_count;
57637a2d22bSVinod Koul 	return 0;
57737a2d22bSVinod Koul }
57837a2d22bSVinod Koul 
intel_pdi_stream_ch_update(struct sdw_intel * sdw,struct sdw_cdns_streams * stream)57963a6aa96SPierre-Louis Bossart static int intel_pdi_stream_ch_update(struct sdw_intel *sdw,
58037a2d22bSVinod Koul 				      struct sdw_cdns_streams *stream)
58137a2d22bSVinod Koul {
58263a6aa96SPierre-Louis Bossart 	intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd,
58337a2d22bSVinod Koul 				&stream->num_ch_bd);
58437a2d22bSVinod Koul 
58563a6aa96SPierre-Louis Bossart 	intel_pdi_get_ch_update(sdw, stream->in, stream->num_in,
58637a2d22bSVinod Koul 				&stream->num_ch_in);
58737a2d22bSVinod Koul 
58863a6aa96SPierre-Louis Bossart 	intel_pdi_get_ch_update(sdw, stream->out, stream->num_out,
58937a2d22bSVinod Koul 				&stream->num_ch_out);
59037a2d22bSVinod Koul 
59137a2d22bSVinod Koul 	return 0;
59237a2d22bSVinod Koul }
59337a2d22bSVinod Koul 
59437a2d22bSVinod Koul static void
intel_pdi_shim_configure(struct sdw_intel * sdw,struct sdw_cdns_pdi * pdi)59537a2d22bSVinod Koul intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
5962523486bSPierre-Louis Bossart {
59737a2d22bSVinod Koul 	void __iomem *shim = sdw->link_res->shim;
59837a2d22bSVinod Koul 	unsigned int link_id = sdw->instance;
59937a2d22bSVinod Koul 	int pdi_conf = 0;
600c134f914SPierre-Louis Bossart 
601c134f914SPierre-Louis Bossart 	/* the Bulk and PCM streams are not contiguous */
602c134f914SPierre-Louis Bossart 	pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
603c134f914SPierre-Louis Bossart 	if (pdi->num >= 2)
60437a2d22bSVinod Koul 		pdi->intel_alh_id += 2;
60537a2d22bSVinod Koul 
60637a2d22bSVinod Koul 	/*
60737a2d22bSVinod Koul 	 * Program stream parameters to stream SHIM register
60837a2d22bSVinod Koul 	 * This is applicable for PCM stream only.
60937a2d22bSVinod Koul 	 */
61037a2d22bSVinod Koul 	if (pdi->type != SDW_STREAM_PCM)
61137a2d22bSVinod Koul 		return;
61237a2d22bSVinod Koul 
61337a2d22bSVinod Koul 	if (pdi->dir == SDW_DATA_DIR_RX)
61437a2d22bSVinod Koul 		pdi_conf |= SDW_SHIM_PCMSYCM_DIR;
61537a2d22bSVinod Koul 	else
61637a2d22bSVinod Koul 		pdi_conf &= ~(SDW_SHIM_PCMSYCM_DIR);
617f067c925SVinod Koul 
618f067c925SVinod Koul 	u32p_replace_bits(&pdi_conf, pdi->intel_alh_id, SDW_SHIM_PCMSYCM_STREAM);
619f067c925SVinod Koul 	u32p_replace_bits(&pdi_conf, pdi->l_ch_num, SDW_SHIM_PCMSYCM_LCHN);
62037a2d22bSVinod Koul 	u32p_replace_bits(&pdi_conf, pdi->h_ch_num, SDW_SHIM_PCMSYCM_HCHN);
62137a2d22bSVinod Koul 
62237a2d22bSVinod Koul 	intel_writew(shim, SDW_SHIM_PCMSYCHM(link_id, pdi->num), pdi_conf);
62337a2d22bSVinod Koul }
62437a2d22bSVinod Koul 
62537a2d22bSVinod Koul static void
intel_pdi_alh_configure(struct sdw_intel * sdw,struct sdw_cdns_pdi * pdi)62637a2d22bSVinod Koul intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
6272523486bSPierre-Louis Bossart {
62837a2d22bSVinod Koul 	void __iomem *alh = sdw->link_res->alh;
62937a2d22bSVinod Koul 	unsigned int link_id = sdw->instance;
63037a2d22bSVinod Koul 	unsigned int conf;
631c134f914SPierre-Louis Bossart 
632c134f914SPierre-Louis Bossart 	/* the Bulk and PCM streams are not contiguous */
633c134f914SPierre-Louis Bossart 	pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
634c134f914SPierre-Louis Bossart 	if (pdi->num >= 2)
63537a2d22bSVinod Koul 		pdi->intel_alh_id += 2;
63637a2d22bSVinod Koul 
63737a2d22bSVinod Koul 	/* Program Stream config ALH register */
63837a2d22bSVinod Koul 	conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id));
639f067c925SVinod Koul 
640f067c925SVinod Koul 	u32p_replace_bits(&conf, SDW_ALH_STRMZCFG_DMAT_VAL, SDW_ALH_STRMZCFG_DMAT);
64137a2d22bSVinod Koul 	u32p_replace_bits(&conf, pdi->ch_count - 1, SDW_ALH_STRMZCFG_CHN);
64237a2d22bSVinod Koul 
64337a2d22bSVinod Koul 	intel_writel(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id), conf);
64437a2d22bSVinod Koul }
6454b206d34SRander Wang 
intel_params_stream(struct sdw_intel * sdw,struct snd_pcm_substream * substream,struct snd_soc_dai * dai,struct snd_pcm_hw_params * hw_params,int link_id,int alh_stream_id)646b86947b5SPierre-Louis Bossart static int intel_params_stream(struct sdw_intel *sdw,
647c46302ecSVinod Koul 			       struct snd_pcm_substream *substream,
6484b206d34SRander Wang 			       struct snd_soc_dai *dai,
6494b206d34SRander Wang 			       struct snd_pcm_hw_params *hw_params,
650c46302ecSVinod Koul 			       int link_id, int alh_stream_id)
6512523486bSPierre-Louis Bossart {
6524b206d34SRander Wang 	struct sdw_intel_link_res *res = sdw->link_res;
65305c8afe4SPierre-Louis Bossart 	struct sdw_intel_stream_params_data params_data;
654b86947b5SPierre-Louis Bossart 
6554b206d34SRander Wang 	params_data.substream = substream;
6564b206d34SRander Wang 	params_data.dai = dai;
6574b206d34SRander Wang 	params_data.hw_params = hw_params;
6584b206d34SRander Wang 	params_data.link_id = link_id;
659c46302ecSVinod Koul 	params_data.alh_stream_id = alh_stream_id;
6604b206d34SRander Wang 
6614b206d34SRander Wang 	if (res->ops && res->ops->params_stream && res->dev)
6624b206d34SRander Wang 		return res->ops->params_stream(res->dev,
663c46302ecSVinod Koul 					       &params_data);
664c46302ecSVinod Koul 	return -EIO;
665c46302ecSVinod Koul }
666eff346f2SPierre-Louis Bossart 
667b86947b5SPierre-Louis Bossart /*
668eff346f2SPierre-Louis Bossart  * DAI routines
669eff346f2SPierre-Louis Bossart  */
670eff346f2SPierre-Louis Bossart 
intel_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)671eff346f2SPierre-Louis Bossart static int intel_hw_params(struct snd_pcm_substream *substream,
672eff346f2SPierre-Louis Bossart 			   struct snd_pcm_hw_params *params,
673eff346f2SPierre-Louis Bossart 			   struct snd_soc_dai *dai)
674b86947b5SPierre-Louis Bossart {
675eff346f2SPierre-Louis Bossart 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
676eff346f2SPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
677eff346f2SPierre-Louis Bossart 	struct sdw_cdns_dai_runtime *dai_runtime;
678eff346f2SPierre-Louis Bossart 	struct sdw_cdns_pdi *pdi;
679eff346f2SPierre-Louis Bossart 	struct sdw_stream_config sconfig;
680eff346f2SPierre-Louis Bossart 	struct sdw_port_config *pconfig;
681eff346f2SPierre-Louis Bossart 	int ch, dir;
682eff346f2SPierre-Louis Bossart 	int ret;
683eff346f2SPierre-Louis Bossart 
684eff346f2SPierre-Louis Bossart 	dai_runtime = cdns->dai_runtime_array[dai->id];
685c46302ecSVinod Koul 	if (!dai_runtime)
686c46302ecSVinod Koul 		return -EIO;
687c46302ecSVinod Koul 
688c46302ecSVinod Koul 	ch = params_channels(params);
689c46302ecSVinod Koul 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
690c46302ecSVinod Koul 		dir = SDW_DATA_DIR_RX;
691c46302ecSVinod Koul 	else
692c46302ecSVinod Koul 		dir = SDW_DATA_DIR_TX;
693c46302ecSVinod Koul 
694c46302ecSVinod Koul 	pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
695e0767e39SPierre-Louis Bossart 
69657a34790SPierre-Louis Bossart 	if (!pdi) {
697c46302ecSVinod Koul 		ret = -EINVAL;
698c46302ecSVinod Koul 		goto error;
69957a34790SPierre-Louis Bossart 	}
70057a34790SPierre-Louis Bossart 
701c46302ecSVinod Koul 	/* do run-time configurations for SHIM, ALH and PDI/PORT */
7027dddead7SPierre-Louis Bossart 	intel_pdi_shim_configure(sdw, pdi);
703e0767e39SPierre-Louis Bossart 	intel_pdi_alh_configure(sdw, pdi);
704c46302ecSVinod Koul 	sdw_cdns_config_stream(cdns, ch, dir, pdi);
705c46302ecSVinod Koul 
706c46302ecSVinod Koul 	/* store pdi and hw_params, may be needed in prepare step */
707c46302ecSVinod Koul 	dai_runtime->paused = false;
708c46302ecSVinod Koul 	dai_runtime->suspended = false;
709c46302ecSVinod Koul 	dai_runtime->pdi = pdi;
710c46302ecSVinod Koul 
711c46302ecSVinod Koul 	/* Inform DSP about PDI stream number */
7121b53385eSBard Liao 	ret = intel_params_stream(sdw, substream, dai, params,
713c46302ecSVinod Koul 				  sdw->instance,
71457a34790SPierre-Louis Bossart 				  pdi->intel_alh_id);
715c46302ecSVinod Koul 	if (ret)
71657a34790SPierre-Louis Bossart 		goto error;
717c46302ecSVinod Koul 
71857a34790SPierre-Louis Bossart 	sconfig.direction = dir;
71957a34790SPierre-Louis Bossart 	sconfig.ch_count = ch;
72057a34790SPierre-Louis Bossart 	sconfig.frame_rate = params_rate(params);
72157a34790SPierre-Louis Bossart 	sconfig.type = dai_runtime->stream_type;
72257a34790SPierre-Louis Bossart 
72357a34790SPierre-Louis Bossart 	sconfig.bps = snd_pcm_format_width(params_format(params));
724a5a0239cSBard Liao 
725e0767e39SPierre-Louis Bossart 	/* Port configuration */
726e0767e39SPierre-Louis Bossart 	pconfig = kzalloc(sizeof(*pconfig), GFP_KERNEL);
727e0767e39SPierre-Louis Bossart 	if (!pconfig) {
728c46302ecSVinod Koul 		ret =  -ENOMEM;
729c46302ecSVinod Koul 		goto error;
730b86947b5SPierre-Louis Bossart 	}
7314b206d34SRander Wang 
73257a34790SPierre-Louis Bossart 	pconfig->num = pdi->num;
733c46302ecSVinod Koul 	pconfig->ch_mask = (1 << ch) - 1;
73457a34790SPierre-Louis Bossart 
735c46302ecSVinod Koul 	ret = sdw_stream_add_master(&cdns->bus, &sconfig,
736c46302ecSVinod Koul 				    pconfig, 1, dai_runtime->stream);
737c46302ecSVinod Koul 	if (ret)
738c46302ecSVinod Koul 		dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
739e0767e39SPierre-Louis Bossart 
740c46302ecSVinod Koul 	kfree(pconfig);
741c46302ecSVinod Koul error:
742c46302ecSVinod Koul 	return ret;
743c46302ecSVinod Koul }
744235ae89bSZheng Yongjun 
intel_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)745c46302ecSVinod Koul static int intel_prepare(struct snd_pcm_substream *substream,
746c46302ecSVinod Koul 			 struct snd_soc_dai *dai)
74757a34790SPierre-Louis Bossart {
748c46302ecSVinod Koul 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
749c46302ecSVinod Koul 	struct sdw_intel *sdw = cdns_to_intel(cdns);
75057a34790SPierre-Louis Bossart 	struct sdw_cdns_dai_runtime *dai_runtime;
75157a34790SPierre-Louis Bossart 	int ch, dir;
752c46302ecSVinod Koul 	int ret = 0;
753c46302ecSVinod Koul 
754e0767e39SPierre-Louis Bossart 	dai_runtime = cdns->dai_runtime_array[dai->id];
75557a34790SPierre-Louis Bossart 	if (!dai_runtime) {
75617ed5befSPierre-Louis Bossart 		dev_err(dai->dev, "failed to get dai runtime in %s\n",
757c46302ecSVinod Koul 			__func__);
758c46302ecSVinod Koul 		return -EIO;
75957a34790SPierre-Louis Bossart 	}
760c46302ecSVinod Koul 
761c46302ecSVinod Koul 	if (dai_runtime->suspended) {
762c46302ecSVinod Koul 		struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
76327b198f4SRander Wang 		struct snd_pcm_hw_params *hw_params;
76427b198f4SRander Wang 
76527b198f4SRander Wang 		hw_params = &rtd->dpcm[substream->stream].hw_params;
766a5a0239cSBard Liao 
767a5a0239cSBard Liao 		dai_runtime->suspended = false;
768e0767e39SPierre-Louis Bossart 
769a5a0239cSBard Liao 		/*
770244eb888SPierre-Louis Bossart 		 * .prepare() is called after system resume, where we
77127b198f4SRander Wang 		 * need to reinitialize the SHIM/ALH/Cadence IP.
7727dddead7SPierre-Louis Bossart 		 * .prepare() is also called to deal with underflows,
773e0767e39SPierre-Louis Bossart 		 * but in those cases we cannot touch ALH/SHIM
774e0767e39SPierre-Louis Bossart 		 * registers
77527b198f4SRander Wang 		 */
77627b198f4SRander Wang 
77727b198f4SRander Wang 		/* configure stream */
77827b198f4SRander Wang 		ch = params_channels(hw_params);
779e0767e39SPierre-Louis Bossart 		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
780*0a0d1740SPierre-Louis Bossart 			dir = SDW_DATA_DIR_RX;
781*0a0d1740SPierre-Louis Bossart 		else
782*0a0d1740SPierre-Louis Bossart 			dir = SDW_DATA_DIR_TX;
783*0a0d1740SPierre-Louis Bossart 
784*0a0d1740SPierre-Louis Bossart 		intel_pdi_shim_configure(sdw, dai_runtime->pdi);
785e0767e39SPierre-Louis Bossart 		intel_pdi_alh_configure(sdw, dai_runtime->pdi);
786a5a0239cSBard Liao 		sdw_cdns_config_stream(cdns, ch, dir, dai_runtime->pdi);
787a5a0239cSBard Liao 
788a5a0239cSBard Liao 		/* Inform DSP about PDI stream number */
789a5a0239cSBard Liao 		ret = intel_params_stream(sdw, substream, dai,
790a5a0239cSBard Liao 					  hw_params,
791a5a0239cSBard Liao 					  sdw->instance,
792a5a0239cSBard Liao 					  dai_runtime->pdi->intel_alh_id);
793a5a0239cSBard Liao 	}
794a5a0239cSBard Liao 
795a5a0239cSBard Liao 	return ret;
796*0a0d1740SPierre-Louis Bossart }
797a5a0239cSBard Liao 
798a5a0239cSBard Liao static int
intel_hw_free(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)799a5a0239cSBard Liao intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
800a5a0239cSBard Liao {
801a5a0239cSBard Liao 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
802e0767e39SPierre-Louis Bossart 	struct sdw_cdns_dai_runtime *dai_runtime;
803e0767e39SPierre-Louis Bossart 	int ret;
804e0767e39SPierre-Louis Bossart 
805a5a0239cSBard Liao 	dai_runtime = cdns->dai_runtime_array[dai->id];
806a5a0239cSBard Liao 	if (!dai_runtime)
807b86947b5SPierre-Louis Bossart 		return -EIO;
808*0a0d1740SPierre-Louis Bossart 
809a5a0239cSBard Liao 	/*
810e0767e39SPierre-Louis Bossart 	 * The sdw stream state will transition to RELEASED when stream->
811a5a0239cSBard Liao 	 * master_list is empty. So the stream state will transition to
812a5a0239cSBard Liao 	 * DEPREPARED for the first cpu-dai and to RELEASED for the last
813a5a0239cSBard Liao 	 * cpu-dai.
81427b198f4SRander Wang 	 */
81527b198f4SRander Wang 	ret = sdw_stream_remove_master(&cdns->bus, dai_runtime->stream);
816c46302ecSVinod Koul 	if (ret < 0) {
817c46302ecSVinod Koul 		dev_err(dai->dev, "remove master from stream %s failed: %d\n",
818c46302ecSVinod Koul 			dai_runtime->stream->name, ret);
819c46302ecSVinod Koul 		return ret;
820eff346f2SPierre-Louis Bossart 	}
821e0767e39SPierre-Louis Bossart 
822c46302ecSVinod Koul 	dai_runtime->pdi = NULL;
823c46302ecSVinod Koul 
8247dddead7SPierre-Louis Bossart 	return 0;
825e0767e39SPierre-Louis Bossart }
826c46302ecSVinod Koul 
intel_pcm_set_sdw_stream(struct snd_soc_dai * dai,void * stream,int direction)827c46302ecSVinod Koul static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,
828244eb888SPierre-Louis Bossart 				    void *stream, int direction)
829244eb888SPierre-Louis Bossart {
830244eb888SPierre-Louis Bossart 	return cdns_set_sdw_stream(dai, stream, direction);
831244eb888SPierre-Louis Bossart }
832244eb888SPierre-Louis Bossart 
intel_get_sdw_stream(struct snd_soc_dai * dai,int direction)833244eb888SPierre-Louis Bossart static void *intel_get_sdw_stream(struct snd_soc_dai *dai,
834e0767e39SPierre-Louis Bossart 				  int direction)
835eff346f2SPierre-Louis Bossart {
83617ed5befSPierre-Louis Bossart 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
837e0767e39SPierre-Louis Bossart 	struct sdw_cdns_dai_runtime *dai_runtime;
838c46302ecSVinod Koul 
839c46302ecSVinod Koul 	dai_runtime = cdns->dai_runtime_array[dai->id];
840c46302ecSVinod Koul 	if (!dai_runtime)
841b86947b5SPierre-Louis Bossart 		return ERR_PTR(-EINVAL);
842eff346f2SPierre-Louis Bossart 
8434e3ea93eSPierre-Louis Bossart 	return dai_runtime->stream;
844eff346f2SPierre-Louis Bossart }
845eff346f2SPierre-Louis Bossart 
intel_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)846eff346f2SPierre-Louis Bossart static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
847e0767e39SPierre-Louis Bossart {
848a5a0239cSBard Liao 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
849eff346f2SPierre-Louis Bossart 	struct sdw_cdns_dai_runtime *dai_runtime;
850eff346f2SPierre-Louis Bossart 	int ret = 0;
851eff346f2SPierre-Louis Bossart 
852c46302ecSVinod Koul 	dai_runtime = cdns->dai_runtime_array[dai->id];
853c46302ecSVinod Koul 	if (!dai_runtime) {
854c46302ecSVinod Koul 		dev_err(dai->dev, "failed to get dai runtime in %s\n",
85563a6aa96SPierre-Louis Bossart 			__func__);
856c46302ecSVinod Koul 		return -EIO;
857c46302ecSVinod Koul 	}
85809553140SPierre-Louis Bossart 
85909553140SPierre-Louis Bossart 	switch (cmd) {
86009553140SPierre-Louis Bossart 	case SNDRV_PCM_TRIGGER_SUSPEND:
8617dddead7SPierre-Louis Bossart 
862e0767e39SPierre-Louis Bossart 		/*
86309553140SPierre-Louis Bossart 		 * The .prepare callback is used to deal with xruns and resume operations.
8647dddead7SPierre-Louis Bossart 		 * In the case of xruns, the DMAs and SHIM registers cannot be touched,
865e0767e39SPierre-Louis Bossart 		 * but for resume operations the DMAs and SHIM registers need to be initialized.
86606dcb4e4SPierre-Louis Bossart 		 * the .trigger callback is used to track the suspend case only.
86709553140SPierre-Louis Bossart 		 */
868e0767e39SPierre-Louis Bossart 
86909553140SPierre-Louis Bossart 		dai_runtime->suspended = true;
87009553140SPierre-Louis Bossart 
8718ddeafb9SRanjani Sridharan 		break;
8728ddeafb9SRanjani Sridharan 
8738ddeafb9SRanjani Sridharan 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
8748ddeafb9SRanjani Sridharan 		dai_runtime->paused = true;
8756d1c1a73SBard Liao 		break;
876e0767e39SPierre-Louis Bossart 	case SNDRV_PCM_TRIGGER_STOP:
8778ddeafb9SRanjani Sridharan 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
8788ddeafb9SRanjani Sridharan 		dai_runtime->paused = false;
8796d1c1a73SBard Liao 		break;
8806d1c1a73SBard Liao 	default:
8816d1c1a73SBard Liao 		break;
8826d1c1a73SBard Liao 	}
8836d1c1a73SBard Liao 
8846d1c1a73SBard Liao 	return ret;
8856d1c1a73SBard Liao }
8866d1c1a73SBard Liao 
intel_component_probe(struct snd_soc_component * component)8877dddead7SPierre-Louis Bossart static int intel_component_probe(struct snd_soc_component *component)
888e0767e39SPierre-Louis Bossart {
889e0767e39SPierre-Louis Bossart 	int ret;
8908ddeafb9SRanjani Sridharan 
8918ddeafb9SRanjani Sridharan 	/*
8928ddeafb9SRanjani Sridharan 	 * make sure the device is pm_runtime_active before initiating
8938ddeafb9SRanjani Sridharan 	 * bus transactions during the card registration.
8948ddeafb9SRanjani Sridharan 	 * We use pm_runtime_resume() here, without taking a reference
8958ddeafb9SRanjani Sridharan 	 * and releasing it immediately.
8968ddeafb9SRanjani Sridharan 	 */
8978ddeafb9SRanjani Sridharan 	ret = pm_runtime_resume(component->dev);
8988ddeafb9SRanjani Sridharan 	if (ret < 0 && ret != -EACCES)
8998ddeafb9SRanjani Sridharan 		return ret;
9008ddeafb9SRanjani Sridharan 
9018ddeafb9SRanjani Sridharan 	return 0;
9028ddeafb9SRanjani Sridharan }
9038ddeafb9SRanjani Sridharan 
intel_component_dais_suspend(struct snd_soc_component * component)904e0767e39SPierre-Louis Bossart static int intel_component_dais_suspend(struct snd_soc_component *component)
9058ddeafb9SRanjani Sridharan {
9068ddeafb9SRanjani Sridharan 	struct snd_soc_dai *dai;
9078ddeafb9SRanjani Sridharan 
9088ddeafb9SRanjani Sridharan 	/*
9098ddeafb9SRanjani Sridharan 	 * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core
910e0767e39SPierre-Louis Bossart 	 * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state.
9118ddeafb9SRanjani Sridharan 	 * Since the component suspend is called last, we can trap this corner case
9128ddeafb9SRanjani Sridharan 	 * and force the DAIs to release their resources.
9138ddeafb9SRanjani Sridharan 	 */
914e0767e39SPierre-Louis Bossart 	for_each_component_dais(component, dai) {
9158ddeafb9SRanjani Sridharan 		struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
9168ddeafb9SRanjani Sridharan 		struct sdw_cdns_dai_runtime *dai_runtime;
9178ddeafb9SRanjani Sridharan 
9188ddeafb9SRanjani Sridharan 		dai_runtime = cdns->dai_runtime_array[dai->id];
9198ddeafb9SRanjani Sridharan 
9208ddeafb9SRanjani Sridharan 		if (!dai_runtime)
9218ddeafb9SRanjani Sridharan 			continue;
9228ddeafb9SRanjani Sridharan 
9233e9c9f90SPierre-Louis Bossart 		if (dai_runtime->suspended)
9243e9c9f90SPierre-Louis Bossart 			continue;
9253e9c9f90SPierre-Louis Bossart 
9263e9c9f90SPierre-Louis Bossart 		if (dai_runtime->paused)
9273e9c9f90SPierre-Louis Bossart 			dai_runtime->suspended = true;
9283e9c9f90SPierre-Louis Bossart 	}
9293e9c9f90SPierre-Louis Bossart 
9303e9c9f90SPierre-Louis Bossart 	return 0;
9313e9c9f90SPierre-Louis Bossart }
9323e9c9f90SPierre-Louis Bossart 
9333e9c9f90SPierre-Louis Bossart static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
9343e9c9f90SPierre-Louis Bossart 	.hw_params = intel_hw_params,
9353e9c9f90SPierre-Louis Bossart 	.prepare = intel_prepare,
9363e9c9f90SPierre-Louis Bossart 	.hw_free = intel_hw_free,
9373e9c9f90SPierre-Louis Bossart 	.trigger = intel_trigger,
9383e9c9f90SPierre-Louis Bossart 	.set_stream = intel_pcm_set_sdw_stream,
9393e9c9f90SPierre-Louis Bossart 	.get_stream = intel_get_sdw_stream,
9408ddeafb9SRanjani Sridharan };
9418ddeafb9SRanjani Sridharan 
9428ddeafb9SRanjani Sridharan static const struct snd_soc_component_driver dai_component = {
9438ddeafb9SRanjani Sridharan 	.name			= "soundwire",
9448ddeafb9SRanjani Sridharan 	.probe			= intel_component_probe,
9458ddeafb9SRanjani Sridharan 	.suspend		= intel_component_dais_suspend,
9468ddeafb9SRanjani Sridharan 	.legacy_dai_naming	= 1,
9478ddeafb9SRanjani Sridharan };
9488ddeafb9SRanjani Sridharan 
intel_create_dai(struct sdw_cdns * cdns,struct snd_soc_dai_driver * dais,enum intel_pdi_type type,u32 num,u32 off,u32 max_ch)9498ddeafb9SRanjani Sridharan static int intel_create_dai(struct sdw_cdns *cdns,
9508ddeafb9SRanjani Sridharan 			    struct snd_soc_dai_driver *dais,
9518ddeafb9SRanjani Sridharan 			    enum intel_pdi_type type,
9528ddeafb9SRanjani Sridharan 			    u32 num, u32 off, u32 max_ch)
953e0767e39SPierre-Louis Bossart {
9548ddeafb9SRanjani Sridharan 	int i;
9558ddeafb9SRanjani Sridharan 
9567dddead7SPierre-Louis Bossart 	if (num == 0)
9578ddeafb9SRanjani Sridharan 		return 0;
958e0767e39SPierre-Louis Bossart 
9598ddeafb9SRanjani Sridharan 	for (i = off; i < (off + num); i++) {
9608ddeafb9SRanjani Sridharan 		dais[i].name = devm_kasprintf(cdns->dev, GFP_KERNEL,
961e0767e39SPierre-Louis Bossart 					      "SDW%d Pin%d",
9628ddeafb9SRanjani Sridharan 					      cdns->instance, i);
9638ddeafb9SRanjani Sridharan 		if (!dais[i].name)
964e0767e39SPierre-Louis Bossart 			return -ENOMEM;
965e0767e39SPierre-Louis Bossart 
9668ddeafb9SRanjani Sridharan 		if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) {
9677dddead7SPierre-Louis Bossart 			dais[i].playback.channels_min = 1;
9688ddeafb9SRanjani Sridharan 			dais[i].playback.channels_max = max_ch;
9698ddeafb9SRanjani Sridharan 		}
9708ddeafb9SRanjani Sridharan 
9718ddeafb9SRanjani Sridharan 		if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) {
9728ddeafb9SRanjani Sridharan 			dais[i].capture.channels_min = 1;
9738ddeafb9SRanjani Sridharan 			dais[i].capture.channels_max = max_ch;
9748ddeafb9SRanjani Sridharan 		}
9758ddeafb9SRanjani Sridharan 
976b1635596SJulia Lawall 		dais[i].ops = &intel_pcm_dai_ops;
977c46302ecSVinod Koul 	}
97827b198f4SRander Wang 
979c46302ecSVinod Koul 	return 0;
9808ddeafb9SRanjani Sridharan }
981e8444560SPierre-Louis Bossart 
intel_register_dai(struct sdw_intel * sdw)982e8444560SPierre-Louis Bossart static int intel_register_dai(struct sdw_intel *sdw)
983c46302ecSVinod Koul {
984c46302ecSVinod Koul 	struct sdw_cdns_dai_runtime **dai_runtime_array;
985c46302ecSVinod Koul 	struct sdw_cdns_stream_config config;
986c46302ecSVinod Koul 	struct sdw_cdns *cdns = &sdw->cdns;
9873e9c9f90SPierre-Louis Bossart 	struct sdw_cdns_streams *stream;
988ca682020SCharles Keepax 	struct snd_soc_dai_driver *dais;
989ca682020SCharles Keepax 	int num_dai, ret, off = 0;
990c46302ecSVinod Koul 
991c46302ecSVinod Koul 	/* Read the PDI config and initialize cadence PDI */
992c46302ecSVinod Koul 	intel_pdi_init(sdw, &config);
993c46302ecSVinod Koul 	ret = sdw_cdns_pdi_init(cdns, config);
994c46302ecSVinod Koul 	if (ret)
99563a6aa96SPierre-Louis Bossart 		return ret;
996c46302ecSVinod Koul 
997c46302ecSVinod Koul 	intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm);
998c46302ecSVinod Koul 
999c46302ecSVinod Koul 	/* DAIs are created based on total number of PDIs supported */
1000c46302ecSVinod Koul 	num_dai = cdns->pcm.num_pdi;
1001c46302ecSVinod Koul 
1002c46302ecSVinod Koul 	dai_runtime_array = devm_kcalloc(cdns->dev, num_dai,
1003bf6d6e68SPierre-Louis Bossart 					 sizeof(struct sdw_cdns_dai_runtime *),
1004bf6d6e68SPierre-Louis Bossart 					 GFP_KERNEL);
1005c46302ecSVinod Koul 	if (!dai_runtime_array)
1006c46302ecSVinod Koul 		return -ENOMEM;
1007c46302ecSVinod Koul 	cdns->dai_runtime_array = dai_runtime_array;
1008c46302ecSVinod Koul 
1009c46302ecSVinod Koul 	dais = devm_kcalloc(cdns->dev, num_dai, sizeof(*dais), GFP_KERNEL);
1010c46302ecSVinod Koul 	if (!dais)
1011c46302ecSVinod Koul 		return -ENOMEM;
1012c46302ecSVinod Koul 
1013c46302ecSVinod Koul 	/* Create PCM DAIs */
1014c46302ecSVinod Koul 	stream = &cdns->pcm;
101539194128SSrinivas Kandagatla 
101639194128SSrinivas Kandagatla 	ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pcm.num_in,
1017c46302ecSVinod Koul 			       off, stream->num_ch_in);
1018c46302ecSVinod Koul 	if (ret)
1019c46302ecSVinod Koul 		return ret;
1020c46302ecSVinod Koul 
1021c46302ecSVinod Koul 	off += cdns->pcm.num_in;
1022c46302ecSVinod Koul 	ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pcm.num_out,
1023c46302ecSVinod Koul 			       off, stream->num_ch_out);
1024c46302ecSVinod Koul 	if (ret)
1025c46302ecSVinod Koul 		return ret;
1026c46302ecSVinod Koul 
10277dddead7SPierre-Louis Bossart 	off += cdns->pcm.num_out;
102830cbae66SPierre-Louis Bossart 	ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pcm.num_bd,
1029c46302ecSVinod Koul 			       off, stream->num_ch_bd);
1030c46302ecSVinod Koul 	if (ret)
1031c46302ecSVinod Koul 		return ret;
1032c46302ecSVinod Koul 
1033c46302ecSVinod Koul 	return devm_snd_soc_register_component(cdns->dev, &dai_component,
103430cbae66SPierre-Louis Bossart 					       dais, num_dai);
103530cbae66SPierre-Louis Bossart }
103630cbae66SPierre-Louis Bossart 
103730cbae66SPierre-Louis Bossart 
103830cbae66SPierre-Louis Bossart const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops = {
103930cbae66SPierre-Louis Bossart 	.debugfs_init = intel_debugfs_init,
104059e924feSPierre-Louis Bossart 	.debugfs_exit = intel_debugfs_exit,
104130cbae66SPierre-Louis Bossart 
1042c46302ecSVinod Koul 	.register_dai = intel_register_dai,
104363a6aa96SPierre-Louis Bossart 
1044c46302ecSVinod Koul 	.check_clock_stop = intel_check_clock_stop,
10457dddead7SPierre-Louis Bossart 	.start_bus = intel_start_bus,
10467dddead7SPierre-Louis Bossart 	.start_bus_after_reset = intel_start_bus_after_reset,
10477dddead7SPierre-Louis Bossart 	.start_bus_after_clock_stop = intel_start_bus_after_clock_stop,
10487dddead7SPierre-Louis Bossart 	.stop_bus = intel_stop_bus,
10497dddead7SPierre-Louis Bossart 
10507dddead7SPierre-Louis Bossart 	.link_power_up = intel_link_power_up,
10517dddead7SPierre-Louis Bossart 	.link_power_down = intel_link_power_down,
1052c46302ecSVinod Koul 
1053c46302ecSVinod Koul 	.shim_check_wake = intel_shim_check_wake,
1054c46302ecSVinod Koul 	.shim_wake = intel_shim_wake,
1055c46302ecSVinod Koul 
1056c46302ecSVinod Koul 	.pre_bank_switch = intel_pre_bank_switch,
1057c46302ecSVinod Koul 	.post_bank_switch = intel_post_bank_switch,
1058c46302ecSVinod Koul 
1059cf924962SBard Liao 	.sync_arm = intel_shim_sync_arm,
106063a6aa96SPierre-Louis Bossart 	.sync_go_unlocked = intel_shim_sync_go_unlocked,
1061c46302ecSVinod Koul 	.sync_go = intel_shim_sync_go,
1062c46302ecSVinod Koul 	.sync_check_cmdsync_unlocked = intel_check_cmdsync_unlocked,
1063c46302ecSVinod Koul };
1064c46302ecSVinod Koul EXPORT_SYMBOL_NS(sdw_intel_cnl_hw_ops, SOUNDWIRE_INTEL);
10651215daeeSVinod Koul 
106663a6aa96SPierre-Louis Bossart