xref: /linux/sound/soc/intel/avs/mtl.c (revision a9e6060bb2a6cae6d43a98ec0794844ad01273d3)
1*af1c968dSCezary Rojewski // SPDX-License-Identifier: GPL-2.0-only
2*af1c968dSCezary Rojewski /*
3*af1c968dSCezary Rojewski  * Copyright(c) 2021-2025 Intel Corporation
4*af1c968dSCezary Rojewski  *
5*af1c968dSCezary Rojewski  * Authors: Cezary Rojewski <cezary.rojewski@intel.com>
6*af1c968dSCezary Rojewski  *          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
7*af1c968dSCezary Rojewski  */
8*af1c968dSCezary Rojewski 
9*af1c968dSCezary Rojewski #include <sound/hdaudio_ext.h>
10*af1c968dSCezary Rojewski #include "avs.h"
11*af1c968dSCezary Rojewski #include "registers.h"
12*af1c968dSCezary Rojewski #include "trace.h"
13*af1c968dSCezary Rojewski 
14*af1c968dSCezary Rojewski #define MTL_HfDSSGBL_BASE	0x1000
15*af1c968dSCezary Rojewski #define MTL_REG_HfDSSCS		(MTL_HfDSSGBL_BASE + 0x0)
16*af1c968dSCezary Rojewski #define MTL_HfDSSCS_SPA		BIT(16)
17*af1c968dSCezary Rojewski #define MTL_HfDSSCS_CPA		BIT(24)
18*af1c968dSCezary Rojewski 
19*af1c968dSCezary Rojewski #define MTL_DSPCS_BASE		0x178D00
20*af1c968dSCezary Rojewski #define MTL_REG_DSPCCTL		(MTL_DSPCS_BASE + 0x4)
21*af1c968dSCezary Rojewski #define MTL_DSPCCTL_SPA		BIT(0)
22*af1c968dSCezary Rojewski #define MTL_DSPCCTL_CPA		BIT(8)
23*af1c968dSCezary Rojewski #define MTL_DSPCCTL_OSEL	GENMASK(25, 24)
24*af1c968dSCezary Rojewski #define MTL_DSPCCTL_OSEL_HOST	BIT(25)
25*af1c968dSCezary Rojewski 
26*af1c968dSCezary Rojewski #define MTL_HfINT_BASE		0x1100
27*af1c968dSCezary Rojewski #define MTL_REG_HfINTIPPTR	(MTL_HfINT_BASE + 0x8)
28*af1c968dSCezary Rojewski #define MTL_REG_HfHIPCIE	(MTL_HfINT_BASE + 0x40)
29*af1c968dSCezary Rojewski #define MTL_HfINTIPPTR_PTR	GENMASK(20, 0)
30*af1c968dSCezary Rojewski #define MTL_HfHIPCIE_IE		BIT(0)
31*af1c968dSCezary Rojewski 
32*af1c968dSCezary Rojewski #define MTL_DWICTL_INTENL_IE		BIT(0)
33*af1c968dSCezary Rojewski #define MTL_DWICTL_FINALSTATUSL_IPC	BIT(0) /* same as ADSPIS_IPC */
34*af1c968dSCezary Rojewski 
avs_mtl_core_power_on(struct avs_dev * adev)35*af1c968dSCezary Rojewski static int avs_mtl_core_power_on(struct avs_dev *adev)
36*af1c968dSCezary Rojewski {
37*af1c968dSCezary Rojewski 	u32 reg;
38*af1c968dSCezary Rojewski 	int ret;
39*af1c968dSCezary Rojewski 
40*af1c968dSCezary Rojewski 	/* Power up DSP domain. */
41*af1c968dSCezary Rojewski 	snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, MTL_HfDSSCS_SPA);
42*af1c968dSCezary Rojewski 	trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "power dsp", true);
43*af1c968dSCezary Rojewski 
44*af1c968dSCezary Rojewski 	ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg,
45*af1c968dSCezary Rojewski 				       (reg & MTL_HfDSSCS_CPA) == MTL_HfDSSCS_CPA,
46*af1c968dSCezary Rojewski 				       AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US);
47*af1c968dSCezary Rojewski 	if (ret) {
48*af1c968dSCezary Rojewski 		dev_err(adev->dev, "power on domain dsp failed: %d\n", ret);
49*af1c968dSCezary Rojewski 		return ret;
50*af1c968dSCezary Rojewski 	}
51*af1c968dSCezary Rojewski 
52*af1c968dSCezary Rojewski 	/* Prevent power gating of DSP domain. */
53*af1c968dSCezary Rojewski 	snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL, MTL_HfPWRCTL_WPDSPHPxPG,
54*af1c968dSCezary Rojewski 			      MTL_HfPWRCTL_WPDSPHPxPG);
55*af1c968dSCezary Rojewski 	trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "prevent dsp PG", true);
56*af1c968dSCezary Rojewski 
57*af1c968dSCezary Rojewski 	ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfPWRSTS, reg,
58*af1c968dSCezary Rojewski 				       (reg & MTL_HfPWRSTS_DSPHPxPGS) == MTL_HfPWRSTS_DSPHPxPGS,
59*af1c968dSCezary Rojewski 				       AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US);
60*af1c968dSCezary Rojewski 
61*af1c968dSCezary Rojewski 	/* Set ownership to HOST. */
62*af1c968dSCezary Rojewski 	snd_hdac_adsp_updatel(adev, MTL_REG_DSPCCTL, MTL_DSPCCTL_OSEL, MTL_DSPCCTL_OSEL_HOST);
63*af1c968dSCezary Rojewski 	return ret;
64*af1c968dSCezary Rojewski }
65*af1c968dSCezary Rojewski 
avs_mtl_core_power_off(struct avs_dev * adev)66*af1c968dSCezary Rojewski static int avs_mtl_core_power_off(struct avs_dev *adev)
67*af1c968dSCezary Rojewski {
68*af1c968dSCezary Rojewski 	u32 reg;
69*af1c968dSCezary Rojewski 
70*af1c968dSCezary Rojewski 	/* Allow power gating of DSP domain. No STS polling as HOST is only one of its users. */
71*af1c968dSCezary Rojewski 	snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL, MTL_HfPWRCTL_WPDSPHPxPG, 0);
72*af1c968dSCezary Rojewski 	trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "allow dsp pg", false);
73*af1c968dSCezary Rojewski 
74*af1c968dSCezary Rojewski 	/* Power down DSP domain. */
75*af1c968dSCezary Rojewski 	snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, 0);
76*af1c968dSCezary Rojewski 	trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "power dsp", false);
77*af1c968dSCezary Rojewski 
78*af1c968dSCezary Rojewski 	return snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg,
79*af1c968dSCezary Rojewski 					(reg & MTL_HfDSSCS_CPA) == 0,
80*af1c968dSCezary Rojewski 					AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US);
81*af1c968dSCezary Rojewski }
82*af1c968dSCezary Rojewski 
avs_mtl_core_power(struct avs_dev * adev,u32 core_mask,bool power)83*af1c968dSCezary Rojewski int avs_mtl_core_power(struct avs_dev *adev, u32 core_mask, bool power)
84*af1c968dSCezary Rojewski {
85*af1c968dSCezary Rojewski 	core_mask &= AVS_MAIN_CORE_MASK;
86*af1c968dSCezary Rojewski 	if (!core_mask)
87*af1c968dSCezary Rojewski 		return 0;
88*af1c968dSCezary Rojewski 
89*af1c968dSCezary Rojewski 	if (power)
90*af1c968dSCezary Rojewski 		return avs_mtl_core_power_on(adev);
91*af1c968dSCezary Rojewski 	return avs_mtl_core_power_off(adev);
92*af1c968dSCezary Rojewski }
93*af1c968dSCezary Rojewski 
avs_mtl_core_reset(struct avs_dev * adev,u32 core_mask,bool power)94*af1c968dSCezary Rojewski int avs_mtl_core_reset(struct avs_dev *adev, u32 core_mask, bool power)
95*af1c968dSCezary Rojewski {
96*af1c968dSCezary Rojewski 	/* No logical equivalent on ACE 1.x. */
97*af1c968dSCezary Rojewski 	return 0;
98*af1c968dSCezary Rojewski }
99*af1c968dSCezary Rojewski 
avs_mtl_core_stall(struct avs_dev * adev,u32 core_mask,bool stall)100*af1c968dSCezary Rojewski int avs_mtl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall)
101*af1c968dSCezary Rojewski {
102*af1c968dSCezary Rojewski 	u32 value, reg;
103*af1c968dSCezary Rojewski 	int ret;
104*af1c968dSCezary Rojewski 
105*af1c968dSCezary Rojewski 	core_mask &= AVS_MAIN_CORE_MASK;
106*af1c968dSCezary Rojewski 	if (!core_mask)
107*af1c968dSCezary Rojewski 		return 0;
108*af1c968dSCezary Rojewski 
109*af1c968dSCezary Rojewski 	value = snd_hdac_adsp_readl(adev, MTL_REG_DSPCCTL);
110*af1c968dSCezary Rojewski 	trace_avs_dsp_core_op(value, core_mask, "stall", stall);
111*af1c968dSCezary Rojewski 	if (value == UINT_MAX)
112*af1c968dSCezary Rojewski 		return 0;
113*af1c968dSCezary Rojewski 
114*af1c968dSCezary Rojewski 	value = stall ? 0 : MTL_DSPCCTL_SPA;
115*af1c968dSCezary Rojewski 	snd_hdac_adsp_updatel(adev, MTL_REG_DSPCCTL, MTL_DSPCCTL_SPA, value);
116*af1c968dSCezary Rojewski 
117*af1c968dSCezary Rojewski 	value = stall ? 0 : MTL_DSPCCTL_CPA;
118*af1c968dSCezary Rojewski 	ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_DSPCCTL,
119*af1c968dSCezary Rojewski 				       reg, (reg & MTL_DSPCCTL_CPA) == value,
120*af1c968dSCezary Rojewski 				       AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US);
121*af1c968dSCezary Rojewski 	if (ret)
122*af1c968dSCezary Rojewski 		dev_err(adev->dev, "core_mask %d %sstall failed: %d\n",
123*af1c968dSCezary Rojewski 			core_mask, stall ? "" : "un", ret);
124*af1c968dSCezary Rojewski 	return ret;
125*af1c968dSCezary Rojewski }
126*af1c968dSCezary Rojewski 
avs_mtl_ipc_interrupt(struct avs_dev * adev)127*af1c968dSCezary Rojewski static void avs_mtl_ipc_interrupt(struct avs_dev *adev)
128*af1c968dSCezary Rojewski {
129*af1c968dSCezary Rojewski 	const struct avs_spec *spec = adev->spec;
130*af1c968dSCezary Rojewski 	u32 hipc_ack, hipc_rsp;
131*af1c968dSCezary Rojewski 
132*af1c968dSCezary Rojewski 	snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
133*af1c968dSCezary Rojewski 			      AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0);
134*af1c968dSCezary Rojewski 
135*af1c968dSCezary Rojewski 	hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset);
136*af1c968dSCezary Rojewski 	hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset);
137*af1c968dSCezary Rojewski 
138*af1c968dSCezary Rojewski 	/* DSP acked host's request. */
139*af1c968dSCezary Rojewski 	if (hipc_ack & spec->hipc->ack_done_mask) {
140*af1c968dSCezary Rojewski 		complete(&adev->ipc->done_completion);
141*af1c968dSCezary Rojewski 
142*af1c968dSCezary Rojewski 		/* Tell DSP it has our attention. */
143*af1c968dSCezary Rojewski 		snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask,
144*af1c968dSCezary Rojewski 				      spec->hipc->ack_done_mask);
145*af1c968dSCezary Rojewski 	}
146*af1c968dSCezary Rojewski 
147*af1c968dSCezary Rojewski 	/* DSP sent new response to process. */
148*af1c968dSCezary Rojewski 	if (hipc_rsp & spec->hipc->rsp_busy_mask) {
149*af1c968dSCezary Rojewski 		union avs_reply_msg msg;
150*af1c968dSCezary Rojewski 
151*af1c968dSCezary Rojewski 		msg.primary = snd_hdac_adsp_readl(adev, MTL_REG_HfIPCxTDR);
152*af1c968dSCezary Rojewski 		msg.ext.val = snd_hdac_adsp_readl(adev, MTL_REG_HfIPCxTDD);
153*af1c968dSCezary Rojewski 
154*af1c968dSCezary Rojewski 		avs_dsp_process_response(adev, msg.val);
155*af1c968dSCezary Rojewski 
156*af1c968dSCezary Rojewski 		/* Tell DSP we accepted its message. */
157*af1c968dSCezary Rojewski 		snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxTDR,
158*af1c968dSCezary Rojewski 				      MTL_HfIPCxTDR_BUSY, MTL_HfIPCxTDR_BUSY);
159*af1c968dSCezary Rojewski 		/* Ack this response. */
160*af1c968dSCezary Rojewski 		snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxTDA, MTL_HfIPCxTDA_BUSY, 0);
161*af1c968dSCezary Rojewski 	}
162*af1c968dSCezary Rojewski 
163*af1c968dSCezary Rojewski 	snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
164*af1c968dSCezary Rojewski 			      AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY,
165*af1c968dSCezary Rojewski 			      AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY);
166*af1c968dSCezary Rojewski }
167*af1c968dSCezary Rojewski 
avs_mtl_dsp_interrupt(struct avs_dev * adev)168*af1c968dSCezary Rojewski irqreturn_t avs_mtl_dsp_interrupt(struct avs_dev *adev)
169*af1c968dSCezary Rojewski {
170*af1c968dSCezary Rojewski 	u32 adspis = snd_hdac_adsp_readl(adev, MTL_DWICTL_REG_FINALSTATUSL);
171*af1c968dSCezary Rojewski 	irqreturn_t ret = IRQ_NONE;
172*af1c968dSCezary Rojewski 
173*af1c968dSCezary Rojewski 	if (adspis == UINT_MAX)
174*af1c968dSCezary Rojewski 		return ret;
175*af1c968dSCezary Rojewski 
176*af1c968dSCezary Rojewski 	if (adspis & MTL_DWICTL_FINALSTATUSL_IPC) {
177*af1c968dSCezary Rojewski 		avs_mtl_ipc_interrupt(adev);
178*af1c968dSCezary Rojewski 		ret = IRQ_HANDLED;
179*af1c968dSCezary Rojewski 	}
180*af1c968dSCezary Rojewski 
181*af1c968dSCezary Rojewski 	return ret;
182*af1c968dSCezary Rojewski }
183*af1c968dSCezary Rojewski 
avs_mtl_interrupt_control(struct avs_dev * adev,bool enable)184*af1c968dSCezary Rojewski void avs_mtl_interrupt_control(struct avs_dev *adev, bool enable)
185*af1c968dSCezary Rojewski {
186*af1c968dSCezary Rojewski 	if (enable) {
187*af1c968dSCezary Rojewski 		snd_hdac_adsp_updatel(adev, MTL_DWICTL_REG_INTENL, MTL_DWICTL_INTENL_IE,
188*af1c968dSCezary Rojewski 				      MTL_DWICTL_INTENL_IE);
189*af1c968dSCezary Rojewski 		snd_hdac_adsp_updatew(adev, MTL_REG_HfHIPCIE, MTL_HfHIPCIE_IE, MTL_HfHIPCIE_IE);
190*af1c968dSCezary Rojewski 		snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_DONE,
191*af1c968dSCezary Rojewski 				      AVS_ADSP_HIPCCTL_DONE);
192*af1c968dSCezary Rojewski 		snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_BUSY,
193*af1c968dSCezary Rojewski 				      AVS_ADSP_HIPCCTL_BUSY);
194*af1c968dSCezary Rojewski 	} else {
195*af1c968dSCezary Rojewski 		snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_BUSY, 0);
196*af1c968dSCezary Rojewski 		snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_DONE, 0);
197*af1c968dSCezary Rojewski 		snd_hdac_adsp_updatew(adev, MTL_REG_HfHIPCIE, MTL_HfHIPCIE_IE, 0);
198*af1c968dSCezary Rojewski 		snd_hdac_adsp_updatel(adev, MTL_DWICTL_REG_INTENL, MTL_DWICTL_INTENL_IE, 0);
199*af1c968dSCezary Rojewski 	}
200*af1c968dSCezary Rojewski }
201