xref: /openbsd-src/sys/dev/pci/drm/i915/display/intel_audio.c (revision f6d48bfef753f50ff588f15b25ad7fce03be0434)
1c349dbc7Sjsg /*
2c349dbc7Sjsg  * Copyright © 2014 Intel Corporation
3c349dbc7Sjsg  *
4c349dbc7Sjsg  * Permission is hereby granted, free of charge, to any person obtaining a
5c349dbc7Sjsg  * copy of this software and associated documentation files (the "Software"),
6c349dbc7Sjsg  * to deal in the Software without restriction, including without limitation
7c349dbc7Sjsg  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c349dbc7Sjsg  * and/or sell copies of the Software, and to permit persons to whom the
9c349dbc7Sjsg  * Software is furnished to do so, subject to the following conditions:
10c349dbc7Sjsg  *
11c349dbc7Sjsg  * The above copyright notice and this permission notice (including the next
12c349dbc7Sjsg  * paragraph) shall be included in all copies or substantial portions of the
13c349dbc7Sjsg  * Software.
14c349dbc7Sjsg  *
15c349dbc7Sjsg  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16c349dbc7Sjsg  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17c349dbc7Sjsg  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18c349dbc7Sjsg  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19c349dbc7Sjsg  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20c349dbc7Sjsg  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21c349dbc7Sjsg  * DEALINGS IN THE SOFTWARE.
22c349dbc7Sjsg  */
23c349dbc7Sjsg 
24c349dbc7Sjsg #include <linux/component.h>
25c349dbc7Sjsg #include <linux/kernel.h>
26c349dbc7Sjsg 
27c349dbc7Sjsg #include <drm/drm_edid.h>
28c349dbc7Sjsg #include <drm/i915_component.h>
29c349dbc7Sjsg 
30c349dbc7Sjsg #include "i915_drv.h"
31c349dbc7Sjsg #include "intel_atomic.h"
32c349dbc7Sjsg #include "intel_audio.h"
331bb76ff1Sjsg #include "intel_audio_regs.h"
34c349dbc7Sjsg #include "intel_cdclk.h"
351bb76ff1Sjsg #include "intel_crtc.h"
365ca02815Sjsg #include "intel_de.h"
37c349dbc7Sjsg #include "intel_display_types.h"
38c349dbc7Sjsg #include "intel_lpe_audio.h"
39c349dbc7Sjsg 
40c349dbc7Sjsg /**
41c349dbc7Sjsg  * DOC: High Definition Audio over HDMI and Display Port
42c349dbc7Sjsg  *
43c349dbc7Sjsg  * The graphics and audio drivers together support High Definition Audio over
44c349dbc7Sjsg  * HDMI and Display Port. The audio programming sequences are divided into audio
45c349dbc7Sjsg  * codec and controller enable and disable sequences. The graphics driver
46c349dbc7Sjsg  * handles the audio codec sequences, while the audio driver handles the audio
47c349dbc7Sjsg  * controller sequences.
48c349dbc7Sjsg  *
49c349dbc7Sjsg  * The disable sequences must be performed before disabling the transcoder or
50c349dbc7Sjsg  * port. The enable sequences may only be performed after enabling the
51c349dbc7Sjsg  * transcoder and port, and after completed link training. Therefore the audio
52c349dbc7Sjsg  * enable/disable sequences are part of the modeset sequence.
53c349dbc7Sjsg  *
54c349dbc7Sjsg  * The codec and controller sequences could be done either parallel or serial,
55c349dbc7Sjsg  * but generally the ELDV/PD change in the codec sequence indicates to the audio
56c349dbc7Sjsg  * driver that the controller sequence should start. Indeed, most of the
57c349dbc7Sjsg  * co-operation between the graphics and audio drivers is handled via audio
58c349dbc7Sjsg  * related registers. (The notable exception is the power management, not
59c349dbc7Sjsg  * covered here.)
60c349dbc7Sjsg  *
61c349dbc7Sjsg  * The struct &i915_audio_component is used to interact between the graphics
62c349dbc7Sjsg  * and audio drivers. The struct &i915_audio_component_ops @ops in it is
63c349dbc7Sjsg  * defined in graphics driver and called in audio driver. The
64c349dbc7Sjsg  * struct &i915_audio_component_audio_ops @audio_ops is called from i915 driver.
65c349dbc7Sjsg  */
66c349dbc7Sjsg 
671bb76ff1Sjsg struct intel_audio_funcs {
681bb76ff1Sjsg 	void (*audio_codec_enable)(struct intel_encoder *encoder,
691bb76ff1Sjsg 				   const struct intel_crtc_state *crtc_state,
701bb76ff1Sjsg 				   const struct drm_connector_state *conn_state);
711bb76ff1Sjsg 	void (*audio_codec_disable)(struct intel_encoder *encoder,
721bb76ff1Sjsg 				    const struct intel_crtc_state *old_crtc_state,
731bb76ff1Sjsg 				    const struct drm_connector_state *old_conn_state);
74f005ef32Sjsg 	void (*audio_codec_get_config)(struct intel_encoder *encoder,
75f005ef32Sjsg 				       struct intel_crtc_state *crtc_state);
761bb76ff1Sjsg };
771bb76ff1Sjsg 
78c349dbc7Sjsg struct hdmi_aud_ncts {
79c349dbc7Sjsg 	int sample_rate;
80c349dbc7Sjsg 	int clock;
81c349dbc7Sjsg 	int n;
82c349dbc7Sjsg 	int cts;
83c349dbc7Sjsg };
84c349dbc7Sjsg 
85c349dbc7Sjsg static const struct {
86c349dbc7Sjsg 	int clock;
87c349dbc7Sjsg 	u32 config;
88c349dbc7Sjsg } hdmi_audio_clock[] = {
89c349dbc7Sjsg 	{ 25175, AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 },
90c349dbc7Sjsg 	{ 25200, AUD_CONFIG_PIXEL_CLOCK_HDMI_25200 }, /* default per bspec */
91c349dbc7Sjsg 	{ 27000, AUD_CONFIG_PIXEL_CLOCK_HDMI_27000 },
92c349dbc7Sjsg 	{ 27027, AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 },
93c349dbc7Sjsg 	{ 54000, AUD_CONFIG_PIXEL_CLOCK_HDMI_54000 },
94c349dbc7Sjsg 	{ 54054, AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 },
95c349dbc7Sjsg 	{ 74176, AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 },
96c349dbc7Sjsg 	{ 74250, AUD_CONFIG_PIXEL_CLOCK_HDMI_74250 },
97c349dbc7Sjsg 	{ 148352, AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 },
98c349dbc7Sjsg 	{ 148500, AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 },
99c349dbc7Sjsg 	{ 296703, AUD_CONFIG_PIXEL_CLOCK_HDMI_296703 },
100c349dbc7Sjsg 	{ 297000, AUD_CONFIG_PIXEL_CLOCK_HDMI_297000 },
101c349dbc7Sjsg 	{ 593407, AUD_CONFIG_PIXEL_CLOCK_HDMI_593407 },
102c349dbc7Sjsg 	{ 594000, AUD_CONFIG_PIXEL_CLOCK_HDMI_594000 },
103c349dbc7Sjsg };
104c349dbc7Sjsg 
105c349dbc7Sjsg /* HDMI N/CTS table */
106c349dbc7Sjsg #define TMDS_297M 297000
107c349dbc7Sjsg #define TMDS_296M 296703
108c349dbc7Sjsg #define TMDS_594M 594000
109c349dbc7Sjsg #define TMDS_593M 593407
110c349dbc7Sjsg 
111c349dbc7Sjsg static const struct hdmi_aud_ncts hdmi_aud_ncts_24bpp[] = {
112c349dbc7Sjsg 	{ 32000, TMDS_296M, 5824, 421875 },
113c349dbc7Sjsg 	{ 32000, TMDS_297M, 3072, 222750 },
114c349dbc7Sjsg 	{ 32000, TMDS_593M, 5824, 843750 },
115c349dbc7Sjsg 	{ 32000, TMDS_594M, 3072, 445500 },
116c349dbc7Sjsg 	{ 44100, TMDS_296M, 4459, 234375 },
117c349dbc7Sjsg 	{ 44100, TMDS_297M, 4704, 247500 },
118c349dbc7Sjsg 	{ 44100, TMDS_593M, 8918, 937500 },
119c349dbc7Sjsg 	{ 44100, TMDS_594M, 9408, 990000 },
120c349dbc7Sjsg 	{ 88200, TMDS_296M, 8918, 234375 },
121c349dbc7Sjsg 	{ 88200, TMDS_297M, 9408, 247500 },
122c349dbc7Sjsg 	{ 88200, TMDS_593M, 17836, 937500 },
123c349dbc7Sjsg 	{ 88200, TMDS_594M, 18816, 990000 },
124c349dbc7Sjsg 	{ 176400, TMDS_296M, 17836, 234375 },
125c349dbc7Sjsg 	{ 176400, TMDS_297M, 18816, 247500 },
126c349dbc7Sjsg 	{ 176400, TMDS_593M, 35672, 937500 },
127c349dbc7Sjsg 	{ 176400, TMDS_594M, 37632, 990000 },
128c349dbc7Sjsg 	{ 48000, TMDS_296M, 5824, 281250 },
129c349dbc7Sjsg 	{ 48000, TMDS_297M, 5120, 247500 },
130c349dbc7Sjsg 	{ 48000, TMDS_593M, 5824, 562500 },
131c349dbc7Sjsg 	{ 48000, TMDS_594M, 6144, 594000 },
132c349dbc7Sjsg 	{ 96000, TMDS_296M, 11648, 281250 },
133c349dbc7Sjsg 	{ 96000, TMDS_297M, 10240, 247500 },
134c349dbc7Sjsg 	{ 96000, TMDS_593M, 11648, 562500 },
135c349dbc7Sjsg 	{ 96000, TMDS_594M, 12288, 594000 },
136c349dbc7Sjsg 	{ 192000, TMDS_296M, 23296, 281250 },
137c349dbc7Sjsg 	{ 192000, TMDS_297M, 20480, 247500 },
138c349dbc7Sjsg 	{ 192000, TMDS_593M, 23296, 562500 },
139c349dbc7Sjsg 	{ 192000, TMDS_594M, 24576, 594000 },
140c349dbc7Sjsg };
141c349dbc7Sjsg 
142c349dbc7Sjsg /* Appendix C - N & CTS values for deep color from HDMI 2.0 spec*/
143c349dbc7Sjsg /* HDMI N/CTS table for 10 bit deep color(30 bpp)*/
144c349dbc7Sjsg #define TMDS_371M 371250
145c349dbc7Sjsg #define TMDS_370M 370878
146c349dbc7Sjsg 
147c349dbc7Sjsg static const struct hdmi_aud_ncts hdmi_aud_ncts_30bpp[] = {
148c349dbc7Sjsg 	{ 32000, TMDS_370M, 5824, 527344 },
149c349dbc7Sjsg 	{ 32000, TMDS_371M, 6144, 556875 },
150c349dbc7Sjsg 	{ 44100, TMDS_370M, 8918, 585938 },
151c349dbc7Sjsg 	{ 44100, TMDS_371M, 4704, 309375 },
152c349dbc7Sjsg 	{ 88200, TMDS_370M, 17836, 585938 },
153c349dbc7Sjsg 	{ 88200, TMDS_371M, 9408, 309375 },
154c349dbc7Sjsg 	{ 176400, TMDS_370M, 35672, 585938 },
155c349dbc7Sjsg 	{ 176400, TMDS_371M, 18816, 309375 },
156c349dbc7Sjsg 	{ 48000, TMDS_370M, 11648, 703125 },
157c349dbc7Sjsg 	{ 48000, TMDS_371M, 5120, 309375 },
158c349dbc7Sjsg 	{ 96000, TMDS_370M, 23296, 703125 },
159c349dbc7Sjsg 	{ 96000, TMDS_371M, 10240, 309375 },
160c349dbc7Sjsg 	{ 192000, TMDS_370M, 46592, 703125 },
161c349dbc7Sjsg 	{ 192000, TMDS_371M, 20480, 309375 },
162c349dbc7Sjsg };
163c349dbc7Sjsg 
164c349dbc7Sjsg /* HDMI N/CTS table for 12 bit deep color(36 bpp)*/
165c349dbc7Sjsg #define TMDS_445_5M 445500
166c349dbc7Sjsg #define TMDS_445M 445054
167c349dbc7Sjsg 
168c349dbc7Sjsg static const struct hdmi_aud_ncts hdmi_aud_ncts_36bpp[] = {
169c349dbc7Sjsg 	{ 32000, TMDS_445M, 5824, 632813 },
170c349dbc7Sjsg 	{ 32000, TMDS_445_5M, 4096, 445500 },
171c349dbc7Sjsg 	{ 44100, TMDS_445M, 8918, 703125 },
172c349dbc7Sjsg 	{ 44100, TMDS_445_5M, 4704, 371250 },
173c349dbc7Sjsg 	{ 88200, TMDS_445M, 17836, 703125 },
174c349dbc7Sjsg 	{ 88200, TMDS_445_5M, 9408, 371250 },
175c349dbc7Sjsg 	{ 176400, TMDS_445M, 35672, 703125 },
176c349dbc7Sjsg 	{ 176400, TMDS_445_5M, 18816, 371250 },
177c349dbc7Sjsg 	{ 48000, TMDS_445M, 5824, 421875 },
178c349dbc7Sjsg 	{ 48000, TMDS_445_5M, 5120, 371250 },
179c349dbc7Sjsg 	{ 96000, TMDS_445M, 11648, 421875 },
180c349dbc7Sjsg 	{ 96000, TMDS_445_5M, 10240, 371250 },
181c349dbc7Sjsg 	{ 192000, TMDS_445M, 23296, 421875 },
182c349dbc7Sjsg 	{ 192000, TMDS_445_5M, 20480, 371250 },
183c349dbc7Sjsg };
184c349dbc7Sjsg 
185c349dbc7Sjsg /* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */
audio_config_hdmi_pixel_clock(const struct intel_crtc_state * crtc_state)186c349dbc7Sjsg static u32 audio_config_hdmi_pixel_clock(const struct intel_crtc_state *crtc_state)
187c349dbc7Sjsg {
188f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
189c349dbc7Sjsg 	const struct drm_display_mode *adjusted_mode =
190c349dbc7Sjsg 		&crtc_state->hw.adjusted_mode;
191c349dbc7Sjsg 	int i;
192c349dbc7Sjsg 
193c349dbc7Sjsg 	for (i = 0; i < ARRAY_SIZE(hdmi_audio_clock); i++) {
194c349dbc7Sjsg 		if (adjusted_mode->crtc_clock == hdmi_audio_clock[i].clock)
195c349dbc7Sjsg 			break;
196c349dbc7Sjsg 	}
197c349dbc7Sjsg 
198f005ef32Sjsg 	if (DISPLAY_VER(i915) < 12 && adjusted_mode->crtc_clock > 148500)
199c349dbc7Sjsg 		i = ARRAY_SIZE(hdmi_audio_clock);
200c349dbc7Sjsg 
201c349dbc7Sjsg 	if (i == ARRAY_SIZE(hdmi_audio_clock)) {
202f005ef32Sjsg 		drm_dbg_kms(&i915->drm,
203ad8b1aafSjsg 			    "HDMI audio pixel clock setting for %d not found, falling back to defaults\n",
204c349dbc7Sjsg 			    adjusted_mode->crtc_clock);
205c349dbc7Sjsg 		i = 1;
206c349dbc7Sjsg 	}
207c349dbc7Sjsg 
208f005ef32Sjsg 	drm_dbg_kms(&i915->drm,
209ad8b1aafSjsg 		    "Configuring HDMI audio for pixel clock %d (0x%08x)\n",
210c349dbc7Sjsg 		    hdmi_audio_clock[i].clock,
211c349dbc7Sjsg 		    hdmi_audio_clock[i].config);
212c349dbc7Sjsg 
213c349dbc7Sjsg 	return hdmi_audio_clock[i].config;
214c349dbc7Sjsg }
215c349dbc7Sjsg 
audio_config_hdmi_get_n(const struct intel_crtc_state * crtc_state,int rate)216c349dbc7Sjsg static int audio_config_hdmi_get_n(const struct intel_crtc_state *crtc_state,
217c349dbc7Sjsg 				   int rate)
218c349dbc7Sjsg {
219c349dbc7Sjsg 	const struct hdmi_aud_ncts *hdmi_ncts_table;
220c349dbc7Sjsg 	int i, size;
221c349dbc7Sjsg 
222c349dbc7Sjsg 	if (crtc_state->pipe_bpp == 36) {
223c349dbc7Sjsg 		hdmi_ncts_table = hdmi_aud_ncts_36bpp;
224c349dbc7Sjsg 		size = ARRAY_SIZE(hdmi_aud_ncts_36bpp);
225c349dbc7Sjsg 	} else if (crtc_state->pipe_bpp == 30) {
226c349dbc7Sjsg 		hdmi_ncts_table = hdmi_aud_ncts_30bpp;
227c349dbc7Sjsg 		size = ARRAY_SIZE(hdmi_aud_ncts_30bpp);
228c349dbc7Sjsg 	} else {
229c349dbc7Sjsg 		hdmi_ncts_table = hdmi_aud_ncts_24bpp;
230c349dbc7Sjsg 		size = ARRAY_SIZE(hdmi_aud_ncts_24bpp);
231c349dbc7Sjsg 	}
232c349dbc7Sjsg 
233c349dbc7Sjsg 	for (i = 0; i < size; i++) {
234c349dbc7Sjsg 		if (rate == hdmi_ncts_table[i].sample_rate &&
235c349dbc7Sjsg 		    crtc_state->port_clock == hdmi_ncts_table[i].clock) {
236c349dbc7Sjsg 			return hdmi_ncts_table[i].n;
237c349dbc7Sjsg 		}
238c349dbc7Sjsg 	}
239c349dbc7Sjsg 	return 0;
240c349dbc7Sjsg }
241c349dbc7Sjsg 
242f005ef32Sjsg /* ELD buffer size in dwords */
g4x_eld_buffer_size(struct drm_i915_private * i915)243f005ef32Sjsg static int g4x_eld_buffer_size(struct drm_i915_private *i915)
244c349dbc7Sjsg {
245c349dbc7Sjsg 	u32 tmp;
246c349dbc7Sjsg 
247f005ef32Sjsg 	tmp = intel_de_read(i915, G4X_AUD_CNTL_ST);
248c349dbc7Sjsg 
249f005ef32Sjsg 	return REG_FIELD_GET(G4X_ELD_BUFFER_SIZE_MASK, tmp);
250f005ef32Sjsg }
251c349dbc7Sjsg 
g4x_audio_codec_get_config(struct intel_encoder * encoder,struct intel_crtc_state * crtc_state)252f005ef32Sjsg static void g4x_audio_codec_get_config(struct intel_encoder *encoder,
253f005ef32Sjsg 				       struct intel_crtc_state *crtc_state)
254f005ef32Sjsg {
255f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
256f005ef32Sjsg 	u32 *eld = (u32 *)crtc_state->eld;
257f005ef32Sjsg 	int eld_buffer_size, len, i;
258f005ef32Sjsg 	u32 tmp;
259c349dbc7Sjsg 
260f005ef32Sjsg 	tmp = intel_de_read(i915, G4X_AUD_CNTL_ST);
261f005ef32Sjsg 	if ((tmp & G4X_ELD_VALID) == 0)
262f005ef32Sjsg 		return;
263c349dbc7Sjsg 
264f005ef32Sjsg 	intel_de_rmw(i915, G4X_AUD_CNTL_ST, G4X_ELD_ADDRESS_MASK, 0);
265f005ef32Sjsg 
266f005ef32Sjsg 	eld_buffer_size = g4x_eld_buffer_size(i915);
267f005ef32Sjsg 	len = min_t(int, sizeof(crtc_state->eld) / 4, eld_buffer_size);
268f005ef32Sjsg 
269f005ef32Sjsg 	for (i = 0; i < len; i++)
270f005ef32Sjsg 		eld[i] = intel_de_read(i915, G4X_HDMIW_HDMIEDID);
271c349dbc7Sjsg }
272c349dbc7Sjsg 
g4x_audio_codec_disable(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)273c349dbc7Sjsg static void g4x_audio_codec_disable(struct intel_encoder *encoder,
274c349dbc7Sjsg 				    const struct intel_crtc_state *old_crtc_state,
275c349dbc7Sjsg 				    const struct drm_connector_state *old_conn_state)
276c349dbc7Sjsg {
277f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
278f005ef32Sjsg 	struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
279c349dbc7Sjsg 
280c349dbc7Sjsg 	/* Invalidate ELD */
281f005ef32Sjsg 	intel_de_rmw(i915, G4X_AUD_CNTL_ST,
282f005ef32Sjsg 		     G4X_ELD_VALID, 0);
283f005ef32Sjsg 
284f005ef32Sjsg 	intel_crtc_wait_for_next_vblank(crtc);
285f005ef32Sjsg 	intel_crtc_wait_for_next_vblank(crtc);
286c349dbc7Sjsg }
287c349dbc7Sjsg 
g4x_audio_codec_enable(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)288c349dbc7Sjsg static void g4x_audio_codec_enable(struct intel_encoder *encoder,
289c349dbc7Sjsg 				   const struct intel_crtc_state *crtc_state,
290c349dbc7Sjsg 				   const struct drm_connector_state *conn_state)
291c349dbc7Sjsg {
292f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
293f005ef32Sjsg 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
294f005ef32Sjsg 	const u32 *eld = (const u32 *)crtc_state->eld;
295f005ef32Sjsg 	int eld_buffer_size, len, i;
296c349dbc7Sjsg 
297f005ef32Sjsg 	intel_crtc_wait_for_next_vblank(crtc);
298c349dbc7Sjsg 
299f005ef32Sjsg 	intel_de_rmw(i915, G4X_AUD_CNTL_ST,
300f005ef32Sjsg 		     G4X_ELD_VALID | G4X_ELD_ADDRESS_MASK, 0);
301c349dbc7Sjsg 
302f005ef32Sjsg 	eld_buffer_size = g4x_eld_buffer_size(i915);
303f005ef32Sjsg 	len = min(drm_eld_size(crtc_state->eld) / 4, eld_buffer_size);
304c349dbc7Sjsg 
305c349dbc7Sjsg 	for (i = 0; i < len; i++)
306f005ef32Sjsg 		intel_de_write(i915, G4X_HDMIW_HDMIEDID, eld[i]);
307f005ef32Sjsg 	for (; i < eld_buffer_size; i++)
308f005ef32Sjsg 		intel_de_write(i915, G4X_HDMIW_HDMIEDID, 0);
309c349dbc7Sjsg 
310f005ef32Sjsg 	drm_WARN_ON(&i915->drm,
311f005ef32Sjsg 		    (intel_de_read(i915, G4X_AUD_CNTL_ST) & G4X_ELD_ADDRESS_MASK) != 0);
312f005ef32Sjsg 
313f005ef32Sjsg 	intel_de_rmw(i915, G4X_AUD_CNTL_ST,
314f005ef32Sjsg 		     0, G4X_ELD_VALID);
315c349dbc7Sjsg }
316c349dbc7Sjsg 
317c349dbc7Sjsg static void
hsw_dp_audio_config_update(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)318c349dbc7Sjsg hsw_dp_audio_config_update(struct intel_encoder *encoder,
319c349dbc7Sjsg 			   const struct intel_crtc_state *crtc_state)
320c349dbc7Sjsg {
321f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
322c349dbc7Sjsg 	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
323c349dbc7Sjsg 
324b57ef33fSjsg 	/* Enable time stamps. Let HW calculate Maud/Naud values */
325b57ef33fSjsg 	intel_de_rmw(i915, HSW_AUD_CFG(cpu_transcoder),
326b57ef33fSjsg 		     AUD_CONFIG_N_VALUE_INDEX |
327b57ef33fSjsg 		     AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK |
328b57ef33fSjsg 		     AUD_CONFIG_UPPER_N_MASK |
329b57ef33fSjsg 		     AUD_CONFIG_LOWER_N_MASK |
330b57ef33fSjsg 		     AUD_CONFIG_N_PROG_ENABLE,
331b57ef33fSjsg 		     AUD_CONFIG_N_VALUE_INDEX);
332c349dbc7Sjsg 
333c349dbc7Sjsg }
334c349dbc7Sjsg 
335c349dbc7Sjsg static void
hsw_hdmi_audio_config_update(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)336c349dbc7Sjsg hsw_hdmi_audio_config_update(struct intel_encoder *encoder,
337c349dbc7Sjsg 			     const struct intel_crtc_state *crtc_state)
338c349dbc7Sjsg {
339f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
340f005ef32Sjsg 	struct i915_audio_component *acomp = i915->display.audio.component;
341c349dbc7Sjsg 	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
342c349dbc7Sjsg 	enum port port = encoder->port;
343c349dbc7Sjsg 	int n, rate;
344c349dbc7Sjsg 	u32 tmp;
345c349dbc7Sjsg 
346c349dbc7Sjsg 	rate = acomp ? acomp->aud_sample_rate[port] : 0;
347c349dbc7Sjsg 
348f005ef32Sjsg 	tmp = intel_de_read(i915, HSW_AUD_CFG(cpu_transcoder));
349c349dbc7Sjsg 	tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
350c349dbc7Sjsg 	tmp &= ~AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK;
351c349dbc7Sjsg 	tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
352c349dbc7Sjsg 	tmp |= audio_config_hdmi_pixel_clock(crtc_state);
353c349dbc7Sjsg 
354c349dbc7Sjsg 	n = audio_config_hdmi_get_n(crtc_state, rate);
355c349dbc7Sjsg 	if (n != 0) {
356f005ef32Sjsg 		drm_dbg_kms(&i915->drm, "using N %d\n", n);
357c349dbc7Sjsg 
358c349dbc7Sjsg 		tmp &= ~AUD_CONFIG_N_MASK;
359c349dbc7Sjsg 		tmp |= AUD_CONFIG_N(n);
360c349dbc7Sjsg 		tmp |= AUD_CONFIG_N_PROG_ENABLE;
361c349dbc7Sjsg 	} else {
362f005ef32Sjsg 		drm_dbg_kms(&i915->drm, "using automatic N\n");
363c349dbc7Sjsg 	}
364c349dbc7Sjsg 
365f005ef32Sjsg 	intel_de_write(i915, HSW_AUD_CFG(cpu_transcoder), tmp);
366c349dbc7Sjsg 
367c349dbc7Sjsg 	/*
368c349dbc7Sjsg 	 * Let's disable "Enable CTS or M Prog bit"
369c349dbc7Sjsg 	 * and let HW calculate the value
370c349dbc7Sjsg 	 */
371f005ef32Sjsg 	tmp = intel_de_read(i915, HSW_AUD_M_CTS_ENABLE(cpu_transcoder));
372c349dbc7Sjsg 	tmp &= ~AUD_M_CTS_M_PROG_ENABLE;
373c349dbc7Sjsg 	tmp &= ~AUD_M_CTS_M_VALUE_INDEX;
374f005ef32Sjsg 	intel_de_write(i915, HSW_AUD_M_CTS_ENABLE(cpu_transcoder), tmp);
375c349dbc7Sjsg }
376c349dbc7Sjsg 
377c349dbc7Sjsg static void
hsw_audio_config_update(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)378c349dbc7Sjsg hsw_audio_config_update(struct intel_encoder *encoder,
379c349dbc7Sjsg 			const struct intel_crtc_state *crtc_state)
380c349dbc7Sjsg {
381c349dbc7Sjsg 	if (intel_crtc_has_dp_encoder(crtc_state))
382c349dbc7Sjsg 		hsw_dp_audio_config_update(encoder, crtc_state);
383c349dbc7Sjsg 	else
384c349dbc7Sjsg 		hsw_hdmi_audio_config_update(encoder, crtc_state);
385c349dbc7Sjsg }
386c349dbc7Sjsg 
hsw_audio_codec_disable(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)387c349dbc7Sjsg static void hsw_audio_codec_disable(struct intel_encoder *encoder,
388c349dbc7Sjsg 				    const struct intel_crtc_state *old_crtc_state,
389c349dbc7Sjsg 				    const struct drm_connector_state *old_conn_state)
390c349dbc7Sjsg {
391f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
392f005ef32Sjsg 	struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
393c349dbc7Sjsg 	enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;
394c349dbc7Sjsg 
395f005ef32Sjsg 	mutex_lock(&i915->display.audio.mutex);
396c349dbc7Sjsg 
397c349dbc7Sjsg 	/* Disable timestamps */
398f005ef32Sjsg 	intel_de_rmw(i915, HSW_AUD_CFG(cpu_transcoder),
399f005ef32Sjsg 		     AUD_CONFIG_N_VALUE_INDEX |
400f005ef32Sjsg 		     AUD_CONFIG_UPPER_N_MASK |
401f005ef32Sjsg 		     AUD_CONFIG_LOWER_N_MASK,
402f005ef32Sjsg 		     AUD_CONFIG_N_PROG_ENABLE |
403f005ef32Sjsg 		     (intel_crtc_has_dp_encoder(old_crtc_state) ?
404f005ef32Sjsg 		      AUD_CONFIG_N_VALUE_INDEX : 0));
405c349dbc7Sjsg 
406c349dbc7Sjsg 	/* Invalidate ELD */
407f005ef32Sjsg 	intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD,
408f005ef32Sjsg 		     AUDIO_ELD_VALID(cpu_transcoder), 0);
409c349dbc7Sjsg 
410f005ef32Sjsg 	intel_crtc_wait_for_next_vblank(crtc);
411f005ef32Sjsg 	intel_crtc_wait_for_next_vblank(crtc);
412f005ef32Sjsg 
413f005ef32Sjsg 	/* Disable audio presence detect */
414f005ef32Sjsg 	intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD,
415f005ef32Sjsg 		     AUDIO_OUTPUT_ENABLE(cpu_transcoder), 0);
416f005ef32Sjsg 
417f005ef32Sjsg 	mutex_unlock(&i915->display.audio.mutex);
418c349dbc7Sjsg }
419c349dbc7Sjsg 
calc_hblank_early_prog(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)420ad8b1aafSjsg static unsigned int calc_hblank_early_prog(struct intel_encoder *encoder,
421ad8b1aafSjsg 					   const struct intel_crtc_state *crtc_state)
422ad8b1aafSjsg {
423ad8b1aafSjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
424ad8b1aafSjsg 	unsigned int link_clks_available, link_clks_required;
425ad8b1aafSjsg 	unsigned int tu_data, tu_line, link_clks_active;
426ad8b1aafSjsg 	unsigned int h_active, h_total, hblank_delta, pixel_clk;
427ad8b1aafSjsg 	unsigned int fec_coeff, cdclk, vdsc_bpp;
428ad8b1aafSjsg 	unsigned int link_clk, lanes;
429ad8b1aafSjsg 	unsigned int hblank_rise;
430ad8b1aafSjsg 
431ad8b1aafSjsg 	h_active = crtc_state->hw.adjusted_mode.crtc_hdisplay;
432ad8b1aafSjsg 	h_total = crtc_state->hw.adjusted_mode.crtc_htotal;
433ad8b1aafSjsg 	pixel_clk = crtc_state->hw.adjusted_mode.crtc_clock;
434ad8b1aafSjsg 	vdsc_bpp = crtc_state->dsc.compressed_bpp;
4351bb76ff1Sjsg 	cdclk = i915->display.cdclk.hw.cdclk;
436ad8b1aafSjsg 	/* fec= 0.972261, using rounding multiplier of 1000000 */
437ad8b1aafSjsg 	fec_coeff = 972261;
438ad8b1aafSjsg 	link_clk = crtc_state->port_clock;
439ad8b1aafSjsg 	lanes = crtc_state->lane_count;
440ad8b1aafSjsg 
441ad8b1aafSjsg 	drm_dbg_kms(&i915->drm, "h_active = %u link_clk = %u :"
442ad8b1aafSjsg 		    "lanes = %u vdsc_bpp = %u cdclk = %u\n",
443ad8b1aafSjsg 		    h_active, link_clk, lanes, vdsc_bpp, cdclk);
444ad8b1aafSjsg 
445ad8b1aafSjsg 	if (WARN_ON(!link_clk || !pixel_clk || !lanes || !vdsc_bpp || !cdclk))
446ad8b1aafSjsg 		return 0;
447ad8b1aafSjsg 
448ad8b1aafSjsg 	link_clks_available = (h_total - h_active) * link_clk / pixel_clk - 28;
449ad8b1aafSjsg 	link_clks_required = DIV_ROUND_UP(192000 * h_total, 1000 * pixel_clk) * (48 / lanes + 2);
450ad8b1aafSjsg 
451ad8b1aafSjsg 	if (link_clks_available > link_clks_required)
452ad8b1aafSjsg 		hblank_delta = 32;
453ad8b1aafSjsg 	else
454ad8b1aafSjsg 		hblank_delta = DIV64_U64_ROUND_UP(mul_u32_u32(5 * (link_clk + cdclk), pixel_clk),
455ad8b1aafSjsg 						  mul_u32_u32(link_clk, cdclk));
456ad8b1aafSjsg 
457ad8b1aafSjsg 	tu_data = div64_u64(mul_u32_u32(pixel_clk * vdsc_bpp * 8, 1000000),
458ad8b1aafSjsg 			    mul_u32_u32(link_clk * lanes, fec_coeff));
459ad8b1aafSjsg 	tu_line = div64_u64(h_active * mul_u32_u32(link_clk, fec_coeff),
460ad8b1aafSjsg 			    mul_u32_u32(64 * pixel_clk, 1000000));
461ad8b1aafSjsg 	link_clks_active  = (tu_line - 1) * 64 + tu_data;
462ad8b1aafSjsg 
463ad8b1aafSjsg 	hblank_rise = (link_clks_active + 6 * DIV_ROUND_UP(link_clks_active, 250) + 4) * pixel_clk / link_clk;
464ad8b1aafSjsg 
465ad8b1aafSjsg 	return h_active - hblank_rise + hblank_delta;
466ad8b1aafSjsg }
467ad8b1aafSjsg 
calc_samples_room(const struct intel_crtc_state * crtc_state)468ad8b1aafSjsg static unsigned int calc_samples_room(const struct intel_crtc_state *crtc_state)
469ad8b1aafSjsg {
470ad8b1aafSjsg 	unsigned int h_active, h_total, pixel_clk;
471ad8b1aafSjsg 	unsigned int link_clk, lanes;
472ad8b1aafSjsg 
473ad8b1aafSjsg 	h_active = crtc_state->hw.adjusted_mode.hdisplay;
474ad8b1aafSjsg 	h_total = crtc_state->hw.adjusted_mode.htotal;
475ad8b1aafSjsg 	pixel_clk = crtc_state->hw.adjusted_mode.clock;
476ad8b1aafSjsg 	link_clk = crtc_state->port_clock;
477ad8b1aafSjsg 	lanes = crtc_state->lane_count;
478ad8b1aafSjsg 
479ad8b1aafSjsg 	return ((h_total - h_active) * link_clk - 12 * pixel_clk) /
480ad8b1aafSjsg 		(pixel_clk * (48 / lanes + 2));
481ad8b1aafSjsg }
482ad8b1aafSjsg 
enable_audio_dsc_wa(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)483ad8b1aafSjsg static void enable_audio_dsc_wa(struct intel_encoder *encoder,
484ad8b1aafSjsg 				const struct intel_crtc_state *crtc_state)
485ad8b1aafSjsg {
486ad8b1aafSjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
487f005ef32Sjsg 	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
488ad8b1aafSjsg 	unsigned int hblank_early_prog, samples_room;
489ad8b1aafSjsg 	unsigned int val;
490ad8b1aafSjsg 
4915ca02815Sjsg 	if (DISPLAY_VER(i915) < 11)
492ad8b1aafSjsg 		return;
493ad8b1aafSjsg 
494ad8b1aafSjsg 	val = intel_de_read(i915, AUD_CONFIG_BE);
495ad8b1aafSjsg 
4965ca02815Sjsg 	if (DISPLAY_VER(i915) == 11)
497f005ef32Sjsg 		val |= HBLANK_EARLY_ENABLE_ICL(cpu_transcoder);
4985ca02815Sjsg 	else if (DISPLAY_VER(i915) >= 12)
499f005ef32Sjsg 		val |= HBLANK_EARLY_ENABLE_TGL(cpu_transcoder);
500ad8b1aafSjsg 
501ad8b1aafSjsg 	if (crtc_state->dsc.compression_enable &&
5025ca02815Sjsg 	    crtc_state->hw.adjusted_mode.hdisplay >= 3840 &&
5035ca02815Sjsg 	    crtc_state->hw.adjusted_mode.vdisplay >= 2160) {
504ad8b1aafSjsg 		/* Get hblank early enable value required */
505f005ef32Sjsg 		val &= ~HBLANK_START_COUNT_MASK(cpu_transcoder);
506ad8b1aafSjsg 		hblank_early_prog = calc_hblank_early_prog(encoder, crtc_state);
5075ca02815Sjsg 		if (hblank_early_prog < 32)
508f005ef32Sjsg 			val |= HBLANK_START_COUNT(cpu_transcoder, HBLANK_START_COUNT_32);
5095ca02815Sjsg 		else if (hblank_early_prog < 64)
510f005ef32Sjsg 			val |= HBLANK_START_COUNT(cpu_transcoder, HBLANK_START_COUNT_64);
5115ca02815Sjsg 		else if (hblank_early_prog < 96)
512f005ef32Sjsg 			val |= HBLANK_START_COUNT(cpu_transcoder, HBLANK_START_COUNT_96);
5135ca02815Sjsg 		else
514f005ef32Sjsg 			val |= HBLANK_START_COUNT(cpu_transcoder, HBLANK_START_COUNT_128);
515ad8b1aafSjsg 
516ad8b1aafSjsg 		/* Get samples room value required */
517f005ef32Sjsg 		val &= ~NUMBER_SAMPLES_PER_LINE_MASK(cpu_transcoder);
518ad8b1aafSjsg 		samples_room = calc_samples_room(crtc_state);
5195ca02815Sjsg 		if (samples_room < 3)
520f005ef32Sjsg 			val |= NUMBER_SAMPLES_PER_LINE(cpu_transcoder, samples_room);
5215ca02815Sjsg 		else /* Program 0 i.e "All Samples available in buffer" */
522f005ef32Sjsg 			val |= NUMBER_SAMPLES_PER_LINE(cpu_transcoder, 0x0);
523ad8b1aafSjsg 	}
524ad8b1aafSjsg 
525ad8b1aafSjsg 	intel_de_write(i915, AUD_CONFIG_BE, val);
526ad8b1aafSjsg }
527ad8b1aafSjsg 
hsw_audio_codec_enable(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)528c349dbc7Sjsg static void hsw_audio_codec_enable(struct intel_encoder *encoder,
529c349dbc7Sjsg 				   const struct intel_crtc_state *crtc_state,
530c349dbc7Sjsg 				   const struct drm_connector_state *conn_state)
531c349dbc7Sjsg {
532f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
533f005ef32Sjsg 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
534c349dbc7Sjsg 	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
535c349dbc7Sjsg 
536f005ef32Sjsg 	mutex_lock(&i915->display.audio.mutex);
537c349dbc7Sjsg 
538ad8b1aafSjsg 	/* Enable Audio WA for 4k DSC usecases */
539ad8b1aafSjsg 	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP))
540ad8b1aafSjsg 		enable_audio_dsc_wa(encoder, crtc_state);
541ad8b1aafSjsg 
542f005ef32Sjsg 	/* Enable audio presence detect */
543f005ef32Sjsg 	intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD,
544f005ef32Sjsg 		     0, AUDIO_OUTPUT_ENABLE(cpu_transcoder));
545f005ef32Sjsg 
546f005ef32Sjsg 	intel_crtc_wait_for_next_vblank(crtc);
547f005ef32Sjsg 
548f005ef32Sjsg 	/* Invalidate ELD */
549f005ef32Sjsg 	intel_de_rmw(i915, HSW_AUD_PIN_ELD_CP_VLD,
550f005ef32Sjsg 		     AUDIO_ELD_VALID(cpu_transcoder), 0);
551c349dbc7Sjsg 
552c349dbc7Sjsg 	/*
553f005ef32Sjsg 	 * The audio componenent is used to convey the ELD
554f005ef32Sjsg 	 * instead using of the hardware ELD buffer.
555c349dbc7Sjsg 	 */
556c349dbc7Sjsg 
557c349dbc7Sjsg 	/* Enable timestamps */
558c349dbc7Sjsg 	hsw_audio_config_update(encoder, crtc_state);
559c349dbc7Sjsg 
560f005ef32Sjsg 	mutex_unlock(&i915->display.audio.mutex);
561c349dbc7Sjsg }
562c349dbc7Sjsg 
563f005ef32Sjsg struct ibx_audio_regs {
564f005ef32Sjsg 	i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2;
565f005ef32Sjsg };
566f005ef32Sjsg 
ibx_audio_regs_init(struct drm_i915_private * i915,enum pipe pipe,struct ibx_audio_regs * regs)567f005ef32Sjsg static void ibx_audio_regs_init(struct drm_i915_private *i915,
568f005ef32Sjsg 				enum pipe pipe,
569f005ef32Sjsg 				struct ibx_audio_regs *regs)
570f005ef32Sjsg {
571f005ef32Sjsg 	if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
572f005ef32Sjsg 		regs->hdmiw_hdmiedid = VLV_HDMIW_HDMIEDID(pipe);
573f005ef32Sjsg 		regs->aud_config = VLV_AUD_CFG(pipe);
574f005ef32Sjsg 		regs->aud_cntl_st = VLV_AUD_CNTL_ST(pipe);
575f005ef32Sjsg 		regs->aud_cntrl_st2 = VLV_AUD_CNTL_ST2;
576f005ef32Sjsg 	} else if (HAS_PCH_CPT(i915)) {
577f005ef32Sjsg 		regs->hdmiw_hdmiedid = CPT_HDMIW_HDMIEDID(pipe);
578f005ef32Sjsg 		regs->aud_config = CPT_AUD_CFG(pipe);
579f005ef32Sjsg 		regs->aud_cntl_st = CPT_AUD_CNTL_ST(pipe);
580f005ef32Sjsg 		regs->aud_cntrl_st2 = CPT_AUD_CNTRL_ST2;
581f005ef32Sjsg 	} else if (HAS_PCH_IBX(i915)) {
582f005ef32Sjsg 		regs->hdmiw_hdmiedid = IBX_HDMIW_HDMIEDID(pipe);
583f005ef32Sjsg 		regs->aud_config = IBX_AUD_CFG(pipe);
584f005ef32Sjsg 		regs->aud_cntl_st = IBX_AUD_CNTL_ST(pipe);
585f005ef32Sjsg 		regs->aud_cntrl_st2 = IBX_AUD_CNTL_ST2;
586f005ef32Sjsg 	}
587f005ef32Sjsg }
588f005ef32Sjsg 
ibx_audio_codec_disable(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)589f005ef32Sjsg static void ibx_audio_codec_disable(struct intel_encoder *encoder,
590c349dbc7Sjsg 				    const struct intel_crtc_state *old_crtc_state,
591c349dbc7Sjsg 				    const struct drm_connector_state *old_conn_state)
592c349dbc7Sjsg {
593f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
594c349dbc7Sjsg 	struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
595c349dbc7Sjsg 	enum port port = encoder->port;
596f005ef32Sjsg 	enum pipe pipe = crtc->pipe;
597f005ef32Sjsg 	struct ibx_audio_regs regs;
598c349dbc7Sjsg 
599f005ef32Sjsg 	if (drm_WARN_ON(&i915->drm, port == PORT_A))
600c349dbc7Sjsg 		return;
601c349dbc7Sjsg 
602f005ef32Sjsg 	ibx_audio_regs_init(i915, pipe, &regs);
603f005ef32Sjsg 
604f005ef32Sjsg 	mutex_lock(&i915->display.audio.mutex);
605c349dbc7Sjsg 
606c349dbc7Sjsg 	/* Disable timestamps */
607f005ef32Sjsg 	intel_de_rmw(i915, regs.aud_config,
608f005ef32Sjsg 		     AUD_CONFIG_N_VALUE_INDEX |
609f005ef32Sjsg 		     AUD_CONFIG_UPPER_N_MASK |
610f005ef32Sjsg 		     AUD_CONFIG_LOWER_N_MASK,
611f005ef32Sjsg 		     AUD_CONFIG_N_PROG_ENABLE |
612f005ef32Sjsg 		     (intel_crtc_has_dp_encoder(old_crtc_state) ?
613f005ef32Sjsg 		      AUD_CONFIG_N_VALUE_INDEX : 0));
614c349dbc7Sjsg 
615c349dbc7Sjsg 	/* Invalidate ELD */
616f005ef32Sjsg 	intel_de_rmw(i915, regs.aud_cntrl_st2,
617f005ef32Sjsg 		     IBX_ELD_VALID(port), 0);
618f005ef32Sjsg 
619f005ef32Sjsg 	mutex_unlock(&i915->display.audio.mutex);
620f005ef32Sjsg 
621f005ef32Sjsg 	intel_crtc_wait_for_next_vblank(crtc);
622f005ef32Sjsg 	intel_crtc_wait_for_next_vblank(crtc);
623c349dbc7Sjsg }
624c349dbc7Sjsg 
ibx_audio_codec_enable(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)625f005ef32Sjsg static void ibx_audio_codec_enable(struct intel_encoder *encoder,
626c349dbc7Sjsg 				   const struct intel_crtc_state *crtc_state,
627c349dbc7Sjsg 				   const struct drm_connector_state *conn_state)
628c349dbc7Sjsg {
629f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
630c349dbc7Sjsg 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
631c349dbc7Sjsg 	enum port port = encoder->port;
632f005ef32Sjsg 	enum pipe pipe = crtc->pipe;
633f005ef32Sjsg 	struct ibx_audio_regs regs;
634c349dbc7Sjsg 
635f005ef32Sjsg 	if (drm_WARN_ON(&i915->drm, port == PORT_A))
636c349dbc7Sjsg 		return;
637c349dbc7Sjsg 
638f005ef32Sjsg 	intel_crtc_wait_for_next_vblank(crtc);
639c349dbc7Sjsg 
640f005ef32Sjsg 	ibx_audio_regs_init(i915, pipe, &regs);
641c349dbc7Sjsg 
642f005ef32Sjsg 	mutex_lock(&i915->display.audio.mutex);
643c349dbc7Sjsg 
644c349dbc7Sjsg 	/* Invalidate ELD */
645f005ef32Sjsg 	intel_de_rmw(i915, regs.aud_cntrl_st2,
646f005ef32Sjsg 		     IBX_ELD_VALID(port), 0);
647c349dbc7Sjsg 
648f005ef32Sjsg 	/*
649f005ef32Sjsg 	 * The audio componenent is used to convey the ELD
650f005ef32Sjsg 	 * instead using of the hardware ELD buffer.
651f005ef32Sjsg 	 */
652c349dbc7Sjsg 
653c349dbc7Sjsg 	/* Enable timestamps */
654f005ef32Sjsg 	intel_de_rmw(i915, regs.aud_config,
655f005ef32Sjsg 		     AUD_CONFIG_N_VALUE_INDEX |
656f005ef32Sjsg 		     AUD_CONFIG_N_PROG_ENABLE |
657f005ef32Sjsg 		     AUD_CONFIG_PIXEL_CLOCK_HDMI_MASK,
658f005ef32Sjsg 		     (intel_crtc_has_dp_encoder(crtc_state) ?
659f005ef32Sjsg 		      AUD_CONFIG_N_VALUE_INDEX :
660f005ef32Sjsg 		      audio_config_hdmi_pixel_clock(crtc_state)));
661f005ef32Sjsg 
662f005ef32Sjsg 	mutex_unlock(&i915->display.audio.mutex);
663f005ef32Sjsg }
664f005ef32Sjsg 
intel_audio_sdp_split_update(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state)665f005ef32Sjsg void intel_audio_sdp_split_update(struct intel_encoder *encoder,
666f005ef32Sjsg 				  const struct intel_crtc_state *crtc_state)
667f005ef32Sjsg {
668f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
669f005ef32Sjsg 	enum transcoder trans = crtc_state->cpu_transcoder;
670f005ef32Sjsg 
671f005ef32Sjsg 	if (HAS_DP20(i915))
672f005ef32Sjsg 		intel_de_rmw(i915, AUD_DP_2DOT0_CTRL(trans), AUD_ENABLE_SDP_SPLIT,
673f005ef32Sjsg 			     crtc_state->sdp_split_enable ? AUD_ENABLE_SDP_SPLIT : 0);
674f005ef32Sjsg }
675f005ef32Sjsg 
intel_audio_compute_config(struct intel_encoder * encoder,struct intel_crtc_state * crtc_state,struct drm_connector_state * conn_state)676f005ef32Sjsg bool intel_audio_compute_config(struct intel_encoder *encoder,
677f005ef32Sjsg 				struct intel_crtc_state *crtc_state,
678f005ef32Sjsg 				struct drm_connector_state *conn_state)
679f005ef32Sjsg {
680f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
681f005ef32Sjsg 	struct drm_connector *connector = conn_state->connector;
682f005ef32Sjsg 	const struct drm_display_mode *adjusted_mode =
683f005ef32Sjsg 		&crtc_state->hw.adjusted_mode;
684f005ef32Sjsg 
685f005ef32Sjsg 	if (!connector->eld[0]) {
686f005ef32Sjsg 		drm_dbg_kms(&i915->drm,
687f005ef32Sjsg 			    "Bogus ELD on [CONNECTOR:%d:%s]\n",
688f005ef32Sjsg 			    connector->base.id, connector->name);
689f005ef32Sjsg 		return false;
690f005ef32Sjsg 	}
691f005ef32Sjsg 
692f005ef32Sjsg 	BUILD_BUG_ON(sizeof(crtc_state->eld) != sizeof(connector->eld));
693f005ef32Sjsg 	memcpy(crtc_state->eld, connector->eld, sizeof(crtc_state->eld));
694f005ef32Sjsg 
695f005ef32Sjsg 	crtc_state->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
696f005ef32Sjsg 
697f005ef32Sjsg 	return true;
698c349dbc7Sjsg }
699c349dbc7Sjsg 
700c349dbc7Sjsg /**
701c349dbc7Sjsg  * intel_audio_codec_enable - Enable the audio codec for HD audio
702c349dbc7Sjsg  * @encoder: encoder on which to enable audio
703c349dbc7Sjsg  * @crtc_state: pointer to the current crtc state.
704c349dbc7Sjsg  * @conn_state: pointer to the current connector state.
705c349dbc7Sjsg  *
706c349dbc7Sjsg  * The enable sequences may only be performed after enabling the transcoder and
707c349dbc7Sjsg  * port, and after completed link training.
708c349dbc7Sjsg  */
intel_audio_codec_enable(struct intel_encoder * encoder,const struct intel_crtc_state * crtc_state,const struct drm_connector_state * conn_state)709c349dbc7Sjsg void intel_audio_codec_enable(struct intel_encoder *encoder,
710c349dbc7Sjsg 			      const struct intel_crtc_state *crtc_state,
711c349dbc7Sjsg 			      const struct drm_connector_state *conn_state)
712c349dbc7Sjsg {
713f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
714f005ef32Sjsg 	struct i915_audio_component *acomp = i915->display.audio.component;
715c349dbc7Sjsg 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
716f005ef32Sjsg 	struct intel_connector *connector = to_intel_connector(conn_state->connector);
717f005ef32Sjsg 	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
718f005ef32Sjsg 	struct intel_audio_state *audio_state;
719c349dbc7Sjsg 	enum port port = encoder->port;
720c349dbc7Sjsg 
7211bb76ff1Sjsg 	if (!crtc_state->has_audio)
7221bb76ff1Sjsg 		return;
7231bb76ff1Sjsg 
724f005ef32Sjsg 	drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Enable audio codec on [CRTC:%d:%s], %u bytes ELD\n",
725f005ef32Sjsg 		    connector->base.base.id, connector->base.name,
7261bb76ff1Sjsg 		    encoder->base.base.id, encoder->base.name,
727f005ef32Sjsg 		    crtc->base.base.id, crtc->base.name,
728f005ef32Sjsg 		    drm_eld_size(crtc_state->eld));
7291bb76ff1Sjsg 
730f005ef32Sjsg 	if (i915->display.funcs.audio)
731f005ef32Sjsg 		i915->display.funcs.audio->audio_codec_enable(encoder,
732c349dbc7Sjsg 							      crtc_state,
733c349dbc7Sjsg 							      conn_state);
734c349dbc7Sjsg 
735f005ef32Sjsg 	mutex_lock(&i915->display.audio.mutex);
736c349dbc7Sjsg 
737f005ef32Sjsg 	audio_state = &i915->display.audio.state[cpu_transcoder];
738f005ef32Sjsg 
739f005ef32Sjsg 	audio_state->encoder = encoder;
740f005ef32Sjsg 	BUILD_BUG_ON(sizeof(audio_state->eld) != sizeof(crtc_state->eld));
741f005ef32Sjsg 	memcpy(audio_state->eld, crtc_state->eld, sizeof(audio_state->eld));
742f005ef32Sjsg 
743f005ef32Sjsg 	mutex_unlock(&i915->display.audio.mutex);
744c349dbc7Sjsg 
745c349dbc7Sjsg 	if (acomp && acomp->base.audio_ops &&
746c349dbc7Sjsg 	    acomp->base.audio_ops->pin_eld_notify) {
747f005ef32Sjsg 		/* audio drivers expect cpu_transcoder = -1 to indicate Non-MST cases */
748c349dbc7Sjsg 		if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST))
749f005ef32Sjsg 			cpu_transcoder = -1;
750c349dbc7Sjsg 		acomp->base.audio_ops->pin_eld_notify(acomp->base.audio_ops->audio_ptr,
751f005ef32Sjsg 						      (int)port, (int)cpu_transcoder);
752c349dbc7Sjsg 	}
753c349dbc7Sjsg 
754f005ef32Sjsg 	intel_lpe_audio_notify(i915, cpu_transcoder, port, crtc_state->eld,
755c349dbc7Sjsg 			       crtc_state->port_clock,
756c349dbc7Sjsg 			       intel_crtc_has_dp_encoder(crtc_state));
757c349dbc7Sjsg }
758c349dbc7Sjsg 
759c349dbc7Sjsg /**
760c349dbc7Sjsg  * intel_audio_codec_disable - Disable the audio codec for HD audio
761c349dbc7Sjsg  * @encoder: encoder on which to disable audio
762c349dbc7Sjsg  * @old_crtc_state: pointer to the old crtc state.
763c349dbc7Sjsg  * @old_conn_state: pointer to the old connector state.
764c349dbc7Sjsg  *
765c349dbc7Sjsg  * The disable sequences must be performed before disabling the transcoder or
766c349dbc7Sjsg  * port.
767c349dbc7Sjsg  */
intel_audio_codec_disable(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)768c349dbc7Sjsg void intel_audio_codec_disable(struct intel_encoder *encoder,
769c349dbc7Sjsg 			       const struct intel_crtc_state *old_crtc_state,
770c349dbc7Sjsg 			       const struct drm_connector_state *old_conn_state)
771c349dbc7Sjsg {
772f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
773f005ef32Sjsg 	struct i915_audio_component *acomp = i915->display.audio.component;
774c349dbc7Sjsg 	struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
775f005ef32Sjsg 	struct intel_connector *connector = to_intel_connector(old_conn_state->connector);
776f005ef32Sjsg 	enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder;
777f005ef32Sjsg 	struct intel_audio_state *audio_state;
778c349dbc7Sjsg 	enum port port = encoder->port;
779c349dbc7Sjsg 
7801bb76ff1Sjsg 	if (!old_crtc_state->has_audio)
7811bb76ff1Sjsg 		return;
7821bb76ff1Sjsg 
783f005ef32Sjsg 	drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s][ENCODER:%d:%s] Disable audio codec on [CRTC:%d:%s]\n",
784f005ef32Sjsg 		    connector->base.base.id, connector->base.name,
785f005ef32Sjsg 		    encoder->base.base.id, encoder->base.name,
786f005ef32Sjsg 		    crtc->base.base.id, crtc->base.name);
7871bb76ff1Sjsg 
788f005ef32Sjsg 	if (i915->display.funcs.audio)
789f005ef32Sjsg 		i915->display.funcs.audio->audio_codec_disable(encoder,
790c349dbc7Sjsg 							       old_crtc_state,
791c349dbc7Sjsg 							       old_conn_state);
792c349dbc7Sjsg 
793f005ef32Sjsg 	mutex_lock(&i915->display.audio.mutex);
794f005ef32Sjsg 
795f005ef32Sjsg 	audio_state = &i915->display.audio.state[cpu_transcoder];
796f005ef32Sjsg 
797f005ef32Sjsg 	audio_state->encoder = NULL;
798f005ef32Sjsg 	memset(audio_state->eld, 0, sizeof(audio_state->eld));
799f005ef32Sjsg 
800f005ef32Sjsg 	mutex_unlock(&i915->display.audio.mutex);
801c349dbc7Sjsg 
802c349dbc7Sjsg 	if (acomp && acomp->base.audio_ops &&
803c349dbc7Sjsg 	    acomp->base.audio_ops->pin_eld_notify) {
804f005ef32Sjsg 		/* audio drivers expect cpu_transcoder = -1 to indicate Non-MST cases */
805c349dbc7Sjsg 		if (!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST))
806f005ef32Sjsg 			cpu_transcoder = -1;
807c349dbc7Sjsg 		acomp->base.audio_ops->pin_eld_notify(acomp->base.audio_ops->audio_ptr,
808f005ef32Sjsg 						      (int)port, (int)cpu_transcoder);
809c349dbc7Sjsg 	}
810c349dbc7Sjsg 
811f005ef32Sjsg 	intel_lpe_audio_notify(i915, cpu_transcoder, port, NULL, 0, false);
812f005ef32Sjsg }
813f005ef32Sjsg 
intel_acomp_get_config(struct intel_encoder * encoder,struct intel_crtc_state * crtc_state)814f005ef32Sjsg static void intel_acomp_get_config(struct intel_encoder *encoder,
815f005ef32Sjsg 				   struct intel_crtc_state *crtc_state)
816f005ef32Sjsg {
817f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
818f005ef32Sjsg 	enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
819f005ef32Sjsg 	struct intel_audio_state *audio_state;
820f005ef32Sjsg 
821f005ef32Sjsg 	mutex_lock(&i915->display.audio.mutex);
822f005ef32Sjsg 
823f005ef32Sjsg 	audio_state = &i915->display.audio.state[cpu_transcoder];
824f005ef32Sjsg 
825f005ef32Sjsg 	if (audio_state->encoder)
826f005ef32Sjsg 		memcpy(crtc_state->eld, audio_state->eld, sizeof(audio_state->eld));
827f005ef32Sjsg 
828f005ef32Sjsg 	mutex_unlock(&i915->display.audio.mutex);
829f005ef32Sjsg }
830f005ef32Sjsg 
intel_audio_codec_get_config(struct intel_encoder * encoder,struct intel_crtc_state * crtc_state)831f005ef32Sjsg void intel_audio_codec_get_config(struct intel_encoder *encoder,
832f005ef32Sjsg 				  struct intel_crtc_state *crtc_state)
833f005ef32Sjsg {
834f005ef32Sjsg 	struct drm_i915_private *i915 = to_i915(encoder->base.dev);
835f005ef32Sjsg 
836f005ef32Sjsg 	if (!crtc_state->has_audio)
837f005ef32Sjsg 		return;
838f005ef32Sjsg 
839f005ef32Sjsg 	if (i915->display.funcs.audio)
840f005ef32Sjsg 		i915->display.funcs.audio->audio_codec_get_config(encoder, crtc_state);
841c349dbc7Sjsg }
842c349dbc7Sjsg 
8431bb76ff1Sjsg static const struct intel_audio_funcs g4x_audio_funcs = {
8441bb76ff1Sjsg 	.audio_codec_enable = g4x_audio_codec_enable,
8451bb76ff1Sjsg 	.audio_codec_disable = g4x_audio_codec_disable,
846f005ef32Sjsg 	.audio_codec_get_config = g4x_audio_codec_get_config,
8471bb76ff1Sjsg };
8481bb76ff1Sjsg 
849f005ef32Sjsg static const struct intel_audio_funcs ibx_audio_funcs = {
850f005ef32Sjsg 	.audio_codec_enable = ibx_audio_codec_enable,
851f005ef32Sjsg 	.audio_codec_disable = ibx_audio_codec_disable,
852f005ef32Sjsg 	.audio_codec_get_config = intel_acomp_get_config,
8531bb76ff1Sjsg };
8541bb76ff1Sjsg 
8551bb76ff1Sjsg static const struct intel_audio_funcs hsw_audio_funcs = {
8561bb76ff1Sjsg 	.audio_codec_enable = hsw_audio_codec_enable,
8571bb76ff1Sjsg 	.audio_codec_disable = hsw_audio_codec_disable,
858f005ef32Sjsg 	.audio_codec_get_config = intel_acomp_get_config,
8591bb76ff1Sjsg };
8601bb76ff1Sjsg 
861c349dbc7Sjsg /**
8621bb76ff1Sjsg  * intel_audio_hooks_init - Set up chip specific audio hooks
863f005ef32Sjsg  * @i915: device private
864c349dbc7Sjsg  */
intel_audio_hooks_init(struct drm_i915_private * i915)865f005ef32Sjsg void intel_audio_hooks_init(struct drm_i915_private *i915)
866c349dbc7Sjsg {
867f005ef32Sjsg 	if (IS_G4X(i915))
868f005ef32Sjsg 		i915->display.funcs.audio = &g4x_audio_funcs;
869f005ef32Sjsg 	else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915) ||
870f005ef32Sjsg 		 HAS_PCH_CPT(i915) || HAS_PCH_IBX(i915))
871f005ef32Sjsg 		i915->display.funcs.audio = &ibx_audio_funcs;
872f005ef32Sjsg 	else if (IS_HASWELL(i915) || DISPLAY_VER(i915) >= 8)
873f005ef32Sjsg 		i915->display.funcs.audio = &hsw_audio_funcs;
8741bb76ff1Sjsg }
8751bb76ff1Sjsg 
8761bb76ff1Sjsg struct aud_ts_cdclk_m_n {
8771bb76ff1Sjsg 	u8 m;
8781bb76ff1Sjsg 	u16 n;
8791bb76ff1Sjsg };
8801bb76ff1Sjsg 
intel_audio_cdclk_change_pre(struct drm_i915_private * i915)8811bb76ff1Sjsg void intel_audio_cdclk_change_pre(struct drm_i915_private *i915)
8821bb76ff1Sjsg {
8831bb76ff1Sjsg 	if (DISPLAY_VER(i915) >= 13)
8841bb76ff1Sjsg 		intel_de_rmw(i915, AUD_TS_CDCLK_M, AUD_TS_CDCLK_M_EN, 0);
8851bb76ff1Sjsg }
8861bb76ff1Sjsg 
get_aud_ts_cdclk_m_n(int refclk,int cdclk,struct aud_ts_cdclk_m_n * aud_ts)8871bb76ff1Sjsg static void get_aud_ts_cdclk_m_n(int refclk, int cdclk, struct aud_ts_cdclk_m_n *aud_ts)
8881bb76ff1Sjsg {
889f005ef32Sjsg 	aud_ts->m = 60;
8901bb76ff1Sjsg 	aud_ts->n = cdclk * aud_ts->m / 24000;
8911bb76ff1Sjsg }
8921bb76ff1Sjsg 
intel_audio_cdclk_change_post(struct drm_i915_private * i915)8931bb76ff1Sjsg void intel_audio_cdclk_change_post(struct drm_i915_private *i915)
8941bb76ff1Sjsg {
8951bb76ff1Sjsg 	struct aud_ts_cdclk_m_n aud_ts;
8961bb76ff1Sjsg 
8971bb76ff1Sjsg 	if (DISPLAY_VER(i915) >= 13) {
8981bb76ff1Sjsg 		get_aud_ts_cdclk_m_n(i915->display.cdclk.hw.ref, i915->display.cdclk.hw.cdclk, &aud_ts);
8991bb76ff1Sjsg 
9001bb76ff1Sjsg 		intel_de_write(i915, AUD_TS_CDCLK_N, aud_ts.n);
9011bb76ff1Sjsg 		intel_de_write(i915, AUD_TS_CDCLK_M, aud_ts.m | AUD_TS_CDCLK_M_EN);
9021bb76ff1Sjsg 		drm_dbg_kms(&i915->drm, "aud_ts_cdclk set to M=%u, N=%u\n", aud_ts.m, aud_ts.n);
903c349dbc7Sjsg 	}
904c349dbc7Sjsg }
905c349dbc7Sjsg 
glk_force_audio_cdclk_commit(struct intel_atomic_state * state,struct intel_crtc * crtc,bool enable)906c349dbc7Sjsg static int glk_force_audio_cdclk_commit(struct intel_atomic_state *state,
907c349dbc7Sjsg 					struct intel_crtc *crtc,
908c349dbc7Sjsg 					bool enable)
909c349dbc7Sjsg {
910c349dbc7Sjsg 	struct intel_cdclk_state *cdclk_state;
911c349dbc7Sjsg 	int ret;
912c349dbc7Sjsg 
913c349dbc7Sjsg 	/* need to hold at least one crtc lock for the global state */
914c349dbc7Sjsg 	ret = drm_modeset_lock(&crtc->base.mutex, state->base.acquire_ctx);
915c349dbc7Sjsg 	if (ret)
916c349dbc7Sjsg 		return ret;
917c349dbc7Sjsg 
918c349dbc7Sjsg 	cdclk_state = intel_atomic_get_cdclk_state(state);
919c349dbc7Sjsg 	if (IS_ERR(cdclk_state))
920c349dbc7Sjsg 		return PTR_ERR(cdclk_state);
921c349dbc7Sjsg 
922c349dbc7Sjsg 	cdclk_state->force_min_cdclk = enable ? 2 * 96000 : 0;
923c349dbc7Sjsg 
924c349dbc7Sjsg 	return drm_atomic_commit(&state->base);
925c349dbc7Sjsg }
926c349dbc7Sjsg 
glk_force_audio_cdclk(struct drm_i915_private * i915,bool enable)927f005ef32Sjsg static void glk_force_audio_cdclk(struct drm_i915_private *i915,
928c349dbc7Sjsg 				  bool enable)
929c349dbc7Sjsg {
930c349dbc7Sjsg 	struct drm_modeset_acquire_ctx ctx;
931c349dbc7Sjsg 	struct drm_atomic_state *state;
932c349dbc7Sjsg 	struct intel_crtc *crtc;
933c349dbc7Sjsg 	int ret;
934c349dbc7Sjsg 
935f005ef32Sjsg 	crtc = intel_first_crtc(i915);
936c349dbc7Sjsg 	if (!crtc)
937c349dbc7Sjsg 		return;
938c349dbc7Sjsg 
939c349dbc7Sjsg 	drm_modeset_acquire_init(&ctx, 0);
940f005ef32Sjsg 	state = drm_atomic_state_alloc(&i915->drm);
941f005ef32Sjsg 	if (drm_WARN_ON(&i915->drm, !state))
942c349dbc7Sjsg 		return;
943c349dbc7Sjsg 
944c349dbc7Sjsg 	state->acquire_ctx = &ctx;
945f005ef32Sjsg 	to_intel_atomic_state(state)->internal = true;
946c349dbc7Sjsg 
947c349dbc7Sjsg retry:
948c349dbc7Sjsg 	ret = glk_force_audio_cdclk_commit(to_intel_atomic_state(state), crtc,
949c349dbc7Sjsg 					   enable);
950c349dbc7Sjsg 	if (ret == -EDEADLK) {
951c349dbc7Sjsg 		drm_atomic_state_clear(state);
952c349dbc7Sjsg 		drm_modeset_backoff(&ctx);
953c349dbc7Sjsg 		goto retry;
954c349dbc7Sjsg 	}
955c349dbc7Sjsg 
956f005ef32Sjsg 	drm_WARN_ON(&i915->drm, ret);
957c349dbc7Sjsg 
958c349dbc7Sjsg 	drm_atomic_state_put(state);
959c349dbc7Sjsg 
960c349dbc7Sjsg 	drm_modeset_drop_locks(&ctx);
961c349dbc7Sjsg 	drm_modeset_acquire_fini(&ctx);
962c349dbc7Sjsg }
963c349dbc7Sjsg 
i915_audio_component_get_power(struct device * kdev)964c349dbc7Sjsg static unsigned long i915_audio_component_get_power(struct device *kdev)
965c349dbc7Sjsg {
966f005ef32Sjsg 	struct drm_i915_private *i915 = kdev_to_i915(kdev);
967c349dbc7Sjsg 	intel_wakeref_t ret;
968c349dbc7Sjsg 
969c349dbc7Sjsg 	/* Catch potential impedance mismatches before they occur! */
970c349dbc7Sjsg 	BUILD_BUG_ON(sizeof(intel_wakeref_t) > sizeof(unsigned long));
971c349dbc7Sjsg 
972f005ef32Sjsg 	ret = intel_display_power_get(i915, POWER_DOMAIN_AUDIO_PLAYBACK);
973c349dbc7Sjsg 
974f005ef32Sjsg 	if (i915->display.audio.power_refcount++ == 0) {
975f005ef32Sjsg 		if (DISPLAY_VER(i915) >= 9) {
976f005ef32Sjsg 			intel_de_write(i915, AUD_FREQ_CNTRL,
977f005ef32Sjsg 				       i915->display.audio.freq_cntrl);
978f005ef32Sjsg 			drm_dbg_kms(&i915->drm,
979c349dbc7Sjsg 				    "restored AUD_FREQ_CNTRL to 0x%x\n",
980f005ef32Sjsg 				    i915->display.audio.freq_cntrl);
981c349dbc7Sjsg 		}
982c349dbc7Sjsg 
983c349dbc7Sjsg 		/* Force CDCLK to 2*BCLK as long as we need audio powered. */
984f005ef32Sjsg 		if (IS_GEMINILAKE(i915))
985f005ef32Sjsg 			glk_force_audio_cdclk(i915, true);
986c349dbc7Sjsg 
987f005ef32Sjsg 		if (DISPLAY_VER(i915) >= 10)
988f005ef32Sjsg 			intel_de_rmw(i915, AUD_PIN_BUF_CTL,
989f005ef32Sjsg 				     0, AUD_PIN_BUF_ENABLE);
990c349dbc7Sjsg 	}
991c349dbc7Sjsg 
992c349dbc7Sjsg 	return ret;
993c349dbc7Sjsg }
994c349dbc7Sjsg 
i915_audio_component_put_power(struct device * kdev,unsigned long cookie)995c349dbc7Sjsg static void i915_audio_component_put_power(struct device *kdev,
996c349dbc7Sjsg 					   unsigned long cookie)
997c349dbc7Sjsg {
998f005ef32Sjsg 	struct drm_i915_private *i915 = kdev_to_i915(kdev);
999c349dbc7Sjsg 
1000c349dbc7Sjsg 	/* Stop forcing CDCLK to 2*BCLK if no need for audio to be powered. */
1001f005ef32Sjsg 	if (--i915->display.audio.power_refcount == 0)
1002f005ef32Sjsg 		if (IS_GEMINILAKE(i915))
1003f005ef32Sjsg 			glk_force_audio_cdclk(i915, false);
1004c349dbc7Sjsg 
1005f005ef32Sjsg 	intel_display_power_put(i915, POWER_DOMAIN_AUDIO_PLAYBACK, cookie);
1006c349dbc7Sjsg }
1007c349dbc7Sjsg 
i915_audio_component_codec_wake_override(struct device * kdev,bool enable)1008c349dbc7Sjsg static void i915_audio_component_codec_wake_override(struct device *kdev,
1009c349dbc7Sjsg 						     bool enable)
1010c349dbc7Sjsg {
1011f005ef32Sjsg 	struct drm_i915_private *i915 = kdev_to_i915(kdev);
1012c349dbc7Sjsg 	unsigned long cookie;
1013c349dbc7Sjsg 
1014f005ef32Sjsg 	if (DISPLAY_VER(i915) < 9)
1015c349dbc7Sjsg 		return;
1016c349dbc7Sjsg 
1017c349dbc7Sjsg 	cookie = i915_audio_component_get_power(kdev);
1018c349dbc7Sjsg 
1019c349dbc7Sjsg 	/*
1020c349dbc7Sjsg 	 * Enable/disable generating the codec wake signal, overriding the
1021c349dbc7Sjsg 	 * internal logic to generate the codec wake to controller.
1022c349dbc7Sjsg 	 */
1023f005ef32Sjsg 	intel_de_rmw(i915, HSW_AUD_CHICKENBIT,
1024f005ef32Sjsg 		     SKL_AUD_CODEC_WAKE_SIGNAL, 0);
1025c349dbc7Sjsg 	usleep_range(1000, 1500);
1026c349dbc7Sjsg 
1027c349dbc7Sjsg 	if (enable) {
1028f005ef32Sjsg 		intel_de_rmw(i915, HSW_AUD_CHICKENBIT,
1029f005ef32Sjsg 			     0, SKL_AUD_CODEC_WAKE_SIGNAL);
1030c349dbc7Sjsg 		usleep_range(1000, 1500);
1031c349dbc7Sjsg 	}
1032c349dbc7Sjsg 
1033c349dbc7Sjsg 	i915_audio_component_put_power(kdev, cookie);
1034c349dbc7Sjsg }
1035c349dbc7Sjsg 
1036c349dbc7Sjsg /* Get CDCLK in kHz  */
i915_audio_component_get_cdclk_freq(struct device * kdev)1037c349dbc7Sjsg static int i915_audio_component_get_cdclk_freq(struct device *kdev)
1038c349dbc7Sjsg {
1039f005ef32Sjsg 	struct drm_i915_private *i915 = kdev_to_i915(kdev);
1040c349dbc7Sjsg 
1041f005ef32Sjsg 	if (drm_WARN_ON_ONCE(&i915->drm, !HAS_DDI(i915)))
1042c349dbc7Sjsg 		return -ENODEV;
1043c349dbc7Sjsg 
1044f005ef32Sjsg 	return i915->display.cdclk.hw.cdclk;
1045c349dbc7Sjsg }
1046c349dbc7Sjsg 
1047c349dbc7Sjsg /*
1048f005ef32Sjsg  * get the intel audio state according to the parameter port and cpu_transcoder
1049f005ef32Sjsg  * MST & (cpu_transcoder >= 0): return the audio.state[cpu_transcoder].encoder],
1050c349dbc7Sjsg  *   when port is matched
1051f005ef32Sjsg  * MST & (cpu_transcoder < 0): this is invalid
1052f005ef32Sjsg  * Non-MST & (cpu_transcoder >= 0): only cpu_transcoder = 0 (the first device entry)
1053c349dbc7Sjsg  *   will get the right intel_encoder with port matched
1054f005ef32Sjsg  * Non-MST & (cpu_transcoder < 0): get the right intel_encoder with port matched
1055c349dbc7Sjsg  */
find_audio_state(struct drm_i915_private * i915,int port,int cpu_transcoder)1056f005ef32Sjsg static struct intel_audio_state *find_audio_state(struct drm_i915_private *i915,
1057f005ef32Sjsg 						  int port, int cpu_transcoder)
1058c349dbc7Sjsg {
1059f005ef32Sjsg 	/* MST */
1060f005ef32Sjsg 	if (cpu_transcoder >= 0) {
1061f005ef32Sjsg 		struct intel_audio_state *audio_state;
1062c349dbc7Sjsg 		struct intel_encoder *encoder;
1063c349dbc7Sjsg 
1064f005ef32Sjsg 		if (drm_WARN_ON(&i915->drm,
1065f005ef32Sjsg 				cpu_transcoder >= ARRAY_SIZE(i915->display.audio.state)))
1066c349dbc7Sjsg 			return NULL;
1067c349dbc7Sjsg 
1068f005ef32Sjsg 		audio_state = &i915->display.audio.state[cpu_transcoder];
1069f005ef32Sjsg 		encoder = audio_state->encoder;
1070f005ef32Sjsg 
1071f005ef32Sjsg 		if (encoder && encoder->port == port &&
1072c349dbc7Sjsg 		    encoder->type == INTEL_OUTPUT_DP_MST)
1073f005ef32Sjsg 			return audio_state;
1074c349dbc7Sjsg 	}
1075c349dbc7Sjsg 
1076c349dbc7Sjsg 	/* Non-MST */
1077f005ef32Sjsg 	if (cpu_transcoder > 0)
1078c349dbc7Sjsg 		return NULL;
1079c349dbc7Sjsg 
1080f005ef32Sjsg 	for_each_cpu_transcoder(i915, cpu_transcoder) {
1081f005ef32Sjsg 		struct intel_audio_state *audio_state;
1082f005ef32Sjsg 		struct intel_encoder *encoder;
1083c349dbc7Sjsg 
1084f005ef32Sjsg 		audio_state = &i915->display.audio.state[cpu_transcoder];
1085f005ef32Sjsg 		encoder = audio_state->encoder;
1086c349dbc7Sjsg 
1087f005ef32Sjsg 		if (encoder && encoder->port == port &&
1088f005ef32Sjsg 		    encoder->type != INTEL_OUTPUT_DP_MST)
1089f005ef32Sjsg 			return audio_state;
1090c349dbc7Sjsg 	}
1091c349dbc7Sjsg 
1092c349dbc7Sjsg 	return NULL;
1093c349dbc7Sjsg }
1094c349dbc7Sjsg 
i915_audio_component_sync_audio_rate(struct device * kdev,int port,int cpu_transcoder,int rate)1095c349dbc7Sjsg static int i915_audio_component_sync_audio_rate(struct device *kdev, int port,
1096f005ef32Sjsg 						int cpu_transcoder, int rate)
1097c349dbc7Sjsg {
1098f005ef32Sjsg 	struct drm_i915_private *i915 = kdev_to_i915(kdev);
1099f005ef32Sjsg 	struct i915_audio_component *acomp = i915->display.audio.component;
1100f005ef32Sjsg 	const struct intel_audio_state *audio_state;
1101c349dbc7Sjsg 	struct intel_encoder *encoder;
1102c349dbc7Sjsg 	struct intel_crtc *crtc;
1103c349dbc7Sjsg 	unsigned long cookie;
1104c349dbc7Sjsg 	int err = 0;
1105c349dbc7Sjsg 
1106f005ef32Sjsg 	if (!HAS_DDI(i915))
1107c349dbc7Sjsg 		return 0;
1108c349dbc7Sjsg 
1109c349dbc7Sjsg 	cookie = i915_audio_component_get_power(kdev);
1110f005ef32Sjsg 	mutex_lock(&i915->display.audio.mutex);
1111c349dbc7Sjsg 
1112f005ef32Sjsg 	audio_state = find_audio_state(i915, port, cpu_transcoder);
1113f005ef32Sjsg 	if (!audio_state) {
1114f005ef32Sjsg 		drm_dbg_kms(&i915->drm, "Not valid for port %c\n", port_name(port));
1115c349dbc7Sjsg 		err = -ENODEV;
1116c349dbc7Sjsg 		goto unlock;
1117c349dbc7Sjsg 	}
1118c349dbc7Sjsg 
1119f005ef32Sjsg 	encoder = audio_state->encoder;
1120f005ef32Sjsg 
1121f005ef32Sjsg 	/* FIXME stop using the legacy crtc pointer */
1122c349dbc7Sjsg 	crtc = to_intel_crtc(encoder->base.crtc);
1123c349dbc7Sjsg 
1124f005ef32Sjsg 	/* port must be valid now, otherwise the cpu_transcoder will be invalid */
1125c349dbc7Sjsg 	acomp->aud_sample_rate[port] = rate;
1126c349dbc7Sjsg 
1127f005ef32Sjsg 	/* FIXME get rid of the crtc->config stuff */
1128c349dbc7Sjsg 	hsw_audio_config_update(encoder, crtc->config);
1129c349dbc7Sjsg 
1130c349dbc7Sjsg  unlock:
1131f005ef32Sjsg 	mutex_unlock(&i915->display.audio.mutex);
1132c349dbc7Sjsg 	i915_audio_component_put_power(kdev, cookie);
1133c349dbc7Sjsg 	return err;
1134c349dbc7Sjsg }
1135c349dbc7Sjsg 
i915_audio_component_get_eld(struct device * kdev,int port,int cpu_transcoder,bool * enabled,unsigned char * buf,int max_bytes)1136c349dbc7Sjsg static int i915_audio_component_get_eld(struct device *kdev, int port,
1137f005ef32Sjsg 					int cpu_transcoder, bool *enabled,
1138c349dbc7Sjsg 					unsigned char *buf, int max_bytes)
1139c349dbc7Sjsg {
1140f005ef32Sjsg 	struct drm_i915_private *i915 = kdev_to_i915(kdev);
1141f005ef32Sjsg 	const struct intel_audio_state *audio_state;
1142f005ef32Sjsg 	int ret = 0;
1143c349dbc7Sjsg 
1144f005ef32Sjsg 	mutex_lock(&i915->display.audio.mutex);
1145c349dbc7Sjsg 
1146f005ef32Sjsg 	audio_state = find_audio_state(i915, port, cpu_transcoder);
1147f005ef32Sjsg 	if (!audio_state) {
1148f005ef32Sjsg 		drm_dbg_kms(&i915->drm, "Not valid for port %c\n", port_name(port));
1149f005ef32Sjsg 		mutex_unlock(&i915->display.audio.mutex);
1150f005ef32Sjsg 		return -EINVAL;
1151c349dbc7Sjsg 	}
1152c349dbc7Sjsg 
1153f005ef32Sjsg 	*enabled = audio_state->encoder != NULL;
1154c349dbc7Sjsg 	if (*enabled) {
1155f005ef32Sjsg 		const u8 *eld = audio_state->eld;
1156f005ef32Sjsg 
1157c349dbc7Sjsg 		ret = drm_eld_size(eld);
1158c349dbc7Sjsg 		memcpy(buf, eld, min(max_bytes, ret));
1159c349dbc7Sjsg 	}
1160c349dbc7Sjsg 
1161f005ef32Sjsg 	mutex_unlock(&i915->display.audio.mutex);
1162c349dbc7Sjsg 	return ret;
1163c349dbc7Sjsg }
1164c349dbc7Sjsg 
1165c349dbc7Sjsg #ifdef notyet
1166c349dbc7Sjsg 
1167c349dbc7Sjsg static const struct drm_audio_component_ops i915_audio_component_ops = {
1168c349dbc7Sjsg 	.owner		= THIS_MODULE,
1169c349dbc7Sjsg 	.get_power	= i915_audio_component_get_power,
1170c349dbc7Sjsg 	.put_power	= i915_audio_component_put_power,
1171c349dbc7Sjsg 	.codec_wake_override = i915_audio_component_codec_wake_override,
1172c349dbc7Sjsg 	.get_cdclk_freq	= i915_audio_component_get_cdclk_freq,
1173c349dbc7Sjsg 	.sync_audio_rate = i915_audio_component_sync_audio_rate,
1174c349dbc7Sjsg 	.get_eld	= i915_audio_component_get_eld,
1175c349dbc7Sjsg };
1176c349dbc7Sjsg 
i915_audio_component_bind(struct device * i915_kdev,struct device * hda_kdev,void * data)1177c349dbc7Sjsg static int i915_audio_component_bind(struct device *i915_kdev,
1178c349dbc7Sjsg 				     struct device *hda_kdev, void *data)
1179c349dbc7Sjsg {
1180c349dbc7Sjsg 	struct i915_audio_component *acomp = data;
1181f005ef32Sjsg 	struct drm_i915_private *i915 = kdev_to_i915(i915_kdev);
1182c349dbc7Sjsg 	int i;
1183c349dbc7Sjsg 
1184f005ef32Sjsg 	if (drm_WARN_ON(&i915->drm, acomp->base.ops || acomp->base.dev))
1185c349dbc7Sjsg 		return -EEXIST;
1186c349dbc7Sjsg 
1187f005ef32Sjsg 	if (drm_WARN_ON(&i915->drm,
1188c349dbc7Sjsg 			!device_link_add(hda_kdev, i915_kdev,
1189c349dbc7Sjsg 					 DL_FLAG_STATELESS)))
1190c349dbc7Sjsg 		return -ENOMEM;
1191c349dbc7Sjsg 
1192f005ef32Sjsg 	drm_modeset_lock_all(&i915->drm);
1193c349dbc7Sjsg 	acomp->base.ops = &i915_audio_component_ops;
1194c349dbc7Sjsg 	acomp->base.dev = i915_kdev;
1195c349dbc7Sjsg 	BUILD_BUG_ON(MAX_PORTS != I915_MAX_PORTS);
1196c349dbc7Sjsg 	for (i = 0; i < ARRAY_SIZE(acomp->aud_sample_rate); i++)
1197c349dbc7Sjsg 		acomp->aud_sample_rate[i] = 0;
1198f005ef32Sjsg 	i915->display.audio.component = acomp;
1199f005ef32Sjsg 	drm_modeset_unlock_all(&i915->drm);
1200c349dbc7Sjsg 
1201c349dbc7Sjsg 	return 0;
1202c349dbc7Sjsg }
1203c349dbc7Sjsg 
i915_audio_component_unbind(struct device * i915_kdev,struct device * hda_kdev,void * data)1204c349dbc7Sjsg static void i915_audio_component_unbind(struct device *i915_kdev,
1205c349dbc7Sjsg 					struct device *hda_kdev, void *data)
1206c349dbc7Sjsg {
1207c349dbc7Sjsg 	struct i915_audio_component *acomp = data;
1208f005ef32Sjsg 	struct drm_i915_private *i915 = kdev_to_i915(i915_kdev);
1209c349dbc7Sjsg 
1210f005ef32Sjsg 	drm_modeset_lock_all(&i915->drm);
1211c349dbc7Sjsg 	acomp->base.ops = NULL;
1212c349dbc7Sjsg 	acomp->base.dev = NULL;
1213f005ef32Sjsg 	i915->display.audio.component = NULL;
1214f005ef32Sjsg 	drm_modeset_unlock_all(&i915->drm);
1215c349dbc7Sjsg 
1216c349dbc7Sjsg 	device_link_remove(hda_kdev, i915_kdev);
1217ad8b1aafSjsg 
1218f005ef32Sjsg 	if (i915->display.audio.power_refcount)
1219f005ef32Sjsg 		drm_err(&i915->drm, "audio power refcount %d after unbind\n",
1220f005ef32Sjsg 			i915->display.audio.power_refcount);
1221c349dbc7Sjsg }
1222c349dbc7Sjsg 
1223c349dbc7Sjsg static const struct component_ops i915_audio_component_bind_ops = {
1224c349dbc7Sjsg 	.bind	= i915_audio_component_bind,
1225c349dbc7Sjsg 	.unbind	= i915_audio_component_unbind,
1226c349dbc7Sjsg };
1227c349dbc7Sjsg 
12285ca02815Sjsg #define AUD_FREQ_TMODE_SHIFT	14
12295ca02815Sjsg #define AUD_FREQ_4T		0
12305ca02815Sjsg #define AUD_FREQ_8T		(2 << AUD_FREQ_TMODE_SHIFT)
12315ca02815Sjsg #define AUD_FREQ_PULLCLKS(x)	(((x) & 0x3) << 11)
12325ca02815Sjsg #define AUD_FREQ_BCLK_96M	BIT(4)
12335ca02815Sjsg 
12345ca02815Sjsg #define AUD_FREQ_GEN12          (AUD_FREQ_8T | AUD_FREQ_PULLCLKS(0) | AUD_FREQ_BCLK_96M)
12355ca02815Sjsg #define AUD_FREQ_TGL_BROKEN     (AUD_FREQ_8T | AUD_FREQ_PULLCLKS(2) | AUD_FREQ_BCLK_96M)
12365ca02815Sjsg 
1237c349dbc7Sjsg #endif /* notyet */
1238c349dbc7Sjsg 
1239c349dbc7Sjsg /**
1240c349dbc7Sjsg  * i915_audio_component_init - initialize and register the audio component
1241f005ef32Sjsg  * @i915: i915 device instance
1242c349dbc7Sjsg  *
1243c349dbc7Sjsg  * This will register with the component framework a child component which
1244c349dbc7Sjsg  * will bind dynamically to the snd_hda_intel driver's corresponding master
1245c349dbc7Sjsg  * component when the latter is registered. During binding the child
1246c349dbc7Sjsg  * initializes an instance of struct i915_audio_component which it receives
1247c349dbc7Sjsg  * from the master. The master can then start to use the interface defined by
1248c349dbc7Sjsg  * this struct. Each side can break the binding at any point by deregistering
1249c349dbc7Sjsg  * its own component after which each side's component unbind callback is
1250c349dbc7Sjsg  * called.
1251c349dbc7Sjsg  *
1252c349dbc7Sjsg  * We ignore any error during registration and continue with reduced
1253c349dbc7Sjsg  * functionality (i.e. without HDMI audio).
1254c349dbc7Sjsg  */
i915_audio_component_init(struct drm_i915_private * i915)1255f005ef32Sjsg static void i915_audio_component_init(struct drm_i915_private *i915)
1256c349dbc7Sjsg {
1257c349dbc7Sjsg #ifdef notyet
12585ca02815Sjsg 	u32 aud_freq, aud_freq_init;
1259c349dbc7Sjsg 
1260f005ef32Sjsg 	if (DISPLAY_VER(i915) >= 9) {
1261f005ef32Sjsg 		aud_freq_init = intel_de_read(i915, AUD_FREQ_CNTRL);
12625ca02815Sjsg 
1263f005ef32Sjsg 		if (DISPLAY_VER(i915) >= 12)
12645ca02815Sjsg 			aud_freq = AUD_FREQ_GEN12;
12655ca02815Sjsg 		else
12665ca02815Sjsg 			aud_freq = aud_freq_init;
12675ca02815Sjsg 
12685ca02815Sjsg 		/* use BIOS provided value for TGL and RKL unless it is a known bad value */
1269f005ef32Sjsg 		if ((IS_TIGERLAKE(i915) || IS_ROCKETLAKE(i915)) &&
12705ca02815Sjsg 		    aud_freq_init != AUD_FREQ_TGL_BROKEN)
12715ca02815Sjsg 			aud_freq = aud_freq_init;
12725ca02815Sjsg 
1273f005ef32Sjsg 		drm_dbg_kms(&i915->drm, "use AUD_FREQ_CNTRL of 0x%x (init value 0x%x)\n",
12745ca02815Sjsg 			    aud_freq, aud_freq_init);
12755ca02815Sjsg 
1276f005ef32Sjsg 		i915->display.audio.freq_cntrl = aud_freq;
1277c349dbc7Sjsg 	}
1278c349dbc7Sjsg 
12791bb76ff1Sjsg 	/* init with current cdclk */
1280f005ef32Sjsg 	intel_audio_cdclk_change_post(i915);
1281*f6d48bfeSjsg #endif
1282*f6d48bfeSjsg }
1283*f6d48bfeSjsg 
i915_audio_component_register(struct drm_i915_private * i915)1284*f6d48bfeSjsg static void i915_audio_component_register(struct drm_i915_private *i915)
1285*f6d48bfeSjsg {
1286*f6d48bfeSjsg #ifdef notyet
1287*f6d48bfeSjsg 	int ret;
1288*f6d48bfeSjsg 
1289*f6d48bfeSjsg 	ret = component_add_typed(i915->drm.dev,
1290*f6d48bfeSjsg 				  &i915_audio_component_bind_ops,
1291*f6d48bfeSjsg 				  I915_COMPONENT_AUDIO);
1292*f6d48bfeSjsg 	if (ret < 0) {
1293*f6d48bfeSjsg 		drm_err(&i915->drm,
1294*f6d48bfeSjsg 			"failed to add audio component (%d)\n", ret);
1295*f6d48bfeSjsg 		/* continue with reduced functionality */
1296*f6d48bfeSjsg 		return;
1297*f6d48bfeSjsg 	}
12981bb76ff1Sjsg 
1299f005ef32Sjsg 	i915->display.audio.component_registered = true;
1300c349dbc7Sjsg #endif
1301c349dbc7Sjsg }
1302c349dbc7Sjsg 
1303c349dbc7Sjsg /**
1304c349dbc7Sjsg  * i915_audio_component_cleanup - deregister the audio component
1305f005ef32Sjsg  * @i915: i915 device instance
1306c349dbc7Sjsg  *
1307c349dbc7Sjsg  * Deregisters the audio component, breaking any existing binding to the
1308c349dbc7Sjsg  * corresponding snd_hda_intel driver's master component.
1309c349dbc7Sjsg  */
i915_audio_component_cleanup(struct drm_i915_private * i915)1310f005ef32Sjsg static void i915_audio_component_cleanup(struct drm_i915_private *i915)
1311c349dbc7Sjsg {
1312f005ef32Sjsg 	if (!i915->display.audio.component_registered)
1313c349dbc7Sjsg 		return;
1314c349dbc7Sjsg 
1315f005ef32Sjsg 	component_del(i915->drm.dev, &i915_audio_component_bind_ops);
1316f005ef32Sjsg 	i915->display.audio.component_registered = false;
1317c349dbc7Sjsg }
1318c349dbc7Sjsg 
1319c349dbc7Sjsg /**
1320c349dbc7Sjsg  * intel_audio_init() - Initialize the audio driver either using
1321c349dbc7Sjsg  * component framework or using lpe audio bridge
1322f005ef32Sjsg  * @i915: the i915 drm device private data
1323c349dbc7Sjsg  *
1324c349dbc7Sjsg  */
intel_audio_init(struct drm_i915_private * i915)1325f005ef32Sjsg void intel_audio_init(struct drm_i915_private *i915)
1326c349dbc7Sjsg {
1327f005ef32Sjsg 	if (intel_lpe_audio_init(i915) < 0)
1328f005ef32Sjsg 		i915_audio_component_init(i915);
1329c349dbc7Sjsg }
1330c349dbc7Sjsg 
intel_audio_register(struct drm_i915_private * i915)1331*f6d48bfeSjsg void intel_audio_register(struct drm_i915_private *i915)
1332*f6d48bfeSjsg {
1333*f6d48bfeSjsg 	if (!i915->display.audio.lpe.platdev)
1334*f6d48bfeSjsg 		i915_audio_component_register(i915);
1335*f6d48bfeSjsg }
1336*f6d48bfeSjsg 
1337c349dbc7Sjsg /**
1338c349dbc7Sjsg  * intel_audio_deinit() - deinitialize the audio driver
1339f005ef32Sjsg  * @i915: the i915 drm device private data
1340c349dbc7Sjsg  *
1341c349dbc7Sjsg  */
intel_audio_deinit(struct drm_i915_private * i915)1342f005ef32Sjsg void intel_audio_deinit(struct drm_i915_private *i915)
1343c349dbc7Sjsg {
1344f005ef32Sjsg 	if (i915->display.audio.lpe.platdev != NULL)
1345f005ef32Sjsg 		intel_lpe_audio_teardown(i915);
1346c349dbc7Sjsg 	else
1347f005ef32Sjsg 		i915_audio_component_cleanup(i915);
1348c349dbc7Sjsg }
1349