xref: /openbmc/linux/drivers/soundwire/intel_ace2x.c (revision 1b0b4c4238c0bdcf1a8ffa4c5431ec1d3fb9a345)
16f23f4e2SPierre-Louis Bossart // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
26f23f4e2SPierre-Louis Bossart // Copyright(c) 2023 Intel Corporation. All rights reserved.
36f23f4e2SPierre-Louis Bossart 
46f23f4e2SPierre-Louis Bossart /*
56f23f4e2SPierre-Louis Bossart  * Soundwire Intel ops for LunarLake
66f23f4e2SPierre-Louis Bossart  */
76f23f4e2SPierre-Louis Bossart 
86f23f4e2SPierre-Louis Bossart #include <linux/acpi.h>
96f23f4e2SPierre-Louis Bossart #include <linux/device.h>
106f23f4e2SPierre-Louis Bossart #include <linux/soundwire/sdw_registers.h>
116f23f4e2SPierre-Louis Bossart #include <linux/soundwire/sdw.h>
126f23f4e2SPierre-Louis Bossart #include <linux/soundwire/sdw_intel.h>
138c4c9a9aSPierre-Louis Bossart #include <sound/pcm_params.h>
14806f5abdSPierre-Louis Bossart #include <sound/hda-mlink.h>
156f23f4e2SPierre-Louis Bossart #include "cadence_master.h"
166f23f4e2SPierre-Louis Bossart #include "bus.h"
176f23f4e2SPierre-Louis Bossart #include "intel.h"
186f23f4e2SPierre-Louis Bossart 
19f40bb244SPierre-Louis Bossart /*
20f40bb244SPierre-Louis Bossart  * shim vendor-specific (vs) ops
21f40bb244SPierre-Louis Bossart  */
22f40bb244SPierre-Louis Bossart 
intel_shim_vs_init(struct sdw_intel * sdw)23f40bb244SPierre-Louis Bossart static void intel_shim_vs_init(struct sdw_intel *sdw)
24f40bb244SPierre-Louis Bossart {
25f40bb244SPierre-Louis Bossart 	void __iomem *shim_vs = sdw->link_res->shim_vs;
26*262853dcSChao Song 	u16 act;
27f40bb244SPierre-Louis Bossart 
28*262853dcSChao Song 	act = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_ACTMCTL);
29f40bb244SPierre-Louis Bossart 	u16p_replace_bits(&act, 0x1, SDW_SHIM2_INTEL_VS_ACTMCTL_DOAIS);
30f40bb244SPierre-Louis Bossart 	act |= SDW_SHIM2_INTEL_VS_ACTMCTL_DACTQE;
31f40bb244SPierre-Louis Bossart 	act |=  SDW_SHIM2_INTEL_VS_ACTMCTL_DODS;
32f40bb244SPierre-Louis Bossart 	intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_ACTMCTL, act);
33f40bb244SPierre-Louis Bossart 	usleep_range(10, 15);
34f40bb244SPierre-Louis Bossart }
35f40bb244SPierre-Louis Bossart 
intel_shim_check_wake(struct sdw_intel * sdw)36b8e39bc4SPierre-Louis Bossart static int intel_shim_check_wake(struct sdw_intel *sdw)
37b8e39bc4SPierre-Louis Bossart {
38b8e39bc4SPierre-Louis Bossart 	void __iomem *shim_vs;
39b8e39bc4SPierre-Louis Bossart 	u16 wake_sts;
40b8e39bc4SPierre-Louis Bossart 
41b8e39bc4SPierre-Louis Bossart 	shim_vs = sdw->link_res->shim_vs;
42b8e39bc4SPierre-Louis Bossart 	wake_sts = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS);
43b8e39bc4SPierre-Louis Bossart 
44b8e39bc4SPierre-Louis Bossart 	return wake_sts & SDW_SHIM2_INTEL_VS_WAKEEN_PWS;
45b8e39bc4SPierre-Louis Bossart }
46b8e39bc4SPierre-Louis Bossart 
intel_shim_wake(struct sdw_intel * sdw,bool wake_enable)47b8e39bc4SPierre-Louis Bossart static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
48b8e39bc4SPierre-Louis Bossart {
49b8e39bc4SPierre-Louis Bossart 	void __iomem *shim_vs = sdw->link_res->shim_vs;
50b8e39bc4SPierre-Louis Bossart 	u16 wake_en;
51b8e39bc4SPierre-Louis Bossart 	u16 wake_sts;
52b8e39bc4SPierre-Louis Bossart 
53b8e39bc4SPierre-Louis Bossart 	wake_en = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN);
54b8e39bc4SPierre-Louis Bossart 
55b8e39bc4SPierre-Louis Bossart 	if (wake_enable) {
56b8e39bc4SPierre-Louis Bossart 		/* Enable the wakeup */
57b8e39bc4SPierre-Louis Bossart 		wake_en |= SDW_SHIM2_INTEL_VS_WAKEEN_PWE;
58b8e39bc4SPierre-Louis Bossart 		intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN, wake_en);
59b8e39bc4SPierre-Louis Bossart 	} else {
60b8e39bc4SPierre-Louis Bossart 		/* Disable the wake up interrupt */
61b8e39bc4SPierre-Louis Bossart 		wake_en &= ~SDW_SHIM2_INTEL_VS_WAKEEN_PWE;
62b8e39bc4SPierre-Louis Bossart 		intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN, wake_en);
63b8e39bc4SPierre-Louis Bossart 
64b8e39bc4SPierre-Louis Bossart 		/* Clear wake status (W1C) */
65b8e39bc4SPierre-Louis Bossart 		wake_sts = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS);
66b8e39bc4SPierre-Louis Bossart 		wake_sts |= SDW_SHIM2_INTEL_VS_WAKEEN_PWS;
67b8e39bc4SPierre-Louis Bossart 		intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS, wake_sts);
68b8e39bc4SPierre-Louis Bossart 	}
69b8e39bc4SPierre-Louis Bossart }
70b8e39bc4SPierre-Louis Bossart 
intel_link_power_up(struct sdw_intel * sdw)71806f5abdSPierre-Louis Bossart static int intel_link_power_up(struct sdw_intel *sdw)
72806f5abdSPierre-Louis Bossart {
73d3565643SPierre-Louis Bossart 	struct sdw_bus *bus = &sdw->cdns.bus;
74d3565643SPierre-Louis Bossart 	struct sdw_master_prop *prop = &bus->prop;
75d3565643SPierre-Louis Bossart 	u32 *shim_mask = sdw->link_res->shim_mask;
76d3565643SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
77d3565643SPierre-Louis Bossart 	u32 syncprd;
78806f5abdSPierre-Louis Bossart 	int ret;
79806f5abdSPierre-Louis Bossart 
80806f5abdSPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
81806f5abdSPierre-Louis Bossart 
82d3565643SPierre-Louis Bossart 	if (!*shim_mask) {
83d3565643SPierre-Louis Bossart 		/* we first need to program the SyncPRD/CPU registers */
84d3565643SPierre-Louis Bossart 		dev_dbg(sdw->cdns.dev, "first link up, programming SYNCPRD\n");
85d3565643SPierre-Louis Bossart 
86d3565643SPierre-Louis Bossart 		if (prop->mclk_freq % 6000000)
87d3565643SPierre-Louis Bossart 			syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
88d3565643SPierre-Louis Bossart 		else
89d3565643SPierre-Louis Bossart 			syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;
90d3565643SPierre-Louis Bossart 
91d3565643SPierre-Louis Bossart 		ret =  hdac_bus_eml_sdw_set_syncprd_unlocked(sdw->link_res->hbus, syncprd);
92d3565643SPierre-Louis Bossart 		if (ret < 0) {
93d3565643SPierre-Louis Bossart 			dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_set_syncprd failed: %d\n",
94d3565643SPierre-Louis Bossart 				__func__, ret);
95d3565643SPierre-Louis Bossart 			goto out;
96d3565643SPierre-Louis Bossart 		}
97d3565643SPierre-Louis Bossart 	}
98d3565643SPierre-Louis Bossart 
99d3565643SPierre-Louis Bossart 	ret = hdac_bus_eml_sdw_power_up_unlocked(sdw->link_res->hbus, link_id);
100806f5abdSPierre-Louis Bossart 	if (ret < 0) {
101806f5abdSPierre-Louis Bossart 		dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_up failed: %d\n",
102806f5abdSPierre-Louis Bossart 			__func__, ret);
103806f5abdSPierre-Louis Bossart 		goto out;
104806f5abdSPierre-Louis Bossart 	}
105806f5abdSPierre-Louis Bossart 
106d3565643SPierre-Louis Bossart 	if (!*shim_mask) {
107d3565643SPierre-Louis Bossart 		/* SYNCPU will change once link is active */
108d3565643SPierre-Louis Bossart 		ret =  hdac_bus_eml_sdw_wait_syncpu_unlocked(sdw->link_res->hbus);
109d3565643SPierre-Louis Bossart 		if (ret < 0) {
110d3565643SPierre-Louis Bossart 			dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_wait_syncpu failed: %d\n",
111d3565643SPierre-Louis Bossart 				__func__, ret);
112d3565643SPierre-Louis Bossart 			goto out;
113d3565643SPierre-Louis Bossart 		}
114d3565643SPierre-Louis Bossart 	}
115d3565643SPierre-Louis Bossart 
116d3565643SPierre-Louis Bossart 	*shim_mask |= BIT(link_id);
117d3565643SPierre-Louis Bossart 
118806f5abdSPierre-Louis Bossart 	sdw->cdns.link_up = true;
119f40bb244SPierre-Louis Bossart 
120f40bb244SPierre-Louis Bossart 	intel_shim_vs_init(sdw);
121f40bb244SPierre-Louis Bossart 
122806f5abdSPierre-Louis Bossart out:
123806f5abdSPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
124806f5abdSPierre-Louis Bossart 
125806f5abdSPierre-Louis Bossart 	return ret;
126806f5abdSPierre-Louis Bossart }
127806f5abdSPierre-Louis Bossart 
intel_link_power_down(struct sdw_intel * sdw)128806f5abdSPierre-Louis Bossart static int intel_link_power_down(struct sdw_intel *sdw)
129806f5abdSPierre-Louis Bossart {
130d3565643SPierre-Louis Bossart 	u32 *shim_mask = sdw->link_res->shim_mask;
131d3565643SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
132806f5abdSPierre-Louis Bossart 	int ret;
133806f5abdSPierre-Louis Bossart 
134806f5abdSPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
135806f5abdSPierre-Louis Bossart 
136806f5abdSPierre-Louis Bossart 	sdw->cdns.link_up = false;
137806f5abdSPierre-Louis Bossart 
138d3565643SPierre-Louis Bossart 	*shim_mask &= ~BIT(link_id);
139d3565643SPierre-Louis Bossart 
140d3565643SPierre-Louis Bossart 	ret = hdac_bus_eml_sdw_power_down_unlocked(sdw->link_res->hbus, link_id);
141806f5abdSPierre-Louis Bossart 	if (ret < 0) {
142806f5abdSPierre-Louis Bossart 		dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_down failed: %d\n",
143806f5abdSPierre-Louis Bossart 			__func__, ret);
144806f5abdSPierre-Louis Bossart 
145806f5abdSPierre-Louis Bossart 		/*
146806f5abdSPierre-Louis Bossart 		 * we leave the sdw->cdns.link_up flag as false since we've disabled
147806f5abdSPierre-Louis Bossart 		 * the link at this point and cannot handle interrupts any longer.
148806f5abdSPierre-Louis Bossart 		 */
149806f5abdSPierre-Louis Bossart 	}
150806f5abdSPierre-Louis Bossart 
151806f5abdSPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
152806f5abdSPierre-Louis Bossart 
153806f5abdSPierre-Louis Bossart 	return ret;
154806f5abdSPierre-Louis Bossart }
155806f5abdSPierre-Louis Bossart 
intel_sync_arm(struct sdw_intel * sdw)1564d1e2464SPierre-Louis Bossart static void intel_sync_arm(struct sdw_intel *sdw)
1574d1e2464SPierre-Louis Bossart {
1584d1e2464SPierre-Louis Bossart 	unsigned int link_id = sdw->instance;
1594d1e2464SPierre-Louis Bossart 
1604d1e2464SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
1614d1e2464SPierre-Louis Bossart 
1624d1e2464SPierre-Louis Bossart 	hdac_bus_eml_sdw_sync_arm_unlocked(sdw->link_res->hbus, link_id);
1634d1e2464SPierre-Louis Bossart 
1644d1e2464SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
1654d1e2464SPierre-Louis Bossart }
1664d1e2464SPierre-Louis Bossart 
intel_sync_go_unlocked(struct sdw_intel * sdw)1674d1e2464SPierre-Louis Bossart static int intel_sync_go_unlocked(struct sdw_intel *sdw)
1684d1e2464SPierre-Louis Bossart {
1694d1e2464SPierre-Louis Bossart 	int ret;
1704d1e2464SPierre-Louis Bossart 
1714d1e2464SPierre-Louis Bossart 	ret = hdac_bus_eml_sdw_sync_go_unlocked(sdw->link_res->hbus);
1724d1e2464SPierre-Louis Bossart 	if (ret < 0)
1734d1e2464SPierre-Louis Bossart 		dev_err(sdw->cdns.dev, "%s: SyncGO clear failed: %d\n", __func__, ret);
1744d1e2464SPierre-Louis Bossart 
1754d1e2464SPierre-Louis Bossart 	return ret;
1764d1e2464SPierre-Louis Bossart }
1774d1e2464SPierre-Louis Bossart 
intel_sync_go(struct sdw_intel * sdw)1784d1e2464SPierre-Louis Bossart static int intel_sync_go(struct sdw_intel *sdw)
1794d1e2464SPierre-Louis Bossart {
1804d1e2464SPierre-Louis Bossart 	int ret;
1814d1e2464SPierre-Louis Bossart 
1824d1e2464SPierre-Louis Bossart 	mutex_lock(sdw->link_res->shim_lock);
1834d1e2464SPierre-Louis Bossart 
1844d1e2464SPierre-Louis Bossart 	ret = intel_sync_go_unlocked(sdw);
1854d1e2464SPierre-Louis Bossart 
1864d1e2464SPierre-Louis Bossart 	mutex_unlock(sdw->link_res->shim_lock);
1874d1e2464SPierre-Louis Bossart 
1884d1e2464SPierre-Louis Bossart 	return ret;
1894d1e2464SPierre-Louis Bossart }
1904d1e2464SPierre-Louis Bossart 
intel_check_cmdsync_unlocked(struct sdw_intel * sdw)1917ba18639SPierre-Louis Bossart static bool intel_check_cmdsync_unlocked(struct sdw_intel *sdw)
1927ba18639SPierre-Louis Bossart {
1937ba18639SPierre-Louis Bossart 	return hdac_bus_eml_sdw_check_cmdsync_unlocked(sdw->link_res->hbus);
1947ba18639SPierre-Louis Bossart }
1957ba18639SPierre-Louis Bossart 
1968c4c9a9aSPierre-Louis Bossart /* DAI callbacks */
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)1978c4c9a9aSPierre-Louis Bossart static int intel_params_stream(struct sdw_intel *sdw,
1988c4c9a9aSPierre-Louis Bossart 			       struct snd_pcm_substream *substream,
1998c4c9a9aSPierre-Louis Bossart 			       struct snd_soc_dai *dai,
2008c4c9a9aSPierre-Louis Bossart 			       struct snd_pcm_hw_params *hw_params,
2018c4c9a9aSPierre-Louis Bossart 			       int link_id, int alh_stream_id)
2028c4c9a9aSPierre-Louis Bossart {
2038c4c9a9aSPierre-Louis Bossart 	struct sdw_intel_link_res *res = sdw->link_res;
2048c4c9a9aSPierre-Louis Bossart 	struct sdw_intel_stream_params_data params_data;
2058c4c9a9aSPierre-Louis Bossart 
2068c4c9a9aSPierre-Louis Bossart 	params_data.substream = substream;
2078c4c9a9aSPierre-Louis Bossart 	params_data.dai = dai;
2088c4c9a9aSPierre-Louis Bossart 	params_data.hw_params = hw_params;
2098c4c9a9aSPierre-Louis Bossart 	params_data.link_id = link_id;
2108c4c9a9aSPierre-Louis Bossart 	params_data.alh_stream_id = alh_stream_id;
2118c4c9a9aSPierre-Louis Bossart 
2128c4c9a9aSPierre-Louis Bossart 	if (res->ops && res->ops->params_stream && res->dev)
2138c4c9a9aSPierre-Louis Bossart 		return res->ops->params_stream(res->dev,
2148c4c9a9aSPierre-Louis Bossart 					       &params_data);
2158c4c9a9aSPierre-Louis Bossart 	return -EIO;
2168c4c9a9aSPierre-Louis Bossart }
2178c4c9a9aSPierre-Louis Bossart 
intel_free_stream(struct sdw_intel * sdw,struct snd_pcm_substream * substream,struct snd_soc_dai * dai,int link_id)2188c4c9a9aSPierre-Louis Bossart static int intel_free_stream(struct sdw_intel *sdw,
2198c4c9a9aSPierre-Louis Bossart 			     struct snd_pcm_substream *substream,
2208c4c9a9aSPierre-Louis Bossart 			     struct snd_soc_dai *dai,
2218c4c9a9aSPierre-Louis Bossart 			     int link_id)
2228c4c9a9aSPierre-Louis Bossart 
2238c4c9a9aSPierre-Louis Bossart {
2248c4c9a9aSPierre-Louis Bossart 	struct sdw_intel_link_res *res = sdw->link_res;
2258c4c9a9aSPierre-Louis Bossart 	struct sdw_intel_stream_free_data free_data;
2268c4c9a9aSPierre-Louis Bossart 
2278c4c9a9aSPierre-Louis Bossart 	free_data.substream = substream;
2288c4c9a9aSPierre-Louis Bossart 	free_data.dai = dai;
2298c4c9a9aSPierre-Louis Bossart 	free_data.link_id = link_id;
2308c4c9a9aSPierre-Louis Bossart 
2318c4c9a9aSPierre-Louis Bossart 	if (res->ops && res->ops->free_stream && res->dev)
2328c4c9a9aSPierre-Louis Bossart 		return res->ops->free_stream(res->dev,
2338c4c9a9aSPierre-Louis Bossart 					     &free_data);
2348c4c9a9aSPierre-Louis Bossart 
2358c4c9a9aSPierre-Louis Bossart 	return 0;
2368c4c9a9aSPierre-Louis Bossart }
2378c4c9a9aSPierre-Louis Bossart 
238d2f0daf6SPierre-Louis Bossart /*
239d2f0daf6SPierre-Louis Bossart  * DAI operations
240d2f0daf6SPierre-Louis Bossart  */
intel_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)2418c4c9a9aSPierre-Louis Bossart static int intel_hw_params(struct snd_pcm_substream *substream,
2428c4c9a9aSPierre-Louis Bossart 			   struct snd_pcm_hw_params *params,
2438c4c9a9aSPierre-Louis Bossart 			   struct snd_soc_dai *dai)
2448c4c9a9aSPierre-Louis Bossart {
2458c4c9a9aSPierre-Louis Bossart 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
2468c4c9a9aSPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
2478c4c9a9aSPierre-Louis Bossart 	struct sdw_cdns_dai_runtime *dai_runtime;
2488c4c9a9aSPierre-Louis Bossart 	struct sdw_cdns_pdi *pdi;
2498c4c9a9aSPierre-Louis Bossart 	struct sdw_stream_config sconfig;
2508c4c9a9aSPierre-Louis Bossart 	struct sdw_port_config *pconfig;
2518c4c9a9aSPierre-Louis Bossart 	int ch, dir;
2528c4c9a9aSPierre-Louis Bossart 	int ret;
2538c4c9a9aSPierre-Louis Bossart 
2548c4c9a9aSPierre-Louis Bossart 	dai_runtime = cdns->dai_runtime_array[dai->id];
2558c4c9a9aSPierre-Louis Bossart 	if (!dai_runtime)
2568c4c9a9aSPierre-Louis Bossart 		return -EIO;
2578c4c9a9aSPierre-Louis Bossart 
2588c4c9a9aSPierre-Louis Bossart 	ch = params_channels(params);
2598c4c9a9aSPierre-Louis Bossart 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
2608c4c9a9aSPierre-Louis Bossart 		dir = SDW_DATA_DIR_RX;
2618c4c9a9aSPierre-Louis Bossart 	else
2628c4c9a9aSPierre-Louis Bossart 		dir = SDW_DATA_DIR_TX;
2638c4c9a9aSPierre-Louis Bossart 
2648c4c9a9aSPierre-Louis Bossart 	pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
2658c4c9a9aSPierre-Louis Bossart 
2668c4c9a9aSPierre-Louis Bossart 	if (!pdi) {
2678c4c9a9aSPierre-Louis Bossart 		ret = -EINVAL;
2688c4c9a9aSPierre-Louis Bossart 		goto error;
2698c4c9a9aSPierre-Louis Bossart 	}
2708c4c9a9aSPierre-Louis Bossart 
2718c4c9a9aSPierre-Louis Bossart 	/* the SHIM will be configured in the callback functions */
2728c4c9a9aSPierre-Louis Bossart 
2738c4c9a9aSPierre-Louis Bossart 	sdw_cdns_config_stream(cdns, ch, dir, pdi);
2748c4c9a9aSPierre-Louis Bossart 
2758c4c9a9aSPierre-Louis Bossart 	/* store pdi and state, may be needed in prepare step */
2768c4c9a9aSPierre-Louis Bossart 	dai_runtime->paused = false;
2778c4c9a9aSPierre-Louis Bossart 	dai_runtime->suspended = false;
2788c4c9a9aSPierre-Louis Bossart 	dai_runtime->pdi = pdi;
2798c4c9a9aSPierre-Louis Bossart 
2808c4c9a9aSPierre-Louis Bossart 	/* Inform DSP about PDI stream number */
2818c4c9a9aSPierre-Louis Bossart 	ret = intel_params_stream(sdw, substream, dai, params,
2828c4c9a9aSPierre-Louis Bossart 				  sdw->instance,
2838c4c9a9aSPierre-Louis Bossart 				  pdi->intel_alh_id);
2848c4c9a9aSPierre-Louis Bossart 	if (ret)
2858c4c9a9aSPierre-Louis Bossart 		goto error;
2868c4c9a9aSPierre-Louis Bossart 
2878c4c9a9aSPierre-Louis Bossart 	sconfig.direction = dir;
2888c4c9a9aSPierre-Louis Bossart 	sconfig.ch_count = ch;
2898c4c9a9aSPierre-Louis Bossart 	sconfig.frame_rate = params_rate(params);
2908c4c9a9aSPierre-Louis Bossart 	sconfig.type = dai_runtime->stream_type;
2918c4c9a9aSPierre-Louis Bossart 
2928c4c9a9aSPierre-Louis Bossart 	sconfig.bps = snd_pcm_format_width(params_format(params));
2938c4c9a9aSPierre-Louis Bossart 
2948c4c9a9aSPierre-Louis Bossart 	/* Port configuration */
2958c4c9a9aSPierre-Louis Bossart 	pconfig = kzalloc(sizeof(*pconfig), GFP_KERNEL);
2968c4c9a9aSPierre-Louis Bossart 	if (!pconfig) {
2978c4c9a9aSPierre-Louis Bossart 		ret =  -ENOMEM;
2988c4c9a9aSPierre-Louis Bossart 		goto error;
2998c4c9a9aSPierre-Louis Bossart 	}
3008c4c9a9aSPierre-Louis Bossart 
3018c4c9a9aSPierre-Louis Bossart 	pconfig->num = pdi->num;
3028c4c9a9aSPierre-Louis Bossart 	pconfig->ch_mask = (1 << ch) - 1;
3038c4c9a9aSPierre-Louis Bossart 
3048c4c9a9aSPierre-Louis Bossart 	ret = sdw_stream_add_master(&cdns->bus, &sconfig,
3058c4c9a9aSPierre-Louis Bossart 				    pconfig, 1, dai_runtime->stream);
3068c4c9a9aSPierre-Louis Bossart 	if (ret)
3078c4c9a9aSPierre-Louis Bossart 		dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
3088c4c9a9aSPierre-Louis Bossart 
3098c4c9a9aSPierre-Louis Bossart 	kfree(pconfig);
3108c4c9a9aSPierre-Louis Bossart error:
3118c4c9a9aSPierre-Louis Bossart 	return ret;
3128c4c9a9aSPierre-Louis Bossart }
3138c4c9a9aSPierre-Louis Bossart 
intel_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)3148c4c9a9aSPierre-Louis Bossart static int intel_prepare(struct snd_pcm_substream *substream,
3158c4c9a9aSPierre-Louis Bossart 			 struct snd_soc_dai *dai)
3168c4c9a9aSPierre-Louis Bossart {
3178c4c9a9aSPierre-Louis Bossart 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
3188c4c9a9aSPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
3198c4c9a9aSPierre-Louis Bossart 	struct sdw_cdns_dai_runtime *dai_runtime;
3208c4c9a9aSPierre-Louis Bossart 	int ch, dir;
3218c4c9a9aSPierre-Louis Bossart 	int ret = 0;
3228c4c9a9aSPierre-Louis Bossart 
3238c4c9a9aSPierre-Louis Bossart 	dai_runtime = cdns->dai_runtime_array[dai->id];
3248c4c9a9aSPierre-Louis Bossart 	if (!dai_runtime) {
3258c4c9a9aSPierre-Louis Bossart 		dev_err(dai->dev, "failed to get dai runtime in %s\n",
3268c4c9a9aSPierre-Louis Bossart 			__func__);
3278c4c9a9aSPierre-Louis Bossart 		return -EIO;
3288c4c9a9aSPierre-Louis Bossart 	}
3298c4c9a9aSPierre-Louis Bossart 
3308c4c9a9aSPierre-Louis Bossart 	if (dai_runtime->suspended) {
3318c4c9a9aSPierre-Louis Bossart 		struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
3328c4c9a9aSPierre-Louis Bossart 		struct snd_pcm_hw_params *hw_params;
3338c4c9a9aSPierre-Louis Bossart 
3348c4c9a9aSPierre-Louis Bossart 		hw_params = &rtd->dpcm[substream->stream].hw_params;
3358c4c9a9aSPierre-Louis Bossart 
3368c4c9a9aSPierre-Louis Bossart 		dai_runtime->suspended = false;
3378c4c9a9aSPierre-Louis Bossart 
3388c4c9a9aSPierre-Louis Bossart 		/*
3398c4c9a9aSPierre-Louis Bossart 		 * .prepare() is called after system resume, where we
3408c4c9a9aSPierre-Louis Bossart 		 * need to reinitialize the SHIM/ALH/Cadence IP.
3418c4c9a9aSPierre-Louis Bossart 		 * .prepare() is also called to deal with underflows,
3428c4c9a9aSPierre-Louis Bossart 		 * but in those cases we cannot touch ALH/SHIM
3438c4c9a9aSPierre-Louis Bossart 		 * registers
3448c4c9a9aSPierre-Louis Bossart 		 */
3458c4c9a9aSPierre-Louis Bossart 
3468c4c9a9aSPierre-Louis Bossart 		/* configure stream */
3478c4c9a9aSPierre-Louis Bossart 		ch = params_channels(hw_params);
3488c4c9a9aSPierre-Louis Bossart 		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
3498c4c9a9aSPierre-Louis Bossart 			dir = SDW_DATA_DIR_RX;
3508c4c9a9aSPierre-Louis Bossart 		else
3518c4c9a9aSPierre-Louis Bossart 			dir = SDW_DATA_DIR_TX;
3528c4c9a9aSPierre-Louis Bossart 
3538c4c9a9aSPierre-Louis Bossart 		/* the SHIM will be configured in the callback functions */
3548c4c9a9aSPierre-Louis Bossart 
3558c4c9a9aSPierre-Louis Bossart 		sdw_cdns_config_stream(cdns, ch, dir, dai_runtime->pdi);
3568c4c9a9aSPierre-Louis Bossart 
3578c4c9a9aSPierre-Louis Bossart 		/* Inform DSP about PDI stream number */
3588c4c9a9aSPierre-Louis Bossart 		ret = intel_params_stream(sdw, substream, dai,
3598c4c9a9aSPierre-Louis Bossart 					  hw_params,
3608c4c9a9aSPierre-Louis Bossart 					  sdw->instance,
3618c4c9a9aSPierre-Louis Bossart 					  dai_runtime->pdi->intel_alh_id);
3628c4c9a9aSPierre-Louis Bossart 	}
3638c4c9a9aSPierre-Louis Bossart 
3648c4c9a9aSPierre-Louis Bossart 	return ret;
3658c4c9a9aSPierre-Louis Bossart }
3668c4c9a9aSPierre-Louis Bossart 
3678c4c9a9aSPierre-Louis Bossart static int
intel_hw_free(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)3688c4c9a9aSPierre-Louis Bossart intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
3698c4c9a9aSPierre-Louis Bossart {
3708c4c9a9aSPierre-Louis Bossart 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
3718c4c9a9aSPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
3728c4c9a9aSPierre-Louis Bossart 	struct sdw_cdns_dai_runtime *dai_runtime;
3738c4c9a9aSPierre-Louis Bossart 	int ret;
3748c4c9a9aSPierre-Louis Bossart 
3758c4c9a9aSPierre-Louis Bossart 	dai_runtime = cdns->dai_runtime_array[dai->id];
3768c4c9a9aSPierre-Louis Bossart 	if (!dai_runtime)
3778c4c9a9aSPierre-Louis Bossart 		return -EIO;
3788c4c9a9aSPierre-Louis Bossart 
3798c4c9a9aSPierre-Louis Bossart 	/*
3808c4c9a9aSPierre-Louis Bossart 	 * The sdw stream state will transition to RELEASED when stream->
3818c4c9a9aSPierre-Louis Bossart 	 * master_list is empty. So the stream state will transition to
3828c4c9a9aSPierre-Louis Bossart 	 * DEPREPARED for the first cpu-dai and to RELEASED for the last
3838c4c9a9aSPierre-Louis Bossart 	 * cpu-dai.
3848c4c9a9aSPierre-Louis Bossart 	 */
3858c4c9a9aSPierre-Louis Bossart 	ret = sdw_stream_remove_master(&cdns->bus, dai_runtime->stream);
3868c4c9a9aSPierre-Louis Bossart 	if (ret < 0) {
3878c4c9a9aSPierre-Louis Bossart 		dev_err(dai->dev, "remove master from stream %s failed: %d\n",
3888c4c9a9aSPierre-Louis Bossart 			dai_runtime->stream->name, ret);
3898c4c9a9aSPierre-Louis Bossart 		return ret;
3908c4c9a9aSPierre-Louis Bossart 	}
3918c4c9a9aSPierre-Louis Bossart 
3928c4c9a9aSPierre-Louis Bossart 	ret = intel_free_stream(sdw, substream, dai, sdw->instance);
3938c4c9a9aSPierre-Louis Bossart 	if (ret < 0) {
3948c4c9a9aSPierre-Louis Bossart 		dev_err(dai->dev, "intel_free_stream: failed %d\n", ret);
3958c4c9a9aSPierre-Louis Bossart 		return ret;
3968c4c9a9aSPierre-Louis Bossart 	}
3978c4c9a9aSPierre-Louis Bossart 
3988c4c9a9aSPierre-Louis Bossart 	dai_runtime->pdi = NULL;
3998c4c9a9aSPierre-Louis Bossart 
4008c4c9a9aSPierre-Louis Bossart 	return 0;
4018c4c9a9aSPierre-Louis Bossart }
4028c4c9a9aSPierre-Louis Bossart 
intel_pcm_set_sdw_stream(struct snd_soc_dai * dai,void * stream,int direction)4038c4c9a9aSPierre-Louis Bossart static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,
4048c4c9a9aSPierre-Louis Bossart 				    void *stream, int direction)
4058c4c9a9aSPierre-Louis Bossart {
4068c4c9a9aSPierre-Louis Bossart 	return cdns_set_sdw_stream(dai, stream, direction);
4078c4c9a9aSPierre-Louis Bossart }
4088c4c9a9aSPierre-Louis Bossart 
intel_get_sdw_stream(struct snd_soc_dai * dai,int direction)4098c4c9a9aSPierre-Louis Bossart static void *intel_get_sdw_stream(struct snd_soc_dai *dai,
4108c4c9a9aSPierre-Louis Bossart 				  int direction)
4118c4c9a9aSPierre-Louis Bossart {
4128c4c9a9aSPierre-Louis Bossart 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
4138c4c9a9aSPierre-Louis Bossart 	struct sdw_cdns_dai_runtime *dai_runtime;
4148c4c9a9aSPierre-Louis Bossart 
4158c4c9a9aSPierre-Louis Bossart 	dai_runtime = cdns->dai_runtime_array[dai->id];
4168c4c9a9aSPierre-Louis Bossart 	if (!dai_runtime)
4178c4c9a9aSPierre-Louis Bossart 		return ERR_PTR(-EINVAL);
4188c4c9a9aSPierre-Louis Bossart 
4198c4c9a9aSPierre-Louis Bossart 	return dai_runtime->stream;
4208c4c9a9aSPierre-Louis Bossart }
4218c4c9a9aSPierre-Louis Bossart 
intel_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)4228c4c9a9aSPierre-Louis Bossart static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
4238c4c9a9aSPierre-Louis Bossart {
4248c4c9a9aSPierre-Louis Bossart 	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
4258c4c9a9aSPierre-Louis Bossart 	struct sdw_intel *sdw = cdns_to_intel(cdns);
4268c4c9a9aSPierre-Louis Bossart 	struct sdw_intel_link_res *res = sdw->link_res;
4278c4c9a9aSPierre-Louis Bossart 	struct sdw_cdns_dai_runtime *dai_runtime;
4288c4c9a9aSPierre-Louis Bossart 	int ret = 0;
4298c4c9a9aSPierre-Louis Bossart 
4308c4c9a9aSPierre-Louis Bossart 	/*
4318c4c9a9aSPierre-Louis Bossart 	 * The .trigger callback is used to program HDaudio DMA and send required IPC to audio
4328c4c9a9aSPierre-Louis Bossart 	 * firmware.
4338c4c9a9aSPierre-Louis Bossart 	 */
4348c4c9a9aSPierre-Louis Bossart 	if (res->ops && res->ops->trigger) {
4358c4c9a9aSPierre-Louis Bossart 		ret = res->ops->trigger(substream, cmd, dai);
4368c4c9a9aSPierre-Louis Bossart 		if (ret < 0)
4378c4c9a9aSPierre-Louis Bossart 			return ret;
4388c4c9a9aSPierre-Louis Bossart 	}
4398c4c9a9aSPierre-Louis Bossart 
4408c4c9a9aSPierre-Louis Bossart 	dai_runtime = cdns->dai_runtime_array[dai->id];
4418c4c9a9aSPierre-Louis Bossart 	if (!dai_runtime) {
4428c4c9a9aSPierre-Louis Bossart 		dev_err(dai->dev, "failed to get dai runtime in %s\n",
4438c4c9a9aSPierre-Louis Bossart 			__func__);
4448c4c9a9aSPierre-Louis Bossart 		return -EIO;
4458c4c9a9aSPierre-Louis Bossart 	}
4468c4c9a9aSPierre-Louis Bossart 
4478c4c9a9aSPierre-Louis Bossart 	switch (cmd) {
4488c4c9a9aSPierre-Louis Bossart 	case SNDRV_PCM_TRIGGER_SUSPEND:
4498c4c9a9aSPierre-Louis Bossart 
4508c4c9a9aSPierre-Louis Bossart 		/*
4518c4c9a9aSPierre-Louis Bossart 		 * The .prepare callback is used to deal with xruns and resume operations.
4528c4c9a9aSPierre-Louis Bossart 		 * In the case of xruns, the DMAs and SHIM registers cannot be touched,
4538c4c9a9aSPierre-Louis Bossart 		 * but for resume operations the DMAs and SHIM registers need to be initialized.
4548c4c9a9aSPierre-Louis Bossart 		 * the .trigger callback is used to track the suspend case only.
4558c4c9a9aSPierre-Louis Bossart 		 */
4568c4c9a9aSPierre-Louis Bossart 
4578c4c9a9aSPierre-Louis Bossart 		dai_runtime->suspended = true;
4588c4c9a9aSPierre-Louis Bossart 
4598c4c9a9aSPierre-Louis Bossart 		break;
4608c4c9a9aSPierre-Louis Bossart 
4618c4c9a9aSPierre-Louis Bossart 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
4628c4c9a9aSPierre-Louis Bossart 		dai_runtime->paused = true;
4638c4c9a9aSPierre-Louis Bossart 		break;
4648c4c9a9aSPierre-Louis Bossart 	case SNDRV_PCM_TRIGGER_STOP:
4658c4c9a9aSPierre-Louis Bossart 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
4668c4c9a9aSPierre-Louis Bossart 		dai_runtime->paused = false;
4678c4c9a9aSPierre-Louis Bossart 		break;
4688c4c9a9aSPierre-Louis Bossart 	default:
4698c4c9a9aSPierre-Louis Bossart 		break;
4708c4c9a9aSPierre-Louis Bossart 	}
4718c4c9a9aSPierre-Louis Bossart 
4728c4c9a9aSPierre-Louis Bossart 	return ret;
4738c4c9a9aSPierre-Louis Bossart }
4748c4c9a9aSPierre-Louis Bossart 
475d2f0daf6SPierre-Louis Bossart static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
4768c4c9a9aSPierre-Louis Bossart 	.hw_params = intel_hw_params,
4778c4c9a9aSPierre-Louis Bossart 	.prepare = intel_prepare,
4788c4c9a9aSPierre-Louis Bossart 	.hw_free = intel_hw_free,
4798c4c9a9aSPierre-Louis Bossart 	.trigger = intel_trigger,
4808c4c9a9aSPierre-Louis Bossart 	.set_stream = intel_pcm_set_sdw_stream,
4818c4c9a9aSPierre-Louis Bossart 	.get_stream = intel_get_sdw_stream,
482d2f0daf6SPierre-Louis Bossart };
483d2f0daf6SPierre-Louis Bossart 
484d2f0daf6SPierre-Louis Bossart static const struct snd_soc_component_driver dai_component = {
485d2f0daf6SPierre-Louis Bossart 	.name			= "soundwire",
486d2f0daf6SPierre-Louis Bossart };
487d2f0daf6SPierre-Louis Bossart 
488d2f0daf6SPierre-Louis Bossart /*
489d2f0daf6SPierre-Louis Bossart  * PDI routines
490d2f0daf6SPierre-Louis Bossart  */
intel_pdi_init(struct sdw_intel * sdw,struct sdw_cdns_stream_config * config)491d2f0daf6SPierre-Louis Bossart static void intel_pdi_init(struct sdw_intel *sdw,
492d2f0daf6SPierre-Louis Bossart 			   struct sdw_cdns_stream_config *config)
493d2f0daf6SPierre-Louis Bossart {
494d2f0daf6SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
495d2f0daf6SPierre-Louis Bossart 	int pcm_cap;
496d2f0daf6SPierre-Louis Bossart 
497d2f0daf6SPierre-Louis Bossart 	/* PCM Stream Capability */
498d2f0daf6SPierre-Louis Bossart 	pcm_cap = intel_readw(shim, SDW_SHIM2_PCMSCAP);
499d2f0daf6SPierre-Louis Bossart 
500d2f0daf6SPierre-Louis Bossart 	config->pcm_bd = FIELD_GET(SDW_SHIM2_PCMSCAP_BSS, pcm_cap);
501d2f0daf6SPierre-Louis Bossart 	config->pcm_in = FIELD_GET(SDW_SHIM2_PCMSCAP_ISS, pcm_cap);
502d2f0daf6SPierre-Louis Bossart 	config->pcm_out = FIELD_GET(SDW_SHIM2_PCMSCAP_ISS, pcm_cap);
503d2f0daf6SPierre-Louis Bossart 
504d2f0daf6SPierre-Louis Bossart 	dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n",
505d2f0daf6SPierre-Louis Bossart 		config->pcm_bd, config->pcm_in, config->pcm_out);
506d2f0daf6SPierre-Louis Bossart }
507d2f0daf6SPierre-Louis Bossart 
508d2f0daf6SPierre-Louis Bossart static int
intel_pdi_get_ch_cap(struct sdw_intel * sdw,unsigned int pdi_num)509d2f0daf6SPierre-Louis Bossart intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num)
510d2f0daf6SPierre-Louis Bossart {
511d2f0daf6SPierre-Louis Bossart 	void __iomem *shim = sdw->link_res->shim;
512d2f0daf6SPierre-Louis Bossart 
513d2f0daf6SPierre-Louis Bossart 	/* zero based values for channel count in register */
514d2f0daf6SPierre-Louis Bossart 	return intel_readw(shim, SDW_SHIM2_PCMSYCHC(pdi_num)) + 1;
515d2f0daf6SPierre-Louis Bossart }
516d2f0daf6SPierre-Louis Bossart 
intel_pdi_get_ch_update(struct sdw_intel * sdw,struct sdw_cdns_pdi * pdi,unsigned int num_pdi,unsigned int * num_ch)517d2f0daf6SPierre-Louis Bossart static void intel_pdi_get_ch_update(struct sdw_intel *sdw,
518d2f0daf6SPierre-Louis Bossart 				    struct sdw_cdns_pdi *pdi,
519d2f0daf6SPierre-Louis Bossart 				    unsigned int num_pdi,
520d2f0daf6SPierre-Louis Bossart 				    unsigned int *num_ch)
521d2f0daf6SPierre-Louis Bossart {
522d2f0daf6SPierre-Louis Bossart 	int ch_count = 0;
523d2f0daf6SPierre-Louis Bossart 	int i;
524d2f0daf6SPierre-Louis Bossart 
525d2f0daf6SPierre-Louis Bossart 	for (i = 0; i < num_pdi; i++) {
526d2f0daf6SPierre-Louis Bossart 		pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num);
527d2f0daf6SPierre-Louis Bossart 		ch_count += pdi->ch_count;
528d2f0daf6SPierre-Louis Bossart 		pdi++;
529d2f0daf6SPierre-Louis Bossart 	}
530d2f0daf6SPierre-Louis Bossart 
531d2f0daf6SPierre-Louis Bossart 	*num_ch = ch_count;
532d2f0daf6SPierre-Louis Bossart }
533d2f0daf6SPierre-Louis Bossart 
intel_pdi_stream_ch_update(struct sdw_intel * sdw,struct sdw_cdns_streams * stream)534d2f0daf6SPierre-Louis Bossart static void intel_pdi_stream_ch_update(struct sdw_intel *sdw,
535d2f0daf6SPierre-Louis Bossart 				       struct sdw_cdns_streams *stream)
536d2f0daf6SPierre-Louis Bossart {
537d2f0daf6SPierre-Louis Bossart 	intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd,
538d2f0daf6SPierre-Louis Bossart 				&stream->num_ch_bd);
539d2f0daf6SPierre-Louis Bossart 
540d2f0daf6SPierre-Louis Bossart 	intel_pdi_get_ch_update(sdw, stream->in, stream->num_in,
541d2f0daf6SPierre-Louis Bossart 				&stream->num_ch_in);
542d2f0daf6SPierre-Louis Bossart 
543d2f0daf6SPierre-Louis Bossart 	intel_pdi_get_ch_update(sdw, stream->out, stream->num_out,
544d2f0daf6SPierre-Louis Bossart 				&stream->num_ch_out);
545d2f0daf6SPierre-Louis Bossart }
546d2f0daf6SPierre-Louis Bossart 
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)547d2f0daf6SPierre-Louis Bossart static int intel_create_dai(struct sdw_cdns *cdns,
548d2f0daf6SPierre-Louis Bossart 			    struct snd_soc_dai_driver *dais,
549d2f0daf6SPierre-Louis Bossart 			    enum intel_pdi_type type,
550d2f0daf6SPierre-Louis Bossart 			    u32 num, u32 off, u32 max_ch)
551d2f0daf6SPierre-Louis Bossart {
552d2f0daf6SPierre-Louis Bossart 	int i;
553d2f0daf6SPierre-Louis Bossart 
554d2f0daf6SPierre-Louis Bossart 	if (!num)
555d2f0daf6SPierre-Louis Bossart 		return 0;
556d2f0daf6SPierre-Louis Bossart 
557d2f0daf6SPierre-Louis Bossart 	for (i = off; i < (off + num); i++) {
558d2f0daf6SPierre-Louis Bossart 		dais[i].name = devm_kasprintf(cdns->dev, GFP_KERNEL,
559d2f0daf6SPierre-Louis Bossart 					      "SDW%d Pin%d",
560d2f0daf6SPierre-Louis Bossart 					      cdns->instance, i);
561d2f0daf6SPierre-Louis Bossart 		if (!dais[i].name)
562d2f0daf6SPierre-Louis Bossart 			return -ENOMEM;
563d2f0daf6SPierre-Louis Bossart 
564d2f0daf6SPierre-Louis Bossart 		if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) {
565d2f0daf6SPierre-Louis Bossart 			dais[i].playback.channels_min = 1;
566d2f0daf6SPierre-Louis Bossart 			dais[i].playback.channels_max = max_ch;
567d2f0daf6SPierre-Louis Bossart 		}
568d2f0daf6SPierre-Louis Bossart 
569d2f0daf6SPierre-Louis Bossart 		if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) {
570d2f0daf6SPierre-Louis Bossart 			dais[i].capture.channels_min = 1;
571d2f0daf6SPierre-Louis Bossart 			dais[i].capture.channels_max = max_ch;
572d2f0daf6SPierre-Louis Bossart 		}
573d2f0daf6SPierre-Louis Bossart 
574d2f0daf6SPierre-Louis Bossart 		dais[i].ops = &intel_pcm_dai_ops;
575d2f0daf6SPierre-Louis Bossart 	}
576d2f0daf6SPierre-Louis Bossart 
577d2f0daf6SPierre-Louis Bossart 	return 0;
578d2f0daf6SPierre-Louis Bossart }
579d2f0daf6SPierre-Louis Bossart 
intel_register_dai(struct sdw_intel * sdw)580d2f0daf6SPierre-Louis Bossart static int intel_register_dai(struct sdw_intel *sdw)
581d2f0daf6SPierre-Louis Bossart {
582d2f0daf6SPierre-Louis Bossart 	struct sdw_cdns_dai_runtime **dai_runtime_array;
583d2f0daf6SPierre-Louis Bossart 	struct sdw_cdns_stream_config config;
584d2f0daf6SPierre-Louis Bossart 	struct sdw_cdns *cdns = &sdw->cdns;
585d2f0daf6SPierre-Louis Bossart 	struct sdw_cdns_streams *stream;
586d2f0daf6SPierre-Louis Bossart 	struct snd_soc_dai_driver *dais;
587d2f0daf6SPierre-Louis Bossart 	int num_dai;
588d2f0daf6SPierre-Louis Bossart 	int ret;
589d2f0daf6SPierre-Louis Bossart 	int off = 0;
590d2f0daf6SPierre-Louis Bossart 
591d2f0daf6SPierre-Louis Bossart 	/* Read the PDI config and initialize cadence PDI */
592d2f0daf6SPierre-Louis Bossart 	intel_pdi_init(sdw, &config);
593d2f0daf6SPierre-Louis Bossart 	ret = sdw_cdns_pdi_init(cdns, config);
594d2f0daf6SPierre-Louis Bossart 	if (ret)
595d2f0daf6SPierre-Louis Bossart 		return ret;
596d2f0daf6SPierre-Louis Bossart 
597d2f0daf6SPierre-Louis Bossart 	intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm);
598d2f0daf6SPierre-Louis Bossart 
599d2f0daf6SPierre-Louis Bossart 	/* DAIs are created based on total number of PDIs supported */
600d2f0daf6SPierre-Louis Bossart 	num_dai = cdns->pcm.num_pdi;
601d2f0daf6SPierre-Louis Bossart 
602d2f0daf6SPierre-Louis Bossart 	dai_runtime_array = devm_kcalloc(cdns->dev, num_dai,
603d2f0daf6SPierre-Louis Bossart 					 sizeof(struct sdw_cdns_dai_runtime *),
604d2f0daf6SPierre-Louis Bossart 					 GFP_KERNEL);
605d2f0daf6SPierre-Louis Bossart 	if (!dai_runtime_array)
606d2f0daf6SPierre-Louis Bossart 		return -ENOMEM;
607d2f0daf6SPierre-Louis Bossart 	cdns->dai_runtime_array = dai_runtime_array;
608d2f0daf6SPierre-Louis Bossart 
609d2f0daf6SPierre-Louis Bossart 	dais = devm_kcalloc(cdns->dev, num_dai, sizeof(*dais), GFP_KERNEL);
610d2f0daf6SPierre-Louis Bossart 	if (!dais)
611d2f0daf6SPierre-Louis Bossart 		return -ENOMEM;
612d2f0daf6SPierre-Louis Bossart 
613d2f0daf6SPierre-Louis Bossart 	/* Create PCM DAIs */
614d2f0daf6SPierre-Louis Bossart 	stream = &cdns->pcm;
615d2f0daf6SPierre-Louis Bossart 
616d2f0daf6SPierre-Louis Bossart 	ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pcm.num_in,
617d2f0daf6SPierre-Louis Bossart 			       off, stream->num_ch_in);
618d2f0daf6SPierre-Louis Bossart 	if (ret)
619d2f0daf6SPierre-Louis Bossart 		return ret;
620d2f0daf6SPierre-Louis Bossart 
621d2f0daf6SPierre-Louis Bossart 	off += cdns->pcm.num_in;
622d2f0daf6SPierre-Louis Bossart 	ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pcm.num_out,
623d2f0daf6SPierre-Louis Bossart 			       off, stream->num_ch_out);
624d2f0daf6SPierre-Louis Bossart 	if (ret)
625d2f0daf6SPierre-Louis Bossart 		return ret;
626d2f0daf6SPierre-Louis Bossart 
627d2f0daf6SPierre-Louis Bossart 	off += cdns->pcm.num_out;
628d2f0daf6SPierre-Louis Bossart 	ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pcm.num_bd,
629d2f0daf6SPierre-Louis Bossart 			       off, stream->num_ch_bd);
630d2f0daf6SPierre-Louis Bossart 	if (ret)
631d2f0daf6SPierre-Louis Bossart 		return ret;
632d2f0daf6SPierre-Louis Bossart 
633d2f0daf6SPierre-Louis Bossart 	return devm_snd_soc_register_component(cdns->dev, &dai_component,
634d2f0daf6SPierre-Louis Bossart 					       dais, num_dai);
635d2f0daf6SPierre-Louis Bossart }
636d2f0daf6SPierre-Louis Bossart 
intel_program_sdi(struct sdw_intel * sdw,int dev_num)637bcf71917SPierre-Louis Bossart static void intel_program_sdi(struct sdw_intel *sdw, int dev_num)
638bcf71917SPierre-Louis Bossart {
639bcf71917SPierre-Louis Bossart 	int ret;
640bcf71917SPierre-Louis Bossart 
641bcf71917SPierre-Louis Bossart 	ret = hdac_bus_eml_sdw_set_lsdiid(sdw->link_res->hbus, sdw->instance, dev_num);
642bcf71917SPierre-Louis Bossart 	if (ret < 0)
643bcf71917SPierre-Louis Bossart 		dev_err(sdw->cdns.dev, "%s: could not set lsdiid for link %d %d\n",
644bcf71917SPierre-Louis Bossart 			__func__, sdw->instance, dev_num);
645bcf71917SPierre-Louis Bossart }
646bcf71917SPierre-Louis Bossart 
6476f23f4e2SPierre-Louis Bossart const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops = {
648312316d5SPierre-Louis Bossart 	.debugfs_init = intel_ace2x_debugfs_init,
649312316d5SPierre-Louis Bossart 	.debugfs_exit = intel_ace2x_debugfs_exit,
650806f5abdSPierre-Louis Bossart 
651d2f0daf6SPierre-Louis Bossart 	.register_dai = intel_register_dai,
652d2f0daf6SPierre-Louis Bossart 
653f90ba301SPierre-Louis Bossart 	.check_clock_stop = intel_check_clock_stop,
654f90ba301SPierre-Louis Bossart 	.start_bus = intel_start_bus,
655f90ba301SPierre-Louis Bossart 	.start_bus_after_reset = intel_start_bus_after_reset,
656f90ba301SPierre-Louis Bossart 	.start_bus_after_clock_stop = intel_start_bus_after_clock_stop,
657f90ba301SPierre-Louis Bossart 	.stop_bus = intel_stop_bus,
658f90ba301SPierre-Louis Bossart 
659806f5abdSPierre-Louis Bossart 	.link_power_up = intel_link_power_up,
660806f5abdSPierre-Louis Bossart 	.link_power_down = intel_link_power_down,
6614d1e2464SPierre-Louis Bossart 
662b8e39bc4SPierre-Louis Bossart 	.shim_check_wake = intel_shim_check_wake,
663b8e39bc4SPierre-Louis Bossart 	.shim_wake = intel_shim_wake,
664b8e39bc4SPierre-Louis Bossart 
66532c3aa85SPierre-Louis Bossart 	.pre_bank_switch = intel_pre_bank_switch,
66632c3aa85SPierre-Louis Bossart 	.post_bank_switch = intel_post_bank_switch,
66732c3aa85SPierre-Louis Bossart 
6684d1e2464SPierre-Louis Bossart 	.sync_arm = intel_sync_arm,
6694d1e2464SPierre-Louis Bossart 	.sync_go_unlocked = intel_sync_go_unlocked,
6704d1e2464SPierre-Louis Bossart 	.sync_go = intel_sync_go,
6717ba18639SPierre-Louis Bossart 	.sync_check_cmdsync_unlocked = intel_check_cmdsync_unlocked,
672bcf71917SPierre-Louis Bossart 
673bcf71917SPierre-Louis Bossart 	.program_sdi = intel_program_sdi,
6746f23f4e2SPierre-Louis Bossart };
6756f23f4e2SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_lnl_hw_ops, SOUNDWIRE_INTEL);
676806f5abdSPierre-Louis Bossart 
677806f5abdSPierre-Louis Bossart MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK);
678