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