xref: /openbmc/linux/sound/soc/sof/intel/hda-mlink.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
152f16103SPierre-Louis Bossart // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
252f16103SPierre-Louis Bossart //
352f16103SPierre-Louis Bossart // This file is provided under a dual BSD/GPLv2 license.  When using or
452f16103SPierre-Louis Bossart // redistributing this file, you may do so under either license.
552f16103SPierre-Louis Bossart //
652f16103SPierre-Louis Bossart // Copyright(c) 2022 Intel Corporation. All rights reserved.
752f16103SPierre-Louis Bossart //
852f16103SPierre-Louis Bossart 
952f16103SPierre-Louis Bossart /*
1052f16103SPierre-Louis Bossart  * Management of HDaudio multi-link (capabilities, power, coupling)
1152f16103SPierre-Louis Bossart  */
1252f16103SPierre-Louis Bossart 
1352f16103SPierre-Louis Bossart #include <sound/hdaudio_ext.h>
1452f16103SPierre-Louis Bossart #include <sound/hda_register.h>
1518227585SPierre-Louis Bossart #include <sound/hda-mlink.h>
1652f16103SPierre-Louis Bossart 
1717c9b6ecSPierre-Louis Bossart #include <linux/bitfield.h>
1852f16103SPierre-Louis Bossart #include <linux/module.h>
1952f16103SPierre-Louis Bossart 
2018227585SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_MLINK)
2152f16103SPierre-Louis Bossart 
227430dea4SPierre-Louis Bossart /* worst-case number of sublinks is used for sublink refcount array allocation only */
237430dea4SPierre-Louis Bossart #define HDAML_MAX_SUBLINKS (AZX_ML_LCTL_CPA_SHIFT - AZX_ML_LCTL_SPA_SHIFT)
247430dea4SPierre-Louis Bossart 
2517c9b6ecSPierre-Louis Bossart /**
2617c9b6ecSPierre-Louis Bossart  * struct hdac_ext2_link - HDAudio extended+alternate link
2717c9b6ecSPierre-Louis Bossart  *
2817c9b6ecSPierre-Louis Bossart  * @hext_link:		hdac_ext_link
2917c9b6ecSPierre-Louis Bossart  * @alt:		flag set for alternate extended links
3017c9b6ecSPierre-Louis Bossart  * @intc:		boolean for interrupt capable
3117c9b6ecSPierre-Louis Bossart  * @ofls:		boolean for offload support
3217c9b6ecSPierre-Louis Bossart  * @lss:		boolean for link synchronization capabilities
3317c9b6ecSPierre-Louis Bossart  * @slcount:		sublink count
3417c9b6ecSPierre-Louis Bossart  * @elid:		extended link ID (AZX_REG_ML_LEPTR_ID_ defines)
3517c9b6ecSPierre-Louis Bossart  * @elver:		extended link version
3617c9b6ecSPierre-Louis Bossart  * @leptr:		extended link pointer
3717c9b6ecSPierre-Louis Bossart  * @eml_lock:		mutual exclusion to access shared registers e.g. CPA/SPA bits
3817c9b6ecSPierre-Louis Bossart  * in LCTL register
397430dea4SPierre-Louis Bossart  * @sublink_ref_count:	array of refcounts, required to power-manage sublinks independently
4017c9b6ecSPierre-Louis Bossart  * @base_ptr:		pointer to shim/ip/shim_vs space
4117c9b6ecSPierre-Louis Bossart  * @instance_offset:	offset between each of @slcount instances managed by link
4217c9b6ecSPierre-Louis Bossart  * @shim_offset:	offset to SHIM register base
4317c9b6ecSPierre-Louis Bossart  * @ip_offset:		offset to IP register base
4417c9b6ecSPierre-Louis Bossart  * @shim_vs_offset:	offset to vendor-specific (VS) SHIM base
4517c9b6ecSPierre-Louis Bossart  */
4617c9b6ecSPierre-Louis Bossart struct hdac_ext2_link {
4717c9b6ecSPierre-Louis Bossart 	struct hdac_ext_link hext_link;
4817c9b6ecSPierre-Louis Bossart 
4917c9b6ecSPierre-Louis Bossart 	/* read directly from LCAP register */
5017c9b6ecSPierre-Louis Bossart 	bool alt;
5117c9b6ecSPierre-Louis Bossart 	bool intc;
5217c9b6ecSPierre-Louis Bossart 	bool ofls;
5317c9b6ecSPierre-Louis Bossart 	bool lss;
5417c9b6ecSPierre-Louis Bossart 	int slcount;
5517c9b6ecSPierre-Louis Bossart 	int elid;
5617c9b6ecSPierre-Louis Bossart 	int elver;
5717c9b6ecSPierre-Louis Bossart 	u32 leptr;
5817c9b6ecSPierre-Louis Bossart 
5917c9b6ecSPierre-Louis Bossart 	struct mutex eml_lock; /* prevent concurrent access to e.g. CPA/SPA */
607430dea4SPierre-Louis Bossart 	int sublink_ref_count[HDAML_MAX_SUBLINKS];
6117c9b6ecSPierre-Louis Bossart 
6217c9b6ecSPierre-Louis Bossart 	/* internal values computed from LCAP contents */
6317c9b6ecSPierre-Louis Bossart 	void __iomem *base_ptr;
6417c9b6ecSPierre-Louis Bossart 	u32 instance_offset;
6517c9b6ecSPierre-Louis Bossart 	u32 shim_offset;
6617c9b6ecSPierre-Louis Bossart 	u32 ip_offset;
6717c9b6ecSPierre-Louis Bossart 	u32 shim_vs_offset;
6817c9b6ecSPierre-Louis Bossart };
6917c9b6ecSPierre-Louis Bossart 
7017c9b6ecSPierre-Louis Bossart #define hdac_ext_link_to_ext2(h) container_of(h, struct hdac_ext2_link, hext_link)
7117c9b6ecSPierre-Louis Bossart 
7217c9b6ecSPierre-Louis Bossart #define AZX_REG_SDW_INSTANCE_OFFSET			0x8000
7317c9b6ecSPierre-Louis Bossart #define AZX_REG_SDW_SHIM_OFFSET				0x0
7417c9b6ecSPierre-Louis Bossart #define AZX_REG_SDW_IP_OFFSET				0x100
7517c9b6ecSPierre-Louis Bossart #define AZX_REG_SDW_VS_SHIM_OFFSET			0x6000
76ccc2f0c1SPierre-Louis Bossart #define AZX_REG_SDW_SHIM_PCMSyCM(y)			(0x16 + 0x4 * (y))
7717c9b6ecSPierre-Louis Bossart 
7817c9b6ecSPierre-Louis Bossart /* only one instance supported */
7917c9b6ecSPierre-Louis Bossart #define AZX_REG_INTEL_DMIC_SHIM_OFFSET			0x0
8017c9b6ecSPierre-Louis Bossart #define AZX_REG_INTEL_DMIC_IP_OFFSET			0x100
8117c9b6ecSPierre-Louis Bossart #define AZX_REG_INTEL_DMIC_VS_SHIM_OFFSET		0x6000
8217c9b6ecSPierre-Louis Bossart 
8317c9b6ecSPierre-Louis Bossart #define AZX_REG_INTEL_SSP_INSTANCE_OFFSET		0x1000
8417c9b6ecSPierre-Louis Bossart #define AZX_REG_INTEL_SSP_SHIM_OFFSET			0x0
8517c9b6ecSPierre-Louis Bossart #define AZX_REG_INTEL_SSP_IP_OFFSET			0x100
8617c9b6ecSPierre-Louis Bossart #define AZX_REG_INTEL_SSP_VS_SHIM_OFFSET		0xC00
8717c9b6ecSPierre-Louis Bossart 
8817c9b6ecSPierre-Louis Bossart /* only one instance supported */
8917c9b6ecSPierre-Louis Bossart #define AZX_REG_INTEL_UAOL_SHIM_OFFSET			0x0
9017c9b6ecSPierre-Louis Bossart #define AZX_REG_INTEL_UAOL_IP_OFFSET			0x100
9117c9b6ecSPierre-Louis Bossart #define AZX_REG_INTEL_UAOL_VS_SHIM_OFFSET		0xC00
9217c9b6ecSPierre-Louis Bossart 
9317c9b6ecSPierre-Louis Bossart /* HDAML section - this part follows sequences in the hardware specification,
9417c9b6ecSPierre-Louis Bossart  * including naming conventions and the use of the hdaml_ prefix.
9517c9b6ecSPierre-Louis Bossart  * The code is intentionally minimal with limited dependencies on frameworks or
9617c9b6ecSPierre-Louis Bossart  * helpers. Locking and scanning lists is handled at a higher level
9717c9b6ecSPierre-Louis Bossart  */
9817c9b6ecSPierre-Louis Bossart 
hdaml_lnk_enum(struct device * dev,struct hdac_ext2_link * h2link,void __iomem * remap_addr,void __iomem * ml_addr,int link_idx)9917c9b6ecSPierre-Louis Bossart static int hdaml_lnk_enum(struct device *dev, struct hdac_ext2_link *h2link,
100af8c32b1SPierre-Louis Bossart 			  void __iomem *remap_addr, void __iomem *ml_addr, int link_idx)
10152f16103SPierre-Louis Bossart {
10217c9b6ecSPierre-Louis Bossart 	struct hdac_ext_link *hlink = &h2link->hext_link;
10317c9b6ecSPierre-Louis Bossart 	u32 base_offset;
10417c9b6ecSPierre-Louis Bossart 
10517c9b6ecSPierre-Louis Bossart 	hlink->lcaps  = readl(ml_addr + AZX_REG_ML_LCAP);
10617c9b6ecSPierre-Louis Bossart 
10717c9b6ecSPierre-Louis Bossart 	h2link->alt = FIELD_GET(AZX_ML_HDA_LCAP_ALT, hlink->lcaps);
10817c9b6ecSPierre-Louis Bossart 
10917c9b6ecSPierre-Louis Bossart 	/* handle alternate extensions */
11017c9b6ecSPierre-Louis Bossart 	if (!h2link->alt) {
11117c9b6ecSPierre-Louis Bossart 		h2link->slcount = 1;
11217c9b6ecSPierre-Louis Bossart 
11317c9b6ecSPierre-Louis Bossart 		/*
11417c9b6ecSPierre-Louis Bossart 		 * LSDIID is initialized by hardware for HDaudio link,
11517c9b6ecSPierre-Louis Bossart 		 * it needs to be setup by software for alternate links
11617c9b6ecSPierre-Louis Bossart 		 */
11717c9b6ecSPierre-Louis Bossart 		hlink->lsdiid = readw(ml_addr + AZX_REG_ML_LSDIID);
11817c9b6ecSPierre-Louis Bossart 
11917c9b6ecSPierre-Louis Bossart 		dev_dbg(dev, "Link %d: HDAudio - lsdiid=%d\n",
12017c9b6ecSPierre-Louis Bossart 			link_idx, hlink->lsdiid);
12117c9b6ecSPierre-Louis Bossart 
12268376a3eSPierre-Louis Bossart 		return 0;
12352f16103SPierre-Louis Bossart 	}
12417c9b6ecSPierre-Louis Bossart 
12517c9b6ecSPierre-Louis Bossart 	h2link->intc = FIELD_GET(AZX_ML_HDA_LCAP_INTC, hlink->lcaps);
12617c9b6ecSPierre-Louis Bossart 	h2link->ofls = FIELD_GET(AZX_ML_HDA_LCAP_OFLS, hlink->lcaps);
12717c9b6ecSPierre-Louis Bossart 	h2link->lss = FIELD_GET(AZX_ML_HDA_LCAP_LSS, hlink->lcaps);
12817c9b6ecSPierre-Louis Bossart 
12917c9b6ecSPierre-Louis Bossart 	/* read slcount (increment due to zero-based hardware representation */
13017c9b6ecSPierre-Louis Bossart 	h2link->slcount = FIELD_GET(AZX_ML_HDA_LCAP_SLCOUNT, hlink->lcaps) + 1;
13117c9b6ecSPierre-Louis Bossart 	dev_dbg(dev, "Link %d: HDAudio extended - sublink count %d\n",
13217c9b6ecSPierre-Louis Bossart 		link_idx, h2link->slcount);
13317c9b6ecSPierre-Louis Bossart 
13417c9b6ecSPierre-Louis Bossart 	/* find IP ID and offsets */
1357dfd1ccdSPierre-Louis Bossart 	h2link->leptr = readl(ml_addr + AZX_REG_ML_LEPTR);
13617c9b6ecSPierre-Louis Bossart 
13717c9b6ecSPierre-Louis Bossart 	h2link->elid = FIELD_GET(AZX_REG_ML_LEPTR_ID, h2link->leptr);
13817c9b6ecSPierre-Louis Bossart 
13917c9b6ecSPierre-Louis Bossart 	base_offset = FIELD_GET(AZX_REG_ML_LEPTR_PTR, h2link->leptr);
140af8c32b1SPierre-Louis Bossart 	h2link->base_ptr = remap_addr + base_offset;
14117c9b6ecSPierre-Louis Bossart 
14217c9b6ecSPierre-Louis Bossart 	switch (h2link->elid) {
14317c9b6ecSPierre-Louis Bossart 	case AZX_REG_ML_LEPTR_ID_SDW:
1449643456eSPierre-Louis Bossart 		h2link->instance_offset = AZX_REG_SDW_INSTANCE_OFFSET;
14517c9b6ecSPierre-Louis Bossart 		h2link->shim_offset = AZX_REG_SDW_SHIM_OFFSET;
14617c9b6ecSPierre-Louis Bossart 		h2link->ip_offset = AZX_REG_SDW_IP_OFFSET;
14717c9b6ecSPierre-Louis Bossart 		h2link->shim_vs_offset = AZX_REG_SDW_VS_SHIM_OFFSET;
14817c9b6ecSPierre-Louis Bossart 		dev_dbg(dev, "Link %d: HDAudio extended - SoundWire alternate link, leptr.ptr %#x\n",
14917c9b6ecSPierre-Louis Bossart 			link_idx, base_offset);
15017c9b6ecSPierre-Louis Bossart 		break;
15117c9b6ecSPierre-Louis Bossart 	case AZX_REG_ML_LEPTR_ID_INTEL_DMIC:
15217c9b6ecSPierre-Louis Bossart 		h2link->shim_offset = AZX_REG_INTEL_DMIC_SHIM_OFFSET;
15317c9b6ecSPierre-Louis Bossart 		h2link->ip_offset = AZX_REG_INTEL_DMIC_IP_OFFSET;
15417c9b6ecSPierre-Louis Bossart 		h2link->shim_vs_offset = AZX_REG_INTEL_DMIC_VS_SHIM_OFFSET;
15517c9b6ecSPierre-Louis Bossart 		dev_dbg(dev, "Link %d: HDAudio extended - INTEL DMIC alternate link, leptr.ptr %#x\n",
15617c9b6ecSPierre-Louis Bossart 			link_idx, base_offset);
15717c9b6ecSPierre-Louis Bossart 		break;
15817c9b6ecSPierre-Louis Bossart 	case AZX_REG_ML_LEPTR_ID_INTEL_SSP:
1599643456eSPierre-Louis Bossart 		h2link->instance_offset = AZX_REG_INTEL_SSP_INSTANCE_OFFSET;
16017c9b6ecSPierre-Louis Bossart 		h2link->shim_offset = AZX_REG_INTEL_SSP_SHIM_OFFSET;
16117c9b6ecSPierre-Louis Bossart 		h2link->ip_offset = AZX_REG_INTEL_SSP_IP_OFFSET;
16217c9b6ecSPierre-Louis Bossart 		h2link->shim_vs_offset = AZX_REG_INTEL_SSP_VS_SHIM_OFFSET;
16317c9b6ecSPierre-Louis Bossart 		dev_dbg(dev, "Link %d: HDAudio extended - INTEL SSP alternate link, leptr.ptr %#x\n",
16417c9b6ecSPierre-Louis Bossart 			link_idx, base_offset);
16517c9b6ecSPierre-Louis Bossart 		break;
16617c9b6ecSPierre-Louis Bossart 	case AZX_REG_ML_LEPTR_ID_INTEL_UAOL:
16717c9b6ecSPierre-Louis Bossart 		h2link->shim_offset = AZX_REG_INTEL_UAOL_SHIM_OFFSET;
16817c9b6ecSPierre-Louis Bossart 		h2link->ip_offset = AZX_REG_INTEL_UAOL_IP_OFFSET;
16917c9b6ecSPierre-Louis Bossart 		h2link->shim_vs_offset = AZX_REG_INTEL_UAOL_VS_SHIM_OFFSET;
17017c9b6ecSPierre-Louis Bossart 		dev_dbg(dev, "Link %d: HDAudio extended - INTEL UAOL alternate link, leptr.ptr %#x\n",
17117c9b6ecSPierre-Louis Bossart 			link_idx, base_offset);
17217c9b6ecSPierre-Louis Bossart 		break;
17317c9b6ecSPierre-Louis Bossart 	default:
17417c9b6ecSPierre-Louis Bossart 		dev_err(dev, "Link %d: HDAudio extended - Unsupported alternate link, leptr.id=%#02x value\n",
17517c9b6ecSPierre-Louis Bossart 			link_idx, h2link->elid);
17617c9b6ecSPierre-Louis Bossart 		return -EINVAL;
17717c9b6ecSPierre-Louis Bossart 	}
17817c9b6ecSPierre-Louis Bossart 	return 0;
17917c9b6ecSPierre-Louis Bossart }
18017c9b6ecSPierre-Louis Bossart 
181fc7dab8eSPierre-Louis Bossart /*
182fc7dab8eSPierre-Louis Bossart  * Hardware recommendations are to wait ~10us before checking any hardware transition
183fc7dab8eSPierre-Louis Bossart  * reported by bits changing status.
184fc7dab8eSPierre-Louis Bossart  * This value does not need to be super-precise, a slack of 5us is perfectly acceptable.
185fc7dab8eSPierre-Louis Bossart  * The worst-case is about 1ms before reporting an issue
186fc7dab8eSPierre-Louis Bossart  */
187fc7dab8eSPierre-Louis Bossart #define HDAML_POLL_DELAY_MIN_US 10
188fc7dab8eSPierre-Louis Bossart #define HDAML_POLL_DELAY_SLACK_US 5
189fc7dab8eSPierre-Louis Bossart #define HDAML_POLL_DELAY_RETRY  100
190fc7dab8eSPierre-Louis Bossart 
check_sublink_power(u32 __iomem * lctl,int sublink,bool enabled)191fc7dab8eSPierre-Louis Bossart static int check_sublink_power(u32 __iomem *lctl, int sublink, bool enabled)
192fc7dab8eSPierre-Louis Bossart {
193fc7dab8eSPierre-Louis Bossart 	int mask = BIT(sublink) << AZX_ML_LCTL_CPA_SHIFT;
194fc7dab8eSPierre-Louis Bossart 	int retry = HDAML_POLL_DELAY_RETRY;
195fc7dab8eSPierre-Louis Bossart 	u32 val;
196fc7dab8eSPierre-Louis Bossart 
197fc7dab8eSPierre-Louis Bossart 	usleep_range(HDAML_POLL_DELAY_MIN_US,
198fc7dab8eSPierre-Louis Bossart 		     HDAML_POLL_DELAY_MIN_US + HDAML_POLL_DELAY_SLACK_US);
199fc7dab8eSPierre-Louis Bossart 	do {
200fc7dab8eSPierre-Louis Bossart 		val = readl(lctl);
201fc7dab8eSPierre-Louis Bossart 		if (enabled) {
202fc7dab8eSPierre-Louis Bossart 			if (val & mask)
203fc7dab8eSPierre-Louis Bossart 				return 0;
204fc7dab8eSPierre-Louis Bossart 		} else {
205fc7dab8eSPierre-Louis Bossart 			if (!(val & mask))
206fc7dab8eSPierre-Louis Bossart 				return 0;
207fc7dab8eSPierre-Louis Bossart 		}
208fc7dab8eSPierre-Louis Bossart 		usleep_range(HDAML_POLL_DELAY_MIN_US,
209fc7dab8eSPierre-Louis Bossart 			     HDAML_POLL_DELAY_MIN_US + HDAML_POLL_DELAY_SLACK_US);
210fc7dab8eSPierre-Louis Bossart 
211fc7dab8eSPierre-Louis Bossart 	} while (--retry);
212fc7dab8eSPierre-Louis Bossart 
213fc7dab8eSPierre-Louis Bossart 	return -EIO;
214fc7dab8eSPierre-Louis Bossart }
215fc7dab8eSPierre-Louis Bossart 
hdaml_link_init(u32 __iomem * lctl,int sublink)216fc7dab8eSPierre-Louis Bossart static int hdaml_link_init(u32 __iomem *lctl, int sublink)
217fc7dab8eSPierre-Louis Bossart {
218fc7dab8eSPierre-Louis Bossart 	u32 val;
219fc7dab8eSPierre-Louis Bossart 	u32 mask = BIT(sublink) << AZX_ML_LCTL_SPA_SHIFT;
220fc7dab8eSPierre-Louis Bossart 
221fc7dab8eSPierre-Louis Bossart 	val = readl(lctl);
222fc7dab8eSPierre-Louis Bossart 	val |= mask;
223fc7dab8eSPierre-Louis Bossart 
224fc7dab8eSPierre-Louis Bossart 	writel(val, lctl);
225fc7dab8eSPierre-Louis Bossart 
226fc7dab8eSPierre-Louis Bossart 	return check_sublink_power(lctl, sublink, true);
227fc7dab8eSPierre-Louis Bossart }
228fc7dab8eSPierre-Louis Bossart 
hdaml_link_shutdown(u32 __iomem * lctl,int sublink)229fc7dab8eSPierre-Louis Bossart static int hdaml_link_shutdown(u32 __iomem *lctl, int sublink)
230fc7dab8eSPierre-Louis Bossart {
231fc7dab8eSPierre-Louis Bossart 	u32 val;
232fc7dab8eSPierre-Louis Bossart 	u32 mask;
233fc7dab8eSPierre-Louis Bossart 
234fc7dab8eSPierre-Louis Bossart 	val = readl(lctl);
235fc7dab8eSPierre-Louis Bossart 	mask = BIT(sublink) << AZX_ML_LCTL_SPA_SHIFT;
236fc7dab8eSPierre-Louis Bossart 	val &= ~mask;
237fc7dab8eSPierre-Louis Bossart 
238fc7dab8eSPierre-Louis Bossart 	writel(val, lctl);
239fc7dab8eSPierre-Louis Bossart 
240fc7dab8eSPierre-Louis Bossart 	return check_sublink_power(lctl, sublink, false);
241fc7dab8eSPierre-Louis Bossart }
242fc7dab8eSPierre-Louis Bossart 
hdaml_link_enable_interrupt(u32 __iomem * lctl,bool enable)2432e428831SPierre-Louis Bossart static void hdaml_link_enable_interrupt(u32 __iomem *lctl, bool enable)
2442e428831SPierre-Louis Bossart {
2452e428831SPierre-Louis Bossart 	u32 val;
2462e428831SPierre-Louis Bossart 
2472e428831SPierre-Louis Bossart 	val = readl(lctl);
2482e428831SPierre-Louis Bossart 	if (enable)
2492e428831SPierre-Louis Bossart 		val |= AZX_ML_LCTL_INTEN;
2502e428831SPierre-Louis Bossart 	else
2512e428831SPierre-Louis Bossart 		val &= ~AZX_ML_LCTL_INTEN;
2522e428831SPierre-Louis Bossart 
2532e428831SPierre-Louis Bossart 	writel(val, lctl);
2542e428831SPierre-Louis Bossart }
2552e428831SPierre-Louis Bossart 
hdaml_link_check_interrupt(u32 __iomem * lctl)2562e428831SPierre-Louis Bossart static bool hdaml_link_check_interrupt(u32 __iomem *lctl)
2572e428831SPierre-Louis Bossart {
2582e428831SPierre-Louis Bossart 	u32 val;
2592e428831SPierre-Louis Bossart 
2602e428831SPierre-Louis Bossart 	val = readl(lctl);
2612e428831SPierre-Louis Bossart 
2622e428831SPierre-Louis Bossart 	return val & AZX_ML_LCTL_INTSTS;
2632e428831SPierre-Louis Bossart }
2642e428831SPierre-Louis Bossart 
hdaml_wait_bit(void __iomem * base,int offset,u32 mask,u32 target)26502ba1b02SPierre-Louis Bossart static int hdaml_wait_bit(void __iomem *base, int offset, u32 mask, u32 target)
26602ba1b02SPierre-Louis Bossart {
26702ba1b02SPierre-Louis Bossart 	int timeout = HDAML_POLL_DELAY_RETRY;
26802ba1b02SPierre-Louis Bossart 	u32 reg_read;
26902ba1b02SPierre-Louis Bossart 
27002ba1b02SPierre-Louis Bossart 	do {
27102ba1b02SPierre-Louis Bossart 		reg_read = readl(base + offset);
27202ba1b02SPierre-Louis Bossart 		if ((reg_read & mask) == target)
27302ba1b02SPierre-Louis Bossart 			return 0;
27402ba1b02SPierre-Louis Bossart 
27502ba1b02SPierre-Louis Bossart 		timeout--;
27602ba1b02SPierre-Louis Bossart 		usleep_range(HDAML_POLL_DELAY_MIN_US,
27702ba1b02SPierre-Louis Bossart 			     HDAML_POLL_DELAY_MIN_US + HDAML_POLL_DELAY_SLACK_US);
27802ba1b02SPierre-Louis Bossart 	} while (timeout != 0);
27902ba1b02SPierre-Louis Bossart 
28002ba1b02SPierre-Louis Bossart 	return -EAGAIN;
28102ba1b02SPierre-Louis Bossart }
28202ba1b02SPierre-Louis Bossart 
hdaml_link_set_syncprd(u32 __iomem * lsync,u32 syncprd)28302ba1b02SPierre-Louis Bossart static void hdaml_link_set_syncprd(u32 __iomem *lsync, u32 syncprd)
28402ba1b02SPierre-Louis Bossart {
28502ba1b02SPierre-Louis Bossart 	u32 val;
28602ba1b02SPierre-Louis Bossart 
28702ba1b02SPierre-Louis Bossart 	val = readl(lsync);
28802ba1b02SPierre-Louis Bossart 	val &= ~AZX_REG_ML_LSYNC_SYNCPRD;
28902ba1b02SPierre-Louis Bossart 	val |= (syncprd & AZX_REG_ML_LSYNC_SYNCPRD);
29002ba1b02SPierre-Louis Bossart 
29102ba1b02SPierre-Louis Bossart 	/*
29202ba1b02SPierre-Louis Bossart 	 * set SYNCPU but do not wait. The bit is cleared by hardware when
29302ba1b02SPierre-Louis Bossart 	 * the link becomes active.
29402ba1b02SPierre-Louis Bossart 	 */
29502ba1b02SPierre-Louis Bossart 	val |= AZX_REG_ML_LSYNC_SYNCPU;
29602ba1b02SPierre-Louis Bossart 
29702ba1b02SPierre-Louis Bossart 	writel(val, lsync);
29802ba1b02SPierre-Louis Bossart }
29902ba1b02SPierre-Louis Bossart 
hdaml_link_wait_syncpu(u32 __iomem * lsync)30002ba1b02SPierre-Louis Bossart static int hdaml_link_wait_syncpu(u32 __iomem *lsync)
30102ba1b02SPierre-Louis Bossart {
30202ba1b02SPierre-Louis Bossart 	return hdaml_wait_bit(lsync, 0, AZX_REG_ML_LSYNC_SYNCPU, 0);
30302ba1b02SPierre-Louis Bossart }
30402ba1b02SPierre-Louis Bossart 
hdaml_link_sync_arm(u32 __iomem * lsync,int sublink)3051f5a6e8bSPierre-Louis Bossart static void hdaml_link_sync_arm(u32 __iomem *lsync, int sublink)
3061f5a6e8bSPierre-Louis Bossart {
3071f5a6e8bSPierre-Louis Bossart 	u32 val;
3081f5a6e8bSPierre-Louis Bossart 
3091f5a6e8bSPierre-Louis Bossart 	val = readl(lsync);
3101f5a6e8bSPierre-Louis Bossart 	val |= (AZX_REG_ML_LSYNC_CMDSYNC << sublink);
3111f5a6e8bSPierre-Louis Bossart 
3121f5a6e8bSPierre-Louis Bossart 	writel(val, lsync);
3131f5a6e8bSPierre-Louis Bossart }
3141f5a6e8bSPierre-Louis Bossart 
hdaml_link_sync_go(u32 __iomem * lsync)3151f5a6e8bSPierre-Louis Bossart static void hdaml_link_sync_go(u32 __iomem *lsync)
3161f5a6e8bSPierre-Louis Bossart {
3171f5a6e8bSPierre-Louis Bossart 	u32 val;
3181f5a6e8bSPierre-Louis Bossart 
3191f5a6e8bSPierre-Louis Bossart 	val = readl(lsync);
3201f5a6e8bSPierre-Louis Bossart 	val |= AZX_REG_ML_LSYNC_SYNCGO;
3211f5a6e8bSPierre-Louis Bossart 
3221f5a6e8bSPierre-Louis Bossart 	writel(val, lsync);
3231f5a6e8bSPierre-Louis Bossart }
3241f5a6e8bSPierre-Louis Bossart 
hdaml_link_check_cmdsync(u32 __iomem * lsync,u32 cmdsync_mask)325d56d2058SPierre-Louis Bossart static bool hdaml_link_check_cmdsync(u32 __iomem *lsync, u32 cmdsync_mask)
326d56d2058SPierre-Louis Bossart {
327d56d2058SPierre-Louis Bossart 	u32 val;
328d56d2058SPierre-Louis Bossart 
329d56d2058SPierre-Louis Bossart 	val = readl(lsync);
330d56d2058SPierre-Louis Bossart 
331d56d2058SPierre-Louis Bossart 	return !!(val & cmdsync_mask);
332d56d2058SPierre-Louis Bossart }
333d56d2058SPierre-Louis Bossart 
hdaml_link_get_lsdiid(u16 __iomem * lsdiid)33434e38f03SPierre-Louis Bossart static u16 hdaml_link_get_lsdiid(u16 __iomem *lsdiid)
33534e38f03SPierre-Louis Bossart {
33634e38f03SPierre-Louis Bossart 	return readw(lsdiid);
33734e38f03SPierre-Louis Bossart }
33834e38f03SPierre-Louis Bossart 
hdaml_link_set_lsdiid(u16 __iomem * lsdiid,int dev_num)3397a52d706SPierre-Louis Bossart static void hdaml_link_set_lsdiid(u16 __iomem *lsdiid, int dev_num)
34087a6ddc0SPierre-Louis Bossart {
3417a52d706SPierre-Louis Bossart 	u16 val;
34287a6ddc0SPierre-Louis Bossart 
3437a52d706SPierre-Louis Bossart 	val = readw(lsdiid);
34487a6ddc0SPierre-Louis Bossart 	val |= BIT(dev_num);
34587a6ddc0SPierre-Louis Bossart 
3467a52d706SPierre-Louis Bossart 	writew(val, lsdiid);
34787a6ddc0SPierre-Louis Bossart }
34887a6ddc0SPierre-Louis Bossart 
hdaml_shim_map_stream_ch(u16 __iomem * pcmsycm,int lchan,int hchan,int stream_id,int dir)349ccc2f0c1SPierre-Louis Bossart static void hdaml_shim_map_stream_ch(u16 __iomem *pcmsycm, int lchan, int hchan,
350ccc2f0c1SPierre-Louis Bossart 				     int stream_id, int dir)
351ccc2f0c1SPierre-Louis Bossart {
352ccc2f0c1SPierre-Louis Bossart 	u16 val;
353ccc2f0c1SPierre-Louis Bossart 
354ccc2f0c1SPierre-Louis Bossart 	val = readw(pcmsycm);
355ccc2f0c1SPierre-Louis Bossart 
356ccc2f0c1SPierre-Louis Bossart 	u16p_replace_bits(&val, lchan, GENMASK(3, 0));
357ccc2f0c1SPierre-Louis Bossart 	u16p_replace_bits(&val, hchan, GENMASK(7, 4));
358ccc2f0c1SPierre-Louis Bossart 	u16p_replace_bits(&val, stream_id, GENMASK(13, 8));
359ccc2f0c1SPierre-Louis Bossart 	u16p_replace_bits(&val, dir, BIT(15));
360ccc2f0c1SPierre-Louis Bossart 
361ccc2f0c1SPierre-Louis Bossart 	writew(val, pcmsycm);
362ccc2f0c1SPierre-Louis Bossart }
363ccc2f0c1SPierre-Louis Bossart 
hdaml_lctl_offload_enable(u32 __iomem * lctl,bool enable)36482958c40SPierre-Louis Bossart static void hdaml_lctl_offload_enable(u32 __iomem *lctl, bool enable)
36582958c40SPierre-Louis Bossart {
36682958c40SPierre-Louis Bossart 	u32 val = readl(lctl);
36782958c40SPierre-Louis Bossart 
36882958c40SPierre-Louis Bossart 	if (enable)
36982958c40SPierre-Louis Bossart 		val |=  AZX_ML_LCTL_OFLEN;
37082958c40SPierre-Louis Bossart 	else
37182958c40SPierre-Louis Bossart 		val &=  ~AZX_ML_LCTL_OFLEN;
37282958c40SPierre-Louis Bossart 
37382958c40SPierre-Louis Bossart 	writel(val, lctl);
37482958c40SPierre-Louis Bossart }
37582958c40SPierre-Louis Bossart 
37617c9b6ecSPierre-Louis Bossart /* END HDAML section */
37717c9b6ecSPierre-Louis Bossart 
hda_ml_alloc_h2link(struct hdac_bus * bus,int index)37817c9b6ecSPierre-Louis Bossart static int hda_ml_alloc_h2link(struct hdac_bus *bus, int index)
37917c9b6ecSPierre-Louis Bossart {
38017c9b6ecSPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
38117c9b6ecSPierre-Louis Bossart 	struct hdac_ext_link *hlink;
38217c9b6ecSPierre-Louis Bossart 	int ret;
38317c9b6ecSPierre-Louis Bossart 
38417c9b6ecSPierre-Louis Bossart 	h2link  = kzalloc(sizeof(*h2link), GFP_KERNEL);
38517c9b6ecSPierre-Louis Bossart 	if (!h2link)
38617c9b6ecSPierre-Louis Bossart 		return -ENOMEM;
38717c9b6ecSPierre-Louis Bossart 
38817c9b6ecSPierre-Louis Bossart 	/* basic initialization */
38917c9b6ecSPierre-Louis Bossart 	hlink = &h2link->hext_link;
39017c9b6ecSPierre-Louis Bossart 
39117c9b6ecSPierre-Louis Bossart 	hlink->index = index;
39217c9b6ecSPierre-Louis Bossart 	hlink->bus = bus;
39317c9b6ecSPierre-Louis Bossart 	hlink->ml_addr = bus->mlcap + AZX_ML_BASE + (AZX_ML_INTERVAL * index);
39417c9b6ecSPierre-Louis Bossart 
395af8c32b1SPierre-Louis Bossart 	ret = hdaml_lnk_enum(bus->dev, h2link, bus->remap_addr, hlink->ml_addr, index);
39617c9b6ecSPierre-Louis Bossart 	if (ret < 0) {
39717c9b6ecSPierre-Louis Bossart 		kfree(h2link);
39817c9b6ecSPierre-Louis Bossart 		return ret;
39917c9b6ecSPierre-Louis Bossart 	}
40017c9b6ecSPierre-Louis Bossart 
40117c9b6ecSPierre-Louis Bossart 	mutex_init(&h2link->eml_lock);
40217c9b6ecSPierre-Louis Bossart 
40317c9b6ecSPierre-Louis Bossart 	list_add_tail(&hlink->list, &bus->hlink_list);
40417c9b6ecSPierre-Louis Bossart 
40517c9b6ecSPierre-Louis Bossart 	/*
40617c9b6ecSPierre-Louis Bossart 	 * HDaudio regular links are powered-on by default, the
40717c9b6ecSPierre-Louis Bossart 	 * refcount needs to be initialized.
40817c9b6ecSPierre-Louis Bossart 	 */
40917c9b6ecSPierre-Louis Bossart 	if (!h2link->alt)
41017c9b6ecSPierre-Louis Bossart 		hlink->ref_count = 1;
41117c9b6ecSPierre-Louis Bossart 
41217c9b6ecSPierre-Louis Bossart 	return 0;
41317c9b6ecSPierre-Louis Bossart }
41417c9b6ecSPierre-Louis Bossart 
hda_bus_ml_init(struct hdac_bus * bus)41517c9b6ecSPierre-Louis Bossart int hda_bus_ml_init(struct hdac_bus *bus)
41617c9b6ecSPierre-Louis Bossart {
41717c9b6ecSPierre-Louis Bossart 	u32 link_count;
41817c9b6ecSPierre-Louis Bossart 	int ret;
41917c9b6ecSPierre-Louis Bossart 	int i;
42017c9b6ecSPierre-Louis Bossart 
42117c9b6ecSPierre-Louis Bossart 	if (!bus->mlcap)
42217c9b6ecSPierre-Louis Bossart 		return 0;
42317c9b6ecSPierre-Louis Bossart 
42417c9b6ecSPierre-Louis Bossart 	link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1;
42517c9b6ecSPierre-Louis Bossart 
42617c9b6ecSPierre-Louis Bossart 	dev_dbg(bus->dev, "HDAudio Multi-Link count: %d\n", link_count);
42717c9b6ecSPierre-Louis Bossart 
42817c9b6ecSPierre-Louis Bossart 	for (i = 0; i < link_count; i++) {
42917c9b6ecSPierre-Louis Bossart 		ret = hda_ml_alloc_h2link(bus, i);
43017c9b6ecSPierre-Louis Bossart 		if (ret < 0) {
43117c9b6ecSPierre-Louis Bossart 			hda_bus_ml_free(bus);
43217c9b6ecSPierre-Louis Bossart 			return ret;
43317c9b6ecSPierre-Louis Bossart 		}
43417c9b6ecSPierre-Louis Bossart 	}
43517c9b6ecSPierre-Louis Bossart 	return 0;
43617c9b6ecSPierre-Louis Bossart }
43717c9b6ecSPierre-Louis Bossart EXPORT_SYMBOL_NS(hda_bus_ml_init, SND_SOC_SOF_HDA_MLINK);
43852f16103SPierre-Louis Bossart 
hda_bus_ml_free(struct hdac_bus * bus)43902785b89SPierre-Louis Bossart void hda_bus_ml_free(struct hdac_bus *bus)
44002785b89SPierre-Louis Bossart {
4418a55786aSPierre-Louis Bossart 	struct hdac_ext_link *hlink, *_h;
44217c9b6ecSPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
44302785b89SPierre-Louis Bossart 
44402785b89SPierre-Louis Bossart 	if (!bus->mlcap)
44502785b89SPierre-Louis Bossart 		return;
44602785b89SPierre-Louis Bossart 
4478a55786aSPierre-Louis Bossart 	list_for_each_entry_safe(hlink, _h, &bus->hlink_list, list) {
44802785b89SPierre-Louis Bossart 		list_del(&hlink->list);
44917c9b6ecSPierre-Louis Bossart 		h2link = hdac_ext_link_to_ext2(hlink);
45017c9b6ecSPierre-Louis Bossart 
45117c9b6ecSPierre-Louis Bossart 		mutex_destroy(&h2link->eml_lock);
45217c9b6ecSPierre-Louis Bossart 		kfree(h2link);
45302785b89SPierre-Louis Bossart 	}
45402785b89SPierre-Louis Bossart }
45518227585SPierre-Louis Bossart EXPORT_SYMBOL_NS(hda_bus_ml_free, SND_SOC_SOF_HDA_MLINK);
45602785b89SPierre-Louis Bossart 
457fc7dab8eSPierre-Louis Bossart static struct hdac_ext2_link *
find_ext2_link(struct hdac_bus * bus,bool alt,int elid)458fc7dab8eSPierre-Louis Bossart find_ext2_link(struct hdac_bus *bus, bool alt, int elid)
459fc7dab8eSPierre-Louis Bossart {
460fc7dab8eSPierre-Louis Bossart 	struct hdac_ext_link *hlink;
461fc7dab8eSPierre-Louis Bossart 
462fc7dab8eSPierre-Louis Bossart 	list_for_each_entry(hlink, &bus->hlink_list, list) {
463fc7dab8eSPierre-Louis Bossart 		struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink);
464fc7dab8eSPierre-Louis Bossart 
465fc7dab8eSPierre-Louis Bossart 		if (h2link->alt == alt && h2link->elid == elid)
466fc7dab8eSPierre-Louis Bossart 			return h2link;
467fc7dab8eSPierre-Louis Bossart 	}
468fc7dab8eSPierre-Louis Bossart 
469fc7dab8eSPierre-Louis Bossart 	return NULL;
470fc7dab8eSPierre-Louis Bossart }
471fc7dab8eSPierre-Louis Bossart 
hdac_bus_eml_get_count(struct hdac_bus * bus,bool alt,int elid)4726857c7eeSPierre-Louis Bossart int hdac_bus_eml_get_count(struct hdac_bus *bus, bool alt, int elid)
4736857c7eeSPierre-Louis Bossart {
4746857c7eeSPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
4756857c7eeSPierre-Louis Bossart 
4766857c7eeSPierre-Louis Bossart 	h2link = find_ext2_link(bus, alt, elid);
4776857c7eeSPierre-Louis Bossart 	if (!h2link)
4786857c7eeSPierre-Louis Bossart 		return 0;
4796857c7eeSPierre-Louis Bossart 
4806857c7eeSPierre-Louis Bossart 	return h2link->slcount;
4816857c7eeSPierre-Louis Bossart }
4826857c7eeSPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_get_count, SND_SOC_SOF_HDA_MLINK);
4836857c7eeSPierre-Louis Bossart 
hdac_bus_eml_enable_interrupt(struct hdac_bus * bus,bool alt,int elid,bool enable)4842e428831SPierre-Louis Bossart void hdac_bus_eml_enable_interrupt(struct hdac_bus *bus, bool alt, int elid, bool enable)
4852e428831SPierre-Louis Bossart {
4862e428831SPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
4872e428831SPierre-Louis Bossart 	struct hdac_ext_link *hlink;
4882e428831SPierre-Louis Bossart 
4892e428831SPierre-Louis Bossart 	h2link = find_ext2_link(bus, alt, elid);
4902e428831SPierre-Louis Bossart 	if (!h2link)
4912e428831SPierre-Louis Bossart 		return;
4922e428831SPierre-Louis Bossart 
4932e428831SPierre-Louis Bossart 	if (!h2link->intc)
4942e428831SPierre-Louis Bossart 		return;
4952e428831SPierre-Louis Bossart 
4962e428831SPierre-Louis Bossart 	hlink = &h2link->hext_link;
4972e428831SPierre-Louis Bossart 
4982e428831SPierre-Louis Bossart 	mutex_lock(&h2link->eml_lock);
4992e428831SPierre-Louis Bossart 
5002e428831SPierre-Louis Bossart 	hdaml_link_enable_interrupt(hlink->ml_addr + AZX_REG_ML_LCTL, enable);
5012e428831SPierre-Louis Bossart 
5022e428831SPierre-Louis Bossart 	mutex_unlock(&h2link->eml_lock);
5032e428831SPierre-Louis Bossart }
5042e428831SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_enable_interrupt, SND_SOC_SOF_HDA_MLINK);
5052e428831SPierre-Louis Bossart 
hdac_bus_eml_check_interrupt(struct hdac_bus * bus,bool alt,int elid)5062e428831SPierre-Louis Bossart bool hdac_bus_eml_check_interrupt(struct hdac_bus *bus, bool alt, int elid)
5072e428831SPierre-Louis Bossart {
5082e428831SPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
5092e428831SPierre-Louis Bossart 	struct hdac_ext_link *hlink;
5102e428831SPierre-Louis Bossart 
5112e428831SPierre-Louis Bossart 	h2link = find_ext2_link(bus, alt, elid);
5122e428831SPierre-Louis Bossart 	if (!h2link)
5132e428831SPierre-Louis Bossart 		return false;
5142e428831SPierre-Louis Bossart 
5152e428831SPierre-Louis Bossart 	if (!h2link->intc)
5162e428831SPierre-Louis Bossart 		return false;
5172e428831SPierre-Louis Bossart 
5182e428831SPierre-Louis Bossart 	hlink = &h2link->hext_link;
5192e428831SPierre-Louis Bossart 
5202e428831SPierre-Louis Bossart 	return hdaml_link_check_interrupt(hlink->ml_addr + AZX_REG_ML_LCTL);
5212e428831SPierre-Louis Bossart }
5222e428831SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_check_interrupt, SND_SOC_SOF_HDA_MLINK);
5232e428831SPierre-Louis Bossart 
hdac_bus_eml_set_syncprd_unlocked(struct hdac_bus * bus,bool alt,int elid,u32 syncprd)52402ba1b02SPierre-Louis Bossart int hdac_bus_eml_set_syncprd_unlocked(struct hdac_bus *bus, bool alt, int elid, u32 syncprd)
52502ba1b02SPierre-Louis Bossart {
52602ba1b02SPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
52702ba1b02SPierre-Louis Bossart 	struct hdac_ext_link *hlink;
52802ba1b02SPierre-Louis Bossart 
52902ba1b02SPierre-Louis Bossart 	h2link = find_ext2_link(bus, alt, elid);
53002ba1b02SPierre-Louis Bossart 	if (!h2link)
53102ba1b02SPierre-Louis Bossart 		return 0;
53202ba1b02SPierre-Louis Bossart 
53302ba1b02SPierre-Louis Bossart 	if (!h2link->lss)
53402ba1b02SPierre-Louis Bossart 		return 0;
53502ba1b02SPierre-Louis Bossart 
53602ba1b02SPierre-Louis Bossart 	hlink = &h2link->hext_link;
53702ba1b02SPierre-Louis Bossart 
53802ba1b02SPierre-Louis Bossart 	hdaml_link_set_syncprd(hlink->ml_addr + AZX_REG_ML_LSYNC, syncprd);
53902ba1b02SPierre-Louis Bossart 
54002ba1b02SPierre-Louis Bossart 	return 0;
54102ba1b02SPierre-Louis Bossart }
54202ba1b02SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_set_syncprd_unlocked, SND_SOC_SOF_HDA_MLINK);
54302ba1b02SPierre-Louis Bossart 
hdac_bus_eml_sdw_set_syncprd_unlocked(struct hdac_bus * bus,u32 syncprd)54402ba1b02SPierre-Louis Bossart int hdac_bus_eml_sdw_set_syncprd_unlocked(struct hdac_bus *bus, u32 syncprd)
54502ba1b02SPierre-Louis Bossart {
54602ba1b02SPierre-Louis Bossart 	return hdac_bus_eml_set_syncprd_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, syncprd);
54702ba1b02SPierre-Louis Bossart }
54802ba1b02SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_syncprd_unlocked, SND_SOC_SOF_HDA_MLINK);
54902ba1b02SPierre-Louis Bossart 
hdac_bus_eml_wait_syncpu_unlocked(struct hdac_bus * bus,bool alt,int elid)55002ba1b02SPierre-Louis Bossart int hdac_bus_eml_wait_syncpu_unlocked(struct hdac_bus *bus, bool alt, int elid)
55102ba1b02SPierre-Louis Bossart {
55202ba1b02SPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
55302ba1b02SPierre-Louis Bossart 	struct hdac_ext_link *hlink;
55402ba1b02SPierre-Louis Bossart 
55502ba1b02SPierre-Louis Bossart 	h2link = find_ext2_link(bus, alt, elid);
55602ba1b02SPierre-Louis Bossart 	if (!h2link)
55702ba1b02SPierre-Louis Bossart 		return 0;
55802ba1b02SPierre-Louis Bossart 
55902ba1b02SPierre-Louis Bossart 	if (!h2link->lss)
56002ba1b02SPierre-Louis Bossart 		return 0;
56102ba1b02SPierre-Louis Bossart 
56202ba1b02SPierre-Louis Bossart 	hlink = &h2link->hext_link;
56302ba1b02SPierre-Louis Bossart 
56402ba1b02SPierre-Louis Bossart 	return hdaml_link_wait_syncpu(hlink->ml_addr + AZX_REG_ML_LSYNC);
56502ba1b02SPierre-Louis Bossart }
56602ba1b02SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_wait_syncpu_unlocked, SND_SOC_SOF_HDA_MLINK);
56702ba1b02SPierre-Louis Bossart 
hdac_bus_eml_sdw_wait_syncpu_unlocked(struct hdac_bus * bus)56802ba1b02SPierre-Louis Bossart int hdac_bus_eml_sdw_wait_syncpu_unlocked(struct hdac_bus *bus)
56902ba1b02SPierre-Louis Bossart {
57002ba1b02SPierre-Louis Bossart 	return hdac_bus_eml_wait_syncpu_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
57102ba1b02SPierre-Louis Bossart }
57202ba1b02SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_wait_syncpu_unlocked, SND_SOC_SOF_HDA_MLINK);
57302ba1b02SPierre-Louis Bossart 
hdac_bus_eml_sync_arm_unlocked(struct hdac_bus * bus,bool alt,int elid,int sublink)5741f5a6e8bSPierre-Louis Bossart void hdac_bus_eml_sync_arm_unlocked(struct hdac_bus *bus, bool alt, int elid, int sublink)
5751f5a6e8bSPierre-Louis Bossart {
5761f5a6e8bSPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
5771f5a6e8bSPierre-Louis Bossart 	struct hdac_ext_link *hlink;
5781f5a6e8bSPierre-Louis Bossart 
5791f5a6e8bSPierre-Louis Bossart 	h2link = find_ext2_link(bus, alt, elid);
5801f5a6e8bSPierre-Louis Bossart 	if (!h2link)
5811f5a6e8bSPierre-Louis Bossart 		return;
5821f5a6e8bSPierre-Louis Bossart 
5831f5a6e8bSPierre-Louis Bossart 	if (!h2link->lss)
5841f5a6e8bSPierre-Louis Bossart 		return;
5851f5a6e8bSPierre-Louis Bossart 
5861f5a6e8bSPierre-Louis Bossart 	hlink = &h2link->hext_link;
5871f5a6e8bSPierre-Louis Bossart 
5881f5a6e8bSPierre-Louis Bossart 	hdaml_link_sync_arm(hlink->ml_addr + AZX_REG_ML_LSYNC, sublink);
5891f5a6e8bSPierre-Louis Bossart }
5901f5a6e8bSPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_sync_arm_unlocked, SND_SOC_SOF_HDA_MLINK);
5911f5a6e8bSPierre-Louis Bossart 
hdac_bus_eml_sdw_sync_arm_unlocked(struct hdac_bus * bus,int sublink)5921f5a6e8bSPierre-Louis Bossart void hdac_bus_eml_sdw_sync_arm_unlocked(struct hdac_bus *bus, int sublink)
5931f5a6e8bSPierre-Louis Bossart {
5941f5a6e8bSPierre-Louis Bossart 	hdac_bus_eml_sync_arm_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, sublink);
5951f5a6e8bSPierre-Louis Bossart }
5961f5a6e8bSPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_sync_arm_unlocked, SND_SOC_SOF_HDA_MLINK);
5971f5a6e8bSPierre-Louis Bossart 
hdac_bus_eml_sync_go_unlocked(struct hdac_bus * bus,bool alt,int elid)5981f5a6e8bSPierre-Louis Bossart int hdac_bus_eml_sync_go_unlocked(struct hdac_bus *bus, bool alt, int elid)
5991f5a6e8bSPierre-Louis Bossart {
6001f5a6e8bSPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
6011f5a6e8bSPierre-Louis Bossart 	struct hdac_ext_link *hlink;
6021f5a6e8bSPierre-Louis Bossart 
6031f5a6e8bSPierre-Louis Bossart 	h2link = find_ext2_link(bus, alt, elid);
6041f5a6e8bSPierre-Louis Bossart 	if (!h2link)
6051f5a6e8bSPierre-Louis Bossart 		return 0;
6061f5a6e8bSPierre-Louis Bossart 
6071f5a6e8bSPierre-Louis Bossart 	if (!h2link->lss)
6081f5a6e8bSPierre-Louis Bossart 		return 0;
6091f5a6e8bSPierre-Louis Bossart 
6101f5a6e8bSPierre-Louis Bossart 	hlink = &h2link->hext_link;
6111f5a6e8bSPierre-Louis Bossart 
6121f5a6e8bSPierre-Louis Bossart 	hdaml_link_sync_go(hlink->ml_addr + AZX_REG_ML_LSYNC);
6131f5a6e8bSPierre-Louis Bossart 
6141f5a6e8bSPierre-Louis Bossart 	return 0;
6151f5a6e8bSPierre-Louis Bossart }
6161f5a6e8bSPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_sync_go_unlocked, SND_SOC_SOF_HDA_MLINK);
6171f5a6e8bSPierre-Louis Bossart 
hdac_bus_eml_sdw_sync_go_unlocked(struct hdac_bus * bus)6181f5a6e8bSPierre-Louis Bossart int hdac_bus_eml_sdw_sync_go_unlocked(struct hdac_bus *bus)
6191f5a6e8bSPierre-Louis Bossart {
6201f5a6e8bSPierre-Louis Bossart 	return hdac_bus_eml_sync_go_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
6211f5a6e8bSPierre-Louis Bossart }
6221f5a6e8bSPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_sync_go_unlocked, SND_SOC_SOF_HDA_MLINK);
6231f5a6e8bSPierre-Louis Bossart 
hdac_bus_eml_check_cmdsync_unlocked(struct hdac_bus * bus,bool alt,int elid)624d56d2058SPierre-Louis Bossart bool hdac_bus_eml_check_cmdsync_unlocked(struct hdac_bus *bus, bool alt, int elid)
625d56d2058SPierre-Louis Bossart {
626d56d2058SPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
627d56d2058SPierre-Louis Bossart 	struct hdac_ext_link *hlink;
628d56d2058SPierre-Louis Bossart 	u32 cmdsync_mask;
629d56d2058SPierre-Louis Bossart 
630d56d2058SPierre-Louis Bossart 	h2link = find_ext2_link(bus, alt, elid);
631d56d2058SPierre-Louis Bossart 	if (!h2link)
632d56d2058SPierre-Louis Bossart 		return 0;
633d56d2058SPierre-Louis Bossart 
634d56d2058SPierre-Louis Bossart 	if (!h2link->lss)
635d56d2058SPierre-Louis Bossart 		return 0;
636d56d2058SPierre-Louis Bossart 
637d56d2058SPierre-Louis Bossart 	hlink = &h2link->hext_link;
638d56d2058SPierre-Louis Bossart 
639d56d2058SPierre-Louis Bossart 	cmdsync_mask = GENMASK(AZX_REG_ML_LSYNC_CMDSYNC_SHIFT + h2link->slcount - 1,
640d56d2058SPierre-Louis Bossart 			       AZX_REG_ML_LSYNC_CMDSYNC_SHIFT);
641d56d2058SPierre-Louis Bossart 
642d56d2058SPierre-Louis Bossart 	return hdaml_link_check_cmdsync(hlink->ml_addr + AZX_REG_ML_LSYNC,
643d56d2058SPierre-Louis Bossart 					cmdsync_mask);
644d56d2058SPierre-Louis Bossart }
645d56d2058SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_check_cmdsync_unlocked, SND_SOC_SOF_HDA_MLINK);
646d56d2058SPierre-Louis Bossart 
hdac_bus_eml_sdw_check_cmdsync_unlocked(struct hdac_bus * bus)647d56d2058SPierre-Louis Bossart bool hdac_bus_eml_sdw_check_cmdsync_unlocked(struct hdac_bus *bus)
648d56d2058SPierre-Louis Bossart {
649d56d2058SPierre-Louis Bossart 	return hdac_bus_eml_check_cmdsync_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
650d56d2058SPierre-Louis Bossart }
651d56d2058SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_check_cmdsync_unlocked, SND_SOC_SOF_HDA_MLINK);
652d56d2058SPierre-Louis Bossart 
hdac_bus_eml_power_up_base(struct hdac_bus * bus,bool alt,int elid,int sublink,bool eml_lock)653fc7dab8eSPierre-Louis Bossart static int hdac_bus_eml_power_up_base(struct hdac_bus *bus, bool alt, int elid, int sublink,
654fc7dab8eSPierre-Louis Bossart 				      bool eml_lock)
655fc7dab8eSPierre-Louis Bossart {
656fc7dab8eSPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
657fc7dab8eSPierre-Louis Bossart 	struct hdac_ext_link *hlink;
658fc7dab8eSPierre-Louis Bossart 	int ret = 0;
659fc7dab8eSPierre-Louis Bossart 
660fc7dab8eSPierre-Louis Bossart 	h2link = find_ext2_link(bus, alt, elid);
661fc7dab8eSPierre-Louis Bossart 	if (!h2link)
662fc7dab8eSPierre-Louis Bossart 		return -ENODEV;
663fc7dab8eSPierre-Louis Bossart 
664fc7dab8eSPierre-Louis Bossart 	if (sublink >= h2link->slcount)
665fc7dab8eSPierre-Louis Bossart 		return -EINVAL;
666fc7dab8eSPierre-Louis Bossart 
667fc7dab8eSPierre-Louis Bossart 	hlink = &h2link->hext_link;
668fc7dab8eSPierre-Louis Bossart 
669fc7dab8eSPierre-Louis Bossart 	if (eml_lock)
670fc7dab8eSPierre-Louis Bossart 		mutex_lock(&h2link->eml_lock);
671fc7dab8eSPierre-Louis Bossart 
6727430dea4SPierre-Louis Bossart 	if (!alt) {
673fc7dab8eSPierre-Louis Bossart 		if (++hlink->ref_count > 1)
674fc7dab8eSPierre-Louis Bossart 			goto skip_init;
6757430dea4SPierre-Louis Bossart 	} else {
6767430dea4SPierre-Louis Bossart 		if (++h2link->sublink_ref_count[sublink] > 1)
6777430dea4SPierre-Louis Bossart 			goto skip_init;
6787430dea4SPierre-Louis Bossart 	}
679fc7dab8eSPierre-Louis Bossart 
680fc7dab8eSPierre-Louis Bossart 	ret = hdaml_link_init(hlink->ml_addr + AZX_REG_ML_LCTL, sublink);
681fc7dab8eSPierre-Louis Bossart 
682fc7dab8eSPierre-Louis Bossart skip_init:
683fc7dab8eSPierre-Louis Bossart 	if (eml_lock)
684fc7dab8eSPierre-Louis Bossart 		mutex_unlock(&h2link->eml_lock);
685fc7dab8eSPierre-Louis Bossart 
686fc7dab8eSPierre-Louis Bossart 	return ret;
687fc7dab8eSPierre-Louis Bossart }
688fc7dab8eSPierre-Louis Bossart 
hdac_bus_eml_power_up(struct hdac_bus * bus,bool alt,int elid,int sublink)689fc7dab8eSPierre-Louis Bossart int hdac_bus_eml_power_up(struct hdac_bus *bus, bool alt, int elid, int sublink)
690fc7dab8eSPierre-Louis Bossart {
691fc7dab8eSPierre-Louis Bossart 	return hdac_bus_eml_power_up_base(bus, alt, elid, sublink, true);
692fc7dab8eSPierre-Louis Bossart }
693fc7dab8eSPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_power_up, SND_SOC_SOF_HDA_MLINK);
694fc7dab8eSPierre-Louis Bossart 
hdac_bus_eml_power_up_unlocked(struct hdac_bus * bus,bool alt,int elid,int sublink)695fc7dab8eSPierre-Louis Bossart int hdac_bus_eml_power_up_unlocked(struct hdac_bus *bus, bool alt, int elid, int sublink)
696fc7dab8eSPierre-Louis Bossart {
697fc7dab8eSPierre-Louis Bossart 	return hdac_bus_eml_power_up_base(bus, alt, elid, sublink, false);
698fc7dab8eSPierre-Louis Bossart }
699fc7dab8eSPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_power_up_unlocked, SND_SOC_SOF_HDA_MLINK);
700fc7dab8eSPierre-Louis Bossart 
hdac_bus_eml_power_down_base(struct hdac_bus * bus,bool alt,int elid,int sublink,bool eml_lock)701fc7dab8eSPierre-Louis Bossart static int hdac_bus_eml_power_down_base(struct hdac_bus *bus, bool alt, int elid, int sublink,
702fc7dab8eSPierre-Louis Bossart 					bool eml_lock)
703fc7dab8eSPierre-Louis Bossart {
704fc7dab8eSPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
705fc7dab8eSPierre-Louis Bossart 	struct hdac_ext_link *hlink;
706fc7dab8eSPierre-Louis Bossart 	int ret = 0;
707fc7dab8eSPierre-Louis Bossart 
708fc7dab8eSPierre-Louis Bossart 	h2link = find_ext2_link(bus, alt, elid);
709fc7dab8eSPierre-Louis Bossart 	if (!h2link)
710fc7dab8eSPierre-Louis Bossart 		return -ENODEV;
711fc7dab8eSPierre-Louis Bossart 
712fc7dab8eSPierre-Louis Bossart 	if (sublink >= h2link->slcount)
713fc7dab8eSPierre-Louis Bossart 		return -EINVAL;
714fc7dab8eSPierre-Louis Bossart 
715fc7dab8eSPierre-Louis Bossart 	hlink = &h2link->hext_link;
716fc7dab8eSPierre-Louis Bossart 
717fc7dab8eSPierre-Louis Bossart 	if (eml_lock)
718fc7dab8eSPierre-Louis Bossart 		mutex_lock(&h2link->eml_lock);
719fc7dab8eSPierre-Louis Bossart 
7207430dea4SPierre-Louis Bossart 	if (!alt) {
721fc7dab8eSPierre-Louis Bossart 		if (--hlink->ref_count > 0)
722fc7dab8eSPierre-Louis Bossart 			goto skip_shutdown;
7237430dea4SPierre-Louis Bossart 	} else {
7247430dea4SPierre-Louis Bossart 		if (--h2link->sublink_ref_count[sublink] > 0)
7257430dea4SPierre-Louis Bossart 			goto skip_shutdown;
7267430dea4SPierre-Louis Bossart 	}
727fc7dab8eSPierre-Louis Bossart 	ret = hdaml_link_shutdown(hlink->ml_addr + AZX_REG_ML_LCTL, sublink);
728fc7dab8eSPierre-Louis Bossart 
729fc7dab8eSPierre-Louis Bossart skip_shutdown:
730fc7dab8eSPierre-Louis Bossart 	if (eml_lock)
731fc7dab8eSPierre-Louis Bossart 		mutex_unlock(&h2link->eml_lock);
732fc7dab8eSPierre-Louis Bossart 
733fc7dab8eSPierre-Louis Bossart 	return ret;
734fc7dab8eSPierre-Louis Bossart }
735fc7dab8eSPierre-Louis Bossart 
hdac_bus_eml_power_down(struct hdac_bus * bus,bool alt,int elid,int sublink)736fc7dab8eSPierre-Louis Bossart int hdac_bus_eml_power_down(struct hdac_bus *bus, bool alt, int elid, int sublink)
737fc7dab8eSPierre-Louis Bossart {
738fc7dab8eSPierre-Louis Bossart 	return hdac_bus_eml_power_down_base(bus, alt, elid, sublink, true);
739fc7dab8eSPierre-Louis Bossart }
740fc7dab8eSPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_power_down, SND_SOC_SOF_HDA_MLINK);
741fc7dab8eSPierre-Louis Bossart 
hdac_bus_eml_power_down_unlocked(struct hdac_bus * bus,bool alt,int elid,int sublink)742fc7dab8eSPierre-Louis Bossart int hdac_bus_eml_power_down_unlocked(struct hdac_bus *bus, bool alt, int elid, int sublink)
743fc7dab8eSPierre-Louis Bossart {
744fc7dab8eSPierre-Louis Bossart 	return hdac_bus_eml_power_down_base(bus, alt, elid, sublink, false);
745fc7dab8eSPierre-Louis Bossart }
746fc7dab8eSPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_power_down_unlocked, SND_SOC_SOF_HDA_MLINK);
747fc7dab8eSPierre-Louis Bossart 
hdac_bus_eml_sdw_power_up_unlocked(struct hdac_bus * bus,int sublink)748725218f1SPierre-Louis Bossart int hdac_bus_eml_sdw_power_up_unlocked(struct hdac_bus *bus, int sublink)
749725218f1SPierre-Louis Bossart {
750725218f1SPierre-Louis Bossart 	return hdac_bus_eml_power_up_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, sublink);
751725218f1SPierre-Louis Bossart }
752725218f1SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_up_unlocked, SND_SOC_SOF_HDA_MLINK);
753725218f1SPierre-Louis Bossart 
hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus * bus,int sublink)754725218f1SPierre-Louis Bossart int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink)
755725218f1SPierre-Louis Bossart {
756725218f1SPierre-Louis Bossart 	return hdac_bus_eml_power_down_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, sublink);
757725218f1SPierre-Louis Bossart }
758725218f1SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_down_unlocked, SND_SOC_SOF_HDA_MLINK);
759725218f1SPierre-Louis Bossart 
hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus * bus,int sublink,u16 * lsdiid)76034e38f03SPierre-Louis Bossart int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid)
76134e38f03SPierre-Louis Bossart {
76234e38f03SPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
76334e38f03SPierre-Louis Bossart 	struct hdac_ext_link *hlink;
76434e38f03SPierre-Louis Bossart 
76534e38f03SPierre-Louis Bossart 	h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
76634e38f03SPierre-Louis Bossart 	if (!h2link)
76734e38f03SPierre-Louis Bossart 		return -ENODEV;
76834e38f03SPierre-Louis Bossart 
76934e38f03SPierre-Louis Bossart 	hlink = &h2link->hext_link;
77034e38f03SPierre-Louis Bossart 
77134e38f03SPierre-Louis Bossart 	*lsdiid = hdaml_link_get_lsdiid(hlink->ml_addr + AZX_REG_ML_LSDIID_OFFSET(sublink));
77234e38f03SPierre-Louis Bossart 
77334e38f03SPierre-Louis Bossart 	return 0;
77434e38f03SPierre-Louis Bossart } EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_lsdiid_unlocked, SND_SOC_SOF_HDA_MLINK);
77534e38f03SPierre-Louis Bossart 
hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus * bus,int sublink,int dev_num)77687a6ddc0SPierre-Louis Bossart int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num)
77787a6ddc0SPierre-Louis Bossart {
77887a6ddc0SPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
77987a6ddc0SPierre-Louis Bossart 	struct hdac_ext_link *hlink;
78087a6ddc0SPierre-Louis Bossart 
78187a6ddc0SPierre-Louis Bossart 	h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
78287a6ddc0SPierre-Louis Bossart 	if (!h2link)
78387a6ddc0SPierre-Louis Bossart 		return -ENODEV;
78487a6ddc0SPierre-Louis Bossart 
78587a6ddc0SPierre-Louis Bossart 	hlink = &h2link->hext_link;
78687a6ddc0SPierre-Louis Bossart 
78787a6ddc0SPierre-Louis Bossart 	mutex_lock(&h2link->eml_lock);
78887a6ddc0SPierre-Louis Bossart 
78987a6ddc0SPierre-Louis Bossart 	hdaml_link_set_lsdiid(hlink->ml_addr + AZX_REG_ML_LSDIID_OFFSET(sublink), dev_num);
79087a6ddc0SPierre-Louis Bossart 
79187a6ddc0SPierre-Louis Bossart 	mutex_unlock(&h2link->eml_lock);
79287a6ddc0SPierre-Louis Bossart 
79387a6ddc0SPierre-Louis Bossart 	return 0;
79487a6ddc0SPierre-Louis Bossart } EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_lsdiid, SND_SOC_SOF_HDA_MLINK);
79587a6ddc0SPierre-Louis Bossart 
796ccc2f0c1SPierre-Louis Bossart /*
797ccc2f0c1SPierre-Louis Bossart  * the 'y' parameter comes from the PCMSyCM hardware register naming. 'y' refers to the
798ccc2f0c1SPierre-Louis Bossart  * PDI index, i.e. the FIFO used for RX or TX
799ccc2f0c1SPierre-Louis Bossart  */
hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus * bus,int sublink,int y,int channel_mask,int stream_id,int dir)800ccc2f0c1SPierre-Louis Bossart int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
801ccc2f0c1SPierre-Louis Bossart 				   int channel_mask, int stream_id, int dir)
802ccc2f0c1SPierre-Louis Bossart {
803ccc2f0c1SPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
804ccc2f0c1SPierre-Louis Bossart 	u16 __iomem *pcmsycm;
8057075b0c9SPierre-Louis Bossart 	int hchan;
8067075b0c9SPierre-Louis Bossart 	int lchan;
807ccc2f0c1SPierre-Louis Bossart 	u16 val;
808ccc2f0c1SPierre-Louis Bossart 
809ccc2f0c1SPierre-Louis Bossart 	h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
810ccc2f0c1SPierre-Louis Bossart 	if (!h2link)
811ccc2f0c1SPierre-Louis Bossart 		return -ENODEV;
812ccc2f0c1SPierre-Louis Bossart 
813ccc2f0c1SPierre-Louis Bossart 	pcmsycm = h2link->base_ptr + h2link->shim_offset +
814ccc2f0c1SPierre-Louis Bossart 		h2link->instance_offset * sublink +
815ccc2f0c1SPierre-Louis Bossart 		AZX_REG_SDW_SHIM_PCMSyCM(y);
816ccc2f0c1SPierre-Louis Bossart 
8177075b0c9SPierre-Louis Bossart 	if (channel_mask) {
8187075b0c9SPierre-Louis Bossart 		hchan = __fls(channel_mask);
8197075b0c9SPierre-Louis Bossart 		lchan = __ffs(channel_mask);
8207075b0c9SPierre-Louis Bossart 	} else {
8217075b0c9SPierre-Louis Bossart 		hchan = 0;
8227075b0c9SPierre-Louis Bossart 		lchan = 0;
8237075b0c9SPierre-Louis Bossart 	}
8247075b0c9SPierre-Louis Bossart 
825ccc2f0c1SPierre-Louis Bossart 	mutex_lock(&h2link->eml_lock);
826ccc2f0c1SPierre-Louis Bossart 
8277075b0c9SPierre-Louis Bossart 	hdaml_shim_map_stream_ch(pcmsycm, lchan, hchan,
828ccc2f0c1SPierre-Louis Bossart 				 stream_id, dir);
829ccc2f0c1SPierre-Louis Bossart 
830ccc2f0c1SPierre-Louis Bossart 	mutex_unlock(&h2link->eml_lock);
831ccc2f0c1SPierre-Louis Bossart 
832ccc2f0c1SPierre-Louis Bossart 	val = readw(pcmsycm);
833ccc2f0c1SPierre-Louis Bossart 
834*02c7f872SPierre-Louis Bossart 	dev_dbg(bus->dev, "sublink %d channel_mask %#x stream_id %d dir %d pcmscm %#x\n",
835*02c7f872SPierre-Louis Bossart 		sublink, channel_mask, stream_id, dir, val);
836ccc2f0c1SPierre-Louis Bossart 
837ccc2f0c1SPierre-Louis Bossart 	return 0;
838ccc2f0c1SPierre-Louis Bossart } EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, SND_SOC_SOF_HDA_MLINK);
839ccc2f0c1SPierre-Louis Bossart 
hda_bus_ml_put_all(struct hdac_bus * bus)84052f16103SPierre-Louis Bossart void hda_bus_ml_put_all(struct hdac_bus *bus)
84152f16103SPierre-Louis Bossart {
84252f16103SPierre-Louis Bossart 	struct hdac_ext_link *hlink;
84352f16103SPierre-Louis Bossart 
8444c2d4e44SPierre-Louis Bossart 	list_for_each_entry(hlink, &bus->hlink_list, list) {
8454c2d4e44SPierre-Louis Bossart 		struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink);
8464c2d4e44SPierre-Louis Bossart 
8474c2d4e44SPierre-Louis Bossart 		if (!h2link->alt)
84852f16103SPierre-Louis Bossart 			snd_hdac_ext_bus_link_put(bus, hlink);
84952f16103SPierre-Louis Bossart 	}
8504c2d4e44SPierre-Louis Bossart }
85118227585SPierre-Louis Bossart EXPORT_SYMBOL_NS(hda_bus_ml_put_all, SND_SOC_SOF_HDA_MLINK);
85252f16103SPierre-Louis Bossart 
hda_bus_ml_reset_losidv(struct hdac_bus * bus)8531a7d06aeSPierre-Louis Bossart void hda_bus_ml_reset_losidv(struct hdac_bus *bus)
8541a7d06aeSPierre-Louis Bossart {
8551a7d06aeSPierre-Louis Bossart 	struct hdac_ext_link *hlink;
8561a7d06aeSPierre-Louis Bossart 
8571a7d06aeSPierre-Louis Bossart 	/* Reset stream-to-link mapping */
8581a7d06aeSPierre-Louis Bossart 	list_for_each_entry(hlink, &bus->hlink_list, list)
8591a7d06aeSPierre-Louis Bossart 		writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
8601a7d06aeSPierre-Louis Bossart }
86118227585SPierre-Louis Bossart EXPORT_SYMBOL_NS(hda_bus_ml_reset_losidv, SND_SOC_SOF_HDA_MLINK);
8621a7d06aeSPierre-Louis Bossart 
hda_bus_ml_resume(struct hdac_bus * bus)863f402a974SPierre-Louis Bossart int hda_bus_ml_resume(struct hdac_bus *bus)
864f402a974SPierre-Louis Bossart {
865f402a974SPierre-Louis Bossart 	struct hdac_ext_link *hlink;
866f402a974SPierre-Louis Bossart 	int ret;
867f402a974SPierre-Louis Bossart 
868f402a974SPierre-Louis Bossart 	/* power up links that were active before suspend */
869f402a974SPierre-Louis Bossart 	list_for_each_entry(hlink, &bus->hlink_list, list) {
8704c2d4e44SPierre-Louis Bossart 		struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink);
8714c2d4e44SPierre-Louis Bossart 
8724c2d4e44SPierre-Louis Bossart 		if (!h2link->alt && hlink->ref_count) {
873f402a974SPierre-Louis Bossart 			ret = snd_hdac_ext_bus_link_power_up(hlink);
874f402a974SPierre-Louis Bossart 			if (ret < 0)
875f402a974SPierre-Louis Bossart 				return ret;
876f402a974SPierre-Louis Bossart 		}
877f402a974SPierre-Louis Bossart 	}
878f402a974SPierre-Louis Bossart 	return 0;
879f402a974SPierre-Louis Bossart }
88018227585SPierre-Louis Bossart EXPORT_SYMBOL_NS(hda_bus_ml_resume, SND_SOC_SOF_HDA_MLINK);
881f402a974SPierre-Louis Bossart 
hda_bus_ml_suspend(struct hdac_bus * bus)882f402a974SPierre-Louis Bossart int hda_bus_ml_suspend(struct hdac_bus *bus)
883f402a974SPierre-Louis Bossart {
8844c2d4e44SPierre-Louis Bossart 	struct hdac_ext_link *hlink;
8854c2d4e44SPierre-Louis Bossart 	int ret;
8864c2d4e44SPierre-Louis Bossart 
8874c2d4e44SPierre-Louis Bossart 	list_for_each_entry(hlink, &bus->hlink_list, list) {
8884c2d4e44SPierre-Louis Bossart 		struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink);
8894c2d4e44SPierre-Louis Bossart 
8904c2d4e44SPierre-Louis Bossart 		if (!h2link->alt) {
8914c2d4e44SPierre-Louis Bossart 			ret = snd_hdac_ext_bus_link_power_down(hlink);
8924c2d4e44SPierre-Louis Bossart 			if (ret < 0)
8934c2d4e44SPierre-Louis Bossart 				return ret;
8944c2d4e44SPierre-Louis Bossart 		}
8954c2d4e44SPierre-Louis Bossart 	}
8964c2d4e44SPierre-Louis Bossart 	return 0;
897f402a974SPierre-Louis Bossart }
89818227585SPierre-Louis Bossart EXPORT_SYMBOL_NS(hda_bus_ml_suspend, SND_SOC_SOF_HDA_MLINK);
899f402a974SPierre-Louis Bossart 
hdac_bus_eml_get_mutex(struct hdac_bus * bus,bool alt,int elid)900681f27f3SPierre-Louis Bossart struct mutex *hdac_bus_eml_get_mutex(struct hdac_bus *bus, bool alt, int elid)
901681f27f3SPierre-Louis Bossart {
902681f27f3SPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
903681f27f3SPierre-Louis Bossart 
904681f27f3SPierre-Louis Bossart 	h2link = find_ext2_link(bus, alt, elid);
905681f27f3SPierre-Louis Bossart 	if (!h2link)
906681f27f3SPierre-Louis Bossart 		return NULL;
907681f27f3SPierre-Louis Bossart 
908681f27f3SPierre-Louis Bossart 	return &h2link->eml_lock;
909681f27f3SPierre-Louis Bossart }
910681f27f3SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_get_mutex, SND_SOC_SOF_HDA_MLINK);
911681f27f3SPierre-Louis Bossart 
hdac_bus_eml_ssp_get_hlink(struct hdac_bus * bus)9122b864e96SPierre-Louis Bossart struct hdac_ext_link *hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus)
9132b864e96SPierre-Louis Bossart {
9142b864e96SPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
9152b864e96SPierre-Louis Bossart 
9162b864e96SPierre-Louis Bossart 	h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_INTEL_SSP);
9172b864e96SPierre-Louis Bossart 	if (!h2link)
9182b864e96SPierre-Louis Bossart 		return NULL;
9192b864e96SPierre-Louis Bossart 
9202b864e96SPierre-Louis Bossart 	return &h2link->hext_link;
9212b864e96SPierre-Louis Bossart }
9222b864e96SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_ssp_get_hlink, SND_SOC_SOF_HDA_MLINK);
9232b864e96SPierre-Louis Bossart 
hdac_bus_eml_dmic_get_hlink(struct hdac_bus * bus)9242b864e96SPierre-Louis Bossart struct hdac_ext_link *hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus)
9252b864e96SPierre-Louis Bossart {
9262b864e96SPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
9272b864e96SPierre-Louis Bossart 
9282b864e96SPierre-Louis Bossart 	h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_INTEL_DMIC);
9292b864e96SPierre-Louis Bossart 	if (!h2link)
9302b864e96SPierre-Louis Bossart 		return NULL;
9312b864e96SPierre-Louis Bossart 
9322b864e96SPierre-Louis Bossart 	return &h2link->hext_link;
9332b864e96SPierre-Louis Bossart }
9342b864e96SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_dmic_get_hlink, SND_SOC_SOF_HDA_MLINK);
9352b864e96SPierre-Louis Bossart 
hdac_bus_eml_sdw_get_hlink(struct hdac_bus * bus)936dcb88fc4SPierre-Louis Bossart struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus)
937dcb88fc4SPierre-Louis Bossart {
938dcb88fc4SPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
939dcb88fc4SPierre-Louis Bossart 
940dcb88fc4SPierre-Louis Bossart 	h2link = find_ext2_link(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
941dcb88fc4SPierre-Louis Bossart 	if (!h2link)
942dcb88fc4SPierre-Louis Bossart 		return NULL;
943dcb88fc4SPierre-Louis Bossart 
944dcb88fc4SPierre-Louis Bossart 	return &h2link->hext_link;
945dcb88fc4SPierre-Louis Bossart }
946dcb88fc4SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_hlink, SND_SOC_SOF_HDA_MLINK);
947dcb88fc4SPierre-Louis Bossart 
hdac_bus_eml_enable_offload(struct hdac_bus * bus,bool alt,int elid,bool enable)94882958c40SPierre-Louis Bossart int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool enable)
94982958c40SPierre-Louis Bossart {
95082958c40SPierre-Louis Bossart 	struct hdac_ext2_link *h2link;
95182958c40SPierre-Louis Bossart 	struct hdac_ext_link *hlink;
95282958c40SPierre-Louis Bossart 
95382958c40SPierre-Louis Bossart 	h2link = find_ext2_link(bus, alt, elid);
95482958c40SPierre-Louis Bossart 	if (!h2link)
95582958c40SPierre-Louis Bossart 		return -ENODEV;
95682958c40SPierre-Louis Bossart 
95782958c40SPierre-Louis Bossart 	if (!h2link->ofls)
95882958c40SPierre-Louis Bossart 		return 0;
95982958c40SPierre-Louis Bossart 
96082958c40SPierre-Louis Bossart 	hlink = &h2link->hext_link;
96182958c40SPierre-Louis Bossart 
96282958c40SPierre-Louis Bossart 	mutex_lock(&h2link->eml_lock);
96382958c40SPierre-Louis Bossart 
96482958c40SPierre-Louis Bossart 	hdaml_lctl_offload_enable(hlink->ml_addr + AZX_REG_ML_LCTL, enable);
96582958c40SPierre-Louis Bossart 
96682958c40SPierre-Louis Bossart 	mutex_unlock(&h2link->eml_lock);
96782958c40SPierre-Louis Bossart 
96882958c40SPierre-Louis Bossart 	return 0;
96982958c40SPierre-Louis Bossart }
97082958c40SPierre-Louis Bossart EXPORT_SYMBOL_NS(hdac_bus_eml_enable_offload, SND_SOC_SOF_HDA_MLINK);
97182958c40SPierre-Louis Bossart 
97252f16103SPierre-Louis Bossart #endif
97318227585SPierre-Louis Bossart 
97418227585SPierre-Louis Bossart MODULE_LICENSE("Dual BSD/GPL");
975