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