1*b843c749SSergey Zigachev /*
2*b843c749SSergey Zigachev * Copyright 2012-15 Advanced Micro Devices, Inc.
3*b843c749SSergey Zigachev *
4*b843c749SSergey Zigachev * Permission is hereby granted, free of charge, to any person obtaining a
5*b843c749SSergey Zigachev * copy of this software and associated documentation files (the "Software"),
6*b843c749SSergey Zigachev * to deal in the Software without restriction, including without limitation
7*b843c749SSergey Zigachev * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*b843c749SSergey Zigachev * and/or sell copies of the Software, and to permit persons to whom the
9*b843c749SSergey Zigachev * Software is furnished to do so, subject to the following conditions:
10*b843c749SSergey Zigachev *
11*b843c749SSergey Zigachev * The above copyright notice and this permission notice shall be included in
12*b843c749SSergey Zigachev * all copies or substantial portions of the Software.
13*b843c749SSergey Zigachev *
14*b843c749SSergey Zigachev * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*b843c749SSergey Zigachev * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*b843c749SSergey Zigachev * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17*b843c749SSergey Zigachev * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18*b843c749SSergey Zigachev * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*b843c749SSergey Zigachev * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20*b843c749SSergey Zigachev * OTHER DEALINGS IN THE SOFTWARE.
21*b843c749SSergey Zigachev *
22*b843c749SSergey Zigachev * Authors: AMD
23*b843c749SSergey Zigachev *
24*b843c749SSergey Zigachev */
25*b843c749SSergey Zigachev
26*b843c749SSergey Zigachev #include "reg_helper.h"
27*b843c749SSergey Zigachev #include "dce_audio.h"
28*b843c749SSergey Zigachev #include "dce/dce_11_0_d.h"
29*b843c749SSergey Zigachev #include "dce/dce_11_0_sh_mask.h"
30*b843c749SSergey Zigachev
31*b843c749SSergey Zigachev #define DCE_AUD(audio)\
32*b843c749SSergey Zigachev container_of(audio, struct dce_audio, base)
33*b843c749SSergey Zigachev
34*b843c749SSergey Zigachev #define CTX \
35*b843c749SSergey Zigachev aud->base.ctx
36*b843c749SSergey Zigachev
37*b843c749SSergey Zigachev #define DC_LOGGER_INIT()
38*b843c749SSergey Zigachev
39*b843c749SSergey Zigachev #define REG(reg)\
40*b843c749SSergey Zigachev (aud->regs->reg)
41*b843c749SSergey Zigachev
42*b843c749SSergey Zigachev #undef FN
43*b843c749SSergey Zigachev #define FN(reg_name, field_name) \
44*b843c749SSergey Zigachev aud->shifts->field_name, aud->masks->field_name
45*b843c749SSergey Zigachev
46*b843c749SSergey Zigachev #define IX_REG(reg)\
47*b843c749SSergey Zigachev ix ## reg
48*b843c749SSergey Zigachev
49*b843c749SSergey Zigachev #define AZ_REG_READ(reg_name) \
50*b843c749SSergey Zigachev read_indirect_azalia_reg(audio, IX_REG(reg_name))
51*b843c749SSergey Zigachev
52*b843c749SSergey Zigachev #define AZ_REG_WRITE(reg_name, value) \
53*b843c749SSergey Zigachev write_indirect_azalia_reg(audio, IX_REG(reg_name), value)
54*b843c749SSergey Zigachev
write_indirect_azalia_reg(struct audio * audio,uint32_t reg_index,uint32_t reg_data)55*b843c749SSergey Zigachev static void write_indirect_azalia_reg(struct audio *audio,
56*b843c749SSergey Zigachev uint32_t reg_index,
57*b843c749SSergey Zigachev uint32_t reg_data)
58*b843c749SSergey Zigachev {
59*b843c749SSergey Zigachev struct dce_audio *aud = DCE_AUD(audio);
60*b843c749SSergey Zigachev
61*b843c749SSergey Zigachev /* AZALIA_F0_CODEC_ENDPOINT_INDEX endpoint index */
62*b843c749SSergey Zigachev REG_SET(AZALIA_F0_CODEC_ENDPOINT_INDEX, 0,
63*b843c749SSergey Zigachev AZALIA_ENDPOINT_REG_INDEX, reg_index);
64*b843c749SSergey Zigachev
65*b843c749SSergey Zigachev /* AZALIA_F0_CODEC_ENDPOINT_DATA endpoint data */
66*b843c749SSergey Zigachev REG_SET(AZALIA_F0_CODEC_ENDPOINT_DATA, 0,
67*b843c749SSergey Zigachev AZALIA_ENDPOINT_REG_DATA, reg_data);
68*b843c749SSergey Zigachev
69*b843c749SSergey Zigachev DC_LOG_HW_AUDIO("AUDIO:write_indirect_azalia_reg: index: %u data: %u\n",
70*b843c749SSergey Zigachev reg_index, reg_data);
71*b843c749SSergey Zigachev }
72*b843c749SSergey Zigachev
read_indirect_azalia_reg(struct audio * audio,uint32_t reg_index)73*b843c749SSergey Zigachev static uint32_t read_indirect_azalia_reg(struct audio *audio, uint32_t reg_index)
74*b843c749SSergey Zigachev {
75*b843c749SSergey Zigachev struct dce_audio *aud = DCE_AUD(audio);
76*b843c749SSergey Zigachev
77*b843c749SSergey Zigachev uint32_t value = 0;
78*b843c749SSergey Zigachev
79*b843c749SSergey Zigachev /* AZALIA_F0_CODEC_ENDPOINT_INDEX endpoint index */
80*b843c749SSergey Zigachev REG_SET(AZALIA_F0_CODEC_ENDPOINT_INDEX, 0,
81*b843c749SSergey Zigachev AZALIA_ENDPOINT_REG_INDEX, reg_index);
82*b843c749SSergey Zigachev
83*b843c749SSergey Zigachev /* AZALIA_F0_CODEC_ENDPOINT_DATA endpoint data */
84*b843c749SSergey Zigachev value = REG_READ(AZALIA_F0_CODEC_ENDPOINT_DATA);
85*b843c749SSergey Zigachev
86*b843c749SSergey Zigachev DC_LOG_HW_AUDIO("AUDIO:read_indirect_azalia_reg: index: %u data: %u\n",
87*b843c749SSergey Zigachev reg_index, value);
88*b843c749SSergey Zigachev
89*b843c749SSergey Zigachev return value;
90*b843c749SSergey Zigachev }
91*b843c749SSergey Zigachev
is_audio_format_supported(const struct audio_info * audio_info,enum audio_format_code audio_format_code,uint32_t * format_index)92*b843c749SSergey Zigachev static bool is_audio_format_supported(
93*b843c749SSergey Zigachev const struct audio_info *audio_info,
94*b843c749SSergey Zigachev enum audio_format_code audio_format_code,
95*b843c749SSergey Zigachev uint32_t *format_index)
96*b843c749SSergey Zigachev {
97*b843c749SSergey Zigachev uint32_t index;
98*b843c749SSergey Zigachev uint32_t max_channe_index = 0;
99*b843c749SSergey Zigachev bool found = false;
100*b843c749SSergey Zigachev
101*b843c749SSergey Zigachev if (audio_info == NULL)
102*b843c749SSergey Zigachev return found;
103*b843c749SSergey Zigachev
104*b843c749SSergey Zigachev /* pass through whole array */
105*b843c749SSergey Zigachev for (index = 0; index < audio_info->mode_count; index++) {
106*b843c749SSergey Zigachev if (audio_info->modes[index].format_code == audio_format_code) {
107*b843c749SSergey Zigachev if (found) {
108*b843c749SSergey Zigachev /* format has multiply entries, choose one with
109*b843c749SSergey Zigachev * highst number of channels */
110*b843c749SSergey Zigachev if (audio_info->modes[index].channel_count >
111*b843c749SSergey Zigachev audio_info->modes[max_channe_index].channel_count) {
112*b843c749SSergey Zigachev max_channe_index = index;
113*b843c749SSergey Zigachev }
114*b843c749SSergey Zigachev } else {
115*b843c749SSergey Zigachev /* format found, save it's index */
116*b843c749SSergey Zigachev found = true;
117*b843c749SSergey Zigachev max_channe_index = index;
118*b843c749SSergey Zigachev }
119*b843c749SSergey Zigachev }
120*b843c749SSergey Zigachev }
121*b843c749SSergey Zigachev
122*b843c749SSergey Zigachev /* return index */
123*b843c749SSergey Zigachev if (found && format_index != NULL)
124*b843c749SSergey Zigachev *format_index = max_channe_index;
125*b843c749SSergey Zigachev
126*b843c749SSergey Zigachev return found;
127*b843c749SSergey Zigachev }
128*b843c749SSergey Zigachev
129*b843c749SSergey Zigachev /*For HDMI, calculate if specified sample rates can fit into a given timing */
check_audio_bandwidth_hdmi(const struct audio_crtc_info * crtc_info,uint32_t channel_count,union audio_sample_rates * sample_rates)130*b843c749SSergey Zigachev static void check_audio_bandwidth_hdmi(
131*b843c749SSergey Zigachev const struct audio_crtc_info *crtc_info,
132*b843c749SSergey Zigachev uint32_t channel_count,
133*b843c749SSergey Zigachev union audio_sample_rates *sample_rates)
134*b843c749SSergey Zigachev {
135*b843c749SSergey Zigachev uint32_t samples;
136*b843c749SSergey Zigachev uint32_t h_blank;
137*b843c749SSergey Zigachev bool limit_freq_to_48_khz = false;
138*b843c749SSergey Zigachev bool limit_freq_to_88_2_khz = false;
139*b843c749SSergey Zigachev bool limit_freq_to_96_khz = false;
140*b843c749SSergey Zigachev bool limit_freq_to_174_4_khz = false;
141*b843c749SSergey Zigachev
142*b843c749SSergey Zigachev /* For two channels supported return whatever sink support,unmodified*/
143*b843c749SSergey Zigachev if (channel_count > 2) {
144*b843c749SSergey Zigachev
145*b843c749SSergey Zigachev /* Based on HDMI spec 1.3 Table 7.5 */
146*b843c749SSergey Zigachev if ((crtc_info->requested_pixel_clock <= 27000) &&
147*b843c749SSergey Zigachev (crtc_info->v_active <= 576) &&
148*b843c749SSergey Zigachev !(crtc_info->interlaced) &&
149*b843c749SSergey Zigachev !(crtc_info->pixel_repetition == 2 ||
150*b843c749SSergey Zigachev crtc_info->pixel_repetition == 4)) {
151*b843c749SSergey Zigachev limit_freq_to_48_khz = true;
152*b843c749SSergey Zigachev
153*b843c749SSergey Zigachev } else if ((crtc_info->requested_pixel_clock <= 27000) &&
154*b843c749SSergey Zigachev (crtc_info->v_active <= 576) &&
155*b843c749SSergey Zigachev (crtc_info->interlaced) &&
156*b843c749SSergey Zigachev (crtc_info->pixel_repetition == 2)) {
157*b843c749SSergey Zigachev limit_freq_to_88_2_khz = true;
158*b843c749SSergey Zigachev
159*b843c749SSergey Zigachev } else if ((crtc_info->requested_pixel_clock <= 54000) &&
160*b843c749SSergey Zigachev (crtc_info->v_active <= 576) &&
161*b843c749SSergey Zigachev !(crtc_info->interlaced)) {
162*b843c749SSergey Zigachev limit_freq_to_174_4_khz = true;
163*b843c749SSergey Zigachev }
164*b843c749SSergey Zigachev }
165*b843c749SSergey Zigachev
166*b843c749SSergey Zigachev /* Also do some calculation for the available Audio Bandwidth for the
167*b843c749SSergey Zigachev * 8 ch (i.e. for the Layout 1 => ch > 2)
168*b843c749SSergey Zigachev */
169*b843c749SSergey Zigachev h_blank = crtc_info->h_total - crtc_info->h_active;
170*b843c749SSergey Zigachev
171*b843c749SSergey Zigachev if (crtc_info->pixel_repetition)
172*b843c749SSergey Zigachev h_blank *= crtc_info->pixel_repetition;
173*b843c749SSergey Zigachev
174*b843c749SSergey Zigachev /*based on HDMI spec 1.3 Table 7.5 */
175*b843c749SSergey Zigachev h_blank -= 58;
176*b843c749SSergey Zigachev /*for Control Period */
177*b843c749SSergey Zigachev h_blank -= 16;
178*b843c749SSergey Zigachev
179*b843c749SSergey Zigachev samples = h_blank * 10;
180*b843c749SSergey Zigachev /* Number of Audio Packets (multiplied by 10) per Line (for 8 ch number
181*b843c749SSergey Zigachev * of Audio samples per line multiplied by 10 - Layout 1)
182*b843c749SSergey Zigachev */
183*b843c749SSergey Zigachev samples /= 32;
184*b843c749SSergey Zigachev samples *= crtc_info->v_active;
185*b843c749SSergey Zigachev /*Number of samples multiplied by 10, per second */
186*b843c749SSergey Zigachev samples *= crtc_info->refresh_rate;
187*b843c749SSergey Zigachev /*Number of Audio samples per second */
188*b843c749SSergey Zigachev samples /= 10;
189*b843c749SSergey Zigachev
190*b843c749SSergey Zigachev /* @todo do it after deep color is implemented
191*b843c749SSergey Zigachev * 8xx - deep color bandwidth scaling
192*b843c749SSergey Zigachev * Extra bandwidth is avaliable in deep color b/c link runs faster than
193*b843c749SSergey Zigachev * pixel rate. This has the effect of allowing more tmds characters to
194*b843c749SSergey Zigachev * be transmitted during blank
195*b843c749SSergey Zigachev */
196*b843c749SSergey Zigachev
197*b843c749SSergey Zigachev switch (crtc_info->color_depth) {
198*b843c749SSergey Zigachev case COLOR_DEPTH_888:
199*b843c749SSergey Zigachev samples *= 4;
200*b843c749SSergey Zigachev break;
201*b843c749SSergey Zigachev case COLOR_DEPTH_101010:
202*b843c749SSergey Zigachev samples *= 5;
203*b843c749SSergey Zigachev break;
204*b843c749SSergey Zigachev case COLOR_DEPTH_121212:
205*b843c749SSergey Zigachev samples *= 6;
206*b843c749SSergey Zigachev break;
207*b843c749SSergey Zigachev default:
208*b843c749SSergey Zigachev samples *= 4;
209*b843c749SSergey Zigachev break;
210*b843c749SSergey Zigachev }
211*b843c749SSergey Zigachev
212*b843c749SSergey Zigachev samples /= 4;
213*b843c749SSergey Zigachev
214*b843c749SSergey Zigachev /*check limitation*/
215*b843c749SSergey Zigachev if (samples < 88200)
216*b843c749SSergey Zigachev limit_freq_to_48_khz = true;
217*b843c749SSergey Zigachev else if (samples < 96000)
218*b843c749SSergey Zigachev limit_freq_to_88_2_khz = true;
219*b843c749SSergey Zigachev else if (samples < 176400)
220*b843c749SSergey Zigachev limit_freq_to_96_khz = true;
221*b843c749SSergey Zigachev else if (samples < 192000)
222*b843c749SSergey Zigachev limit_freq_to_174_4_khz = true;
223*b843c749SSergey Zigachev
224*b843c749SSergey Zigachev if (sample_rates != NULL) {
225*b843c749SSergey Zigachev /* limit frequencies */
226*b843c749SSergey Zigachev if (limit_freq_to_174_4_khz)
227*b843c749SSergey Zigachev sample_rates->rate.RATE_192 = 0;
228*b843c749SSergey Zigachev
229*b843c749SSergey Zigachev if (limit_freq_to_96_khz) {
230*b843c749SSergey Zigachev sample_rates->rate.RATE_192 = 0;
231*b843c749SSergey Zigachev sample_rates->rate.RATE_176_4 = 0;
232*b843c749SSergey Zigachev }
233*b843c749SSergey Zigachev if (limit_freq_to_88_2_khz) {
234*b843c749SSergey Zigachev sample_rates->rate.RATE_192 = 0;
235*b843c749SSergey Zigachev sample_rates->rate.RATE_176_4 = 0;
236*b843c749SSergey Zigachev sample_rates->rate.RATE_96 = 0;
237*b843c749SSergey Zigachev }
238*b843c749SSergey Zigachev if (limit_freq_to_48_khz) {
239*b843c749SSergey Zigachev sample_rates->rate.RATE_192 = 0;
240*b843c749SSergey Zigachev sample_rates->rate.RATE_176_4 = 0;
241*b843c749SSergey Zigachev sample_rates->rate.RATE_96 = 0;
242*b843c749SSergey Zigachev sample_rates->rate.RATE_88_2 = 0;
243*b843c749SSergey Zigachev }
244*b843c749SSergey Zigachev }
245*b843c749SSergey Zigachev }
246*b843c749SSergey Zigachev
247*b843c749SSergey Zigachev /*For DP SST, calculate if specified sample rates can fit into a given timing */
check_audio_bandwidth_dpsst(const struct audio_crtc_info * crtc_info,uint32_t channel_count,union audio_sample_rates * sample_rates)248*b843c749SSergey Zigachev static void check_audio_bandwidth_dpsst(
249*b843c749SSergey Zigachev const struct audio_crtc_info *crtc_info,
250*b843c749SSergey Zigachev uint32_t channel_count,
251*b843c749SSergey Zigachev union audio_sample_rates *sample_rates)
252*b843c749SSergey Zigachev {
253*b843c749SSergey Zigachev /* do nothing */
254*b843c749SSergey Zigachev }
255*b843c749SSergey Zigachev
256*b843c749SSergey Zigachev /*For DP MST, calculate if specified sample rates can fit into a given timing */
check_audio_bandwidth_dpmst(const struct audio_crtc_info * crtc_info,uint32_t channel_count,union audio_sample_rates * sample_rates)257*b843c749SSergey Zigachev static void check_audio_bandwidth_dpmst(
258*b843c749SSergey Zigachev const struct audio_crtc_info *crtc_info,
259*b843c749SSergey Zigachev uint32_t channel_count,
260*b843c749SSergey Zigachev union audio_sample_rates *sample_rates)
261*b843c749SSergey Zigachev {
262*b843c749SSergey Zigachev /* do nothing */
263*b843c749SSergey Zigachev }
264*b843c749SSergey Zigachev
check_audio_bandwidth(const struct audio_crtc_info * crtc_info,uint32_t channel_count,enum signal_type signal,union audio_sample_rates * sample_rates)265*b843c749SSergey Zigachev static void check_audio_bandwidth(
266*b843c749SSergey Zigachev const struct audio_crtc_info *crtc_info,
267*b843c749SSergey Zigachev uint32_t channel_count,
268*b843c749SSergey Zigachev enum signal_type signal,
269*b843c749SSergey Zigachev union audio_sample_rates *sample_rates)
270*b843c749SSergey Zigachev {
271*b843c749SSergey Zigachev switch (signal) {
272*b843c749SSergey Zigachev case SIGNAL_TYPE_HDMI_TYPE_A:
273*b843c749SSergey Zigachev check_audio_bandwidth_hdmi(
274*b843c749SSergey Zigachev crtc_info, channel_count, sample_rates);
275*b843c749SSergey Zigachev break;
276*b843c749SSergey Zigachev case SIGNAL_TYPE_EDP:
277*b843c749SSergey Zigachev case SIGNAL_TYPE_DISPLAY_PORT:
278*b843c749SSergey Zigachev check_audio_bandwidth_dpsst(
279*b843c749SSergey Zigachev crtc_info, channel_count, sample_rates);
280*b843c749SSergey Zigachev break;
281*b843c749SSergey Zigachev case SIGNAL_TYPE_DISPLAY_PORT_MST:
282*b843c749SSergey Zigachev check_audio_bandwidth_dpmst(
283*b843c749SSergey Zigachev crtc_info, channel_count, sample_rates);
284*b843c749SSergey Zigachev break;
285*b843c749SSergey Zigachev default:
286*b843c749SSergey Zigachev break;
287*b843c749SSergey Zigachev }
288*b843c749SSergey Zigachev }
289*b843c749SSergey Zigachev
290*b843c749SSergey Zigachev /* expose/not expose HBR capability to Audio driver */
set_high_bit_rate_capable(struct audio * audio,bool capable)291*b843c749SSergey Zigachev static void set_high_bit_rate_capable(
292*b843c749SSergey Zigachev struct audio *audio,
293*b843c749SSergey Zigachev bool capable)
294*b843c749SSergey Zigachev {
295*b843c749SSergey Zigachev uint32_t value = 0;
296*b843c749SSergey Zigachev
297*b843c749SSergey Zigachev /* set high bit rate audio capable*/
298*b843c749SSergey Zigachev value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR);
299*b843c749SSergey Zigachev
300*b843c749SSergey Zigachev set_reg_field_value(value, capable,
301*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR,
302*b843c749SSergey Zigachev HBR_CAPABLE);
303*b843c749SSergey Zigachev
304*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR, value);
305*b843c749SSergey Zigachev }
306*b843c749SSergey Zigachev
307*b843c749SSergey Zigachev /* set video latency in in ms/2+1 */
set_video_latency(struct audio * audio,int latency_in_ms)308*b843c749SSergey Zigachev static void set_video_latency(
309*b843c749SSergey Zigachev struct audio *audio,
310*b843c749SSergey Zigachev int latency_in_ms)
311*b843c749SSergey Zigachev {
312*b843c749SSergey Zigachev uint32_t value = 0;
313*b843c749SSergey Zigachev
314*b843c749SSergey Zigachev if ((latency_in_ms < 0) || (latency_in_ms > 255))
315*b843c749SSergey Zigachev return;
316*b843c749SSergey Zigachev
317*b843c749SSergey Zigachev value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC);
318*b843c749SSergey Zigachev
319*b843c749SSergey Zigachev set_reg_field_value(value, latency_in_ms,
320*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
321*b843c749SSergey Zigachev VIDEO_LIPSYNC);
322*b843c749SSergey Zigachev
323*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
324*b843c749SSergey Zigachev value);
325*b843c749SSergey Zigachev }
326*b843c749SSergey Zigachev
327*b843c749SSergey Zigachev /* set audio latency in in ms/2+1 */
set_audio_latency(struct audio * audio,int latency_in_ms)328*b843c749SSergey Zigachev static void set_audio_latency(
329*b843c749SSergey Zigachev struct audio *audio,
330*b843c749SSergey Zigachev int latency_in_ms)
331*b843c749SSergey Zigachev {
332*b843c749SSergey Zigachev uint32_t value = 0;
333*b843c749SSergey Zigachev
334*b843c749SSergey Zigachev if (latency_in_ms < 0)
335*b843c749SSergey Zigachev latency_in_ms = 0;
336*b843c749SSergey Zigachev
337*b843c749SSergey Zigachev if (latency_in_ms > 255)
338*b843c749SSergey Zigachev latency_in_ms = 255;
339*b843c749SSergey Zigachev
340*b843c749SSergey Zigachev value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC);
341*b843c749SSergey Zigachev
342*b843c749SSergey Zigachev set_reg_field_value(value, latency_in_ms,
343*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
344*b843c749SSergey Zigachev AUDIO_LIPSYNC);
345*b843c749SSergey Zigachev
346*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
347*b843c749SSergey Zigachev value);
348*b843c749SSergey Zigachev }
349*b843c749SSergey Zigachev
dce_aud_az_enable(struct audio * audio)350*b843c749SSergey Zigachev void dce_aud_az_enable(struct audio *audio)
351*b843c749SSergey Zigachev {
352*b843c749SSergey Zigachev uint32_t value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
353*b843c749SSergey Zigachev DC_LOGGER_INIT();
354*b843c749SSergey Zigachev
355*b843c749SSergey Zigachev set_reg_field_value(value, 1,
356*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
357*b843c749SSergey Zigachev CLOCK_GATING_DISABLE);
358*b843c749SSergey Zigachev set_reg_field_value(value, 1,
359*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
360*b843c749SSergey Zigachev AUDIO_ENABLED);
361*b843c749SSergey Zigachev
362*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
363*b843c749SSergey Zigachev set_reg_field_value(value, 0,
364*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
365*b843c749SSergey Zigachev CLOCK_GATING_DISABLE);
366*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
367*b843c749SSergey Zigachev
368*b843c749SSergey Zigachev DC_LOG_HW_AUDIO("\n\t========= AUDIO:dce_aud_az_enable: index: %u data: 0x%x\n",
369*b843c749SSergey Zigachev audio->inst, value);
370*b843c749SSergey Zigachev }
371*b843c749SSergey Zigachev
dce_aud_az_disable(struct audio * audio)372*b843c749SSergey Zigachev void dce_aud_az_disable(struct audio *audio)
373*b843c749SSergey Zigachev {
374*b843c749SSergey Zigachev uint32_t value;
375*b843c749SSergey Zigachev DC_LOGGER_INIT();
376*b843c749SSergey Zigachev
377*b843c749SSergey Zigachev value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
378*b843c749SSergey Zigachev set_reg_field_value(value, 1,
379*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
380*b843c749SSergey Zigachev CLOCK_GATING_DISABLE);
381*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
382*b843c749SSergey Zigachev
383*b843c749SSergey Zigachev set_reg_field_value(value, 0,
384*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
385*b843c749SSergey Zigachev AUDIO_ENABLED);
386*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
387*b843c749SSergey Zigachev
388*b843c749SSergey Zigachev set_reg_field_value(value, 0,
389*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
390*b843c749SSergey Zigachev CLOCK_GATING_DISABLE);
391*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
392*b843c749SSergey Zigachev value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
393*b843c749SSergey Zigachev DC_LOG_HW_AUDIO("\n\t========= AUDIO:dce_aud_az_disable: index: %u data: 0x%x\n",
394*b843c749SSergey Zigachev audio->inst, value);
395*b843c749SSergey Zigachev }
396*b843c749SSergey Zigachev
dce_aud_az_configure(struct audio * audio,enum signal_type signal,const struct audio_crtc_info * crtc_info,const struct audio_info * audio_info)397*b843c749SSergey Zigachev void dce_aud_az_configure(
398*b843c749SSergey Zigachev struct audio *audio,
399*b843c749SSergey Zigachev enum signal_type signal,
400*b843c749SSergey Zigachev const struct audio_crtc_info *crtc_info,
401*b843c749SSergey Zigachev const struct audio_info *audio_info)
402*b843c749SSergey Zigachev {
403*b843c749SSergey Zigachev struct dce_audio *aud = DCE_AUD(audio);
404*b843c749SSergey Zigachev
405*b843c749SSergey Zigachev uint32_t speakers = audio_info->flags.info.ALLSPEAKERS;
406*b843c749SSergey Zigachev uint32_t value;
407*b843c749SSergey Zigachev uint32_t field = 0;
408*b843c749SSergey Zigachev enum audio_format_code audio_format_code;
409*b843c749SSergey Zigachev uint32_t format_index;
410*b843c749SSergey Zigachev uint32_t index;
411*b843c749SSergey Zigachev bool is_ac3_supported = false;
412*b843c749SSergey Zigachev union audio_sample_rates sample_rate;
413*b843c749SSergey Zigachev uint32_t strlen = 0;
414*b843c749SSergey Zigachev value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
415*b843c749SSergey Zigachev set_reg_field_value(value, 1,
416*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
417*b843c749SSergey Zigachev CLOCK_GATING_DISABLE);
418*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
419*b843c749SSergey Zigachev
420*b843c749SSergey Zigachev /* Speaker Allocation */
421*b843c749SSergey Zigachev /*
422*b843c749SSergey Zigachev uint32_t value;
423*b843c749SSergey Zigachev uint32_t field = 0;*/
424*b843c749SSergey Zigachev value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
425*b843c749SSergey Zigachev
426*b843c749SSergey Zigachev set_reg_field_value(value,
427*b843c749SSergey Zigachev speakers,
428*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
429*b843c749SSergey Zigachev SPEAKER_ALLOCATION);
430*b843c749SSergey Zigachev
431*b843c749SSergey Zigachev /* LFE_PLAYBACK_LEVEL = LFEPBL
432*b843c749SSergey Zigachev * LFEPBL = 0 : Unknown or refer to other information
433*b843c749SSergey Zigachev * LFEPBL = 1 : 0dB playback
434*b843c749SSergey Zigachev * LFEPBL = 2 : +10dB playback
435*b843c749SSergey Zigachev * LFE_BL = 3 : Reserved
436*b843c749SSergey Zigachev */
437*b843c749SSergey Zigachev set_reg_field_value(value,
438*b843c749SSergey Zigachev 0,
439*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
440*b843c749SSergey Zigachev LFE_PLAYBACK_LEVEL);
441*b843c749SSergey Zigachev /* todo: according to reg spec LFE_PLAYBACK_LEVEL is read only.
442*b843c749SSergey Zigachev * why are we writing to it? DCE8 does not write this */
443*b843c749SSergey Zigachev
444*b843c749SSergey Zigachev
445*b843c749SSergey Zigachev set_reg_field_value(value,
446*b843c749SSergey Zigachev 0,
447*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
448*b843c749SSergey Zigachev HDMI_CONNECTION);
449*b843c749SSergey Zigachev
450*b843c749SSergey Zigachev set_reg_field_value(value,
451*b843c749SSergey Zigachev 0,
452*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
453*b843c749SSergey Zigachev DP_CONNECTION);
454*b843c749SSergey Zigachev
455*b843c749SSergey Zigachev field = get_reg_field_value(value,
456*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
457*b843c749SSergey Zigachev EXTRA_CONNECTION_INFO);
458*b843c749SSergey Zigachev
459*b843c749SSergey Zigachev field &= ~0x1;
460*b843c749SSergey Zigachev
461*b843c749SSergey Zigachev set_reg_field_value(value,
462*b843c749SSergey Zigachev field,
463*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
464*b843c749SSergey Zigachev EXTRA_CONNECTION_INFO);
465*b843c749SSergey Zigachev
466*b843c749SSergey Zigachev /* set audio for output signal */
467*b843c749SSergey Zigachev switch (signal) {
468*b843c749SSergey Zigachev case SIGNAL_TYPE_HDMI_TYPE_A:
469*b843c749SSergey Zigachev set_reg_field_value(value,
470*b843c749SSergey Zigachev 1,
471*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
472*b843c749SSergey Zigachev HDMI_CONNECTION);
473*b843c749SSergey Zigachev
474*b843c749SSergey Zigachev break;
475*b843c749SSergey Zigachev
476*b843c749SSergey Zigachev case SIGNAL_TYPE_EDP:
477*b843c749SSergey Zigachev case SIGNAL_TYPE_DISPLAY_PORT:
478*b843c749SSergey Zigachev case SIGNAL_TYPE_DISPLAY_PORT_MST:
479*b843c749SSergey Zigachev set_reg_field_value(value,
480*b843c749SSergey Zigachev 1,
481*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
482*b843c749SSergey Zigachev DP_CONNECTION);
483*b843c749SSergey Zigachev break;
484*b843c749SSergey Zigachev default:
485*b843c749SSergey Zigachev BREAK_TO_DEBUGGER();
486*b843c749SSergey Zigachev break;
487*b843c749SSergey Zigachev }
488*b843c749SSergey Zigachev
489*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, value);
490*b843c749SSergey Zigachev
491*b843c749SSergey Zigachev /* Audio Descriptors */
492*b843c749SSergey Zigachev /* pass through all formats */
493*b843c749SSergey Zigachev for (format_index = 0; format_index < AUDIO_FORMAT_CODE_COUNT;
494*b843c749SSergey Zigachev format_index++) {
495*b843c749SSergey Zigachev audio_format_code =
496*b843c749SSergey Zigachev (AUDIO_FORMAT_CODE_FIRST + format_index);
497*b843c749SSergey Zigachev
498*b843c749SSergey Zigachev /* those are unsupported, skip programming */
499*b843c749SSergey Zigachev if (audio_format_code == AUDIO_FORMAT_CODE_1BITAUDIO ||
500*b843c749SSergey Zigachev audio_format_code == AUDIO_FORMAT_CODE_DST)
501*b843c749SSergey Zigachev continue;
502*b843c749SSergey Zigachev
503*b843c749SSergey Zigachev value = 0;
504*b843c749SSergey Zigachev
505*b843c749SSergey Zigachev /* check if supported */
506*b843c749SSergey Zigachev if (is_audio_format_supported(
507*b843c749SSergey Zigachev audio_info, audio_format_code, &index)) {
508*b843c749SSergey Zigachev const struct audio_mode *audio_mode =
509*b843c749SSergey Zigachev &audio_info->modes[index];
510*b843c749SSergey Zigachev union audio_sample_rates sample_rates =
511*b843c749SSergey Zigachev audio_mode->sample_rates;
512*b843c749SSergey Zigachev uint8_t byte2 = audio_mode->max_bit_rate;
513*b843c749SSergey Zigachev
514*b843c749SSergey Zigachev /* adjust specific properties */
515*b843c749SSergey Zigachev switch (audio_format_code) {
516*b843c749SSergey Zigachev case AUDIO_FORMAT_CODE_LINEARPCM: {
517*b843c749SSergey Zigachev check_audio_bandwidth(
518*b843c749SSergey Zigachev crtc_info,
519*b843c749SSergey Zigachev audio_mode->channel_count,
520*b843c749SSergey Zigachev signal,
521*b843c749SSergey Zigachev &sample_rates);
522*b843c749SSergey Zigachev
523*b843c749SSergey Zigachev byte2 = audio_mode->sample_size;
524*b843c749SSergey Zigachev
525*b843c749SSergey Zigachev set_reg_field_value(value,
526*b843c749SSergey Zigachev sample_rates.all,
527*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
528*b843c749SSergey Zigachev SUPPORTED_FREQUENCIES_STEREO);
529*b843c749SSergey Zigachev }
530*b843c749SSergey Zigachev break;
531*b843c749SSergey Zigachev case AUDIO_FORMAT_CODE_AC3:
532*b843c749SSergey Zigachev is_ac3_supported = true;
533*b843c749SSergey Zigachev break;
534*b843c749SSergey Zigachev case AUDIO_FORMAT_CODE_DOLBYDIGITALPLUS:
535*b843c749SSergey Zigachev case AUDIO_FORMAT_CODE_DTS_HD:
536*b843c749SSergey Zigachev case AUDIO_FORMAT_CODE_MAT_MLP:
537*b843c749SSergey Zigachev case AUDIO_FORMAT_CODE_DST:
538*b843c749SSergey Zigachev case AUDIO_FORMAT_CODE_WMAPRO:
539*b843c749SSergey Zigachev byte2 = audio_mode->vendor_specific;
540*b843c749SSergey Zigachev break;
541*b843c749SSergey Zigachev default:
542*b843c749SSergey Zigachev break;
543*b843c749SSergey Zigachev }
544*b843c749SSergey Zigachev
545*b843c749SSergey Zigachev /* fill audio format data */
546*b843c749SSergey Zigachev set_reg_field_value(value,
547*b843c749SSergey Zigachev audio_mode->channel_count - 1,
548*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
549*b843c749SSergey Zigachev MAX_CHANNELS);
550*b843c749SSergey Zigachev
551*b843c749SSergey Zigachev set_reg_field_value(value,
552*b843c749SSergey Zigachev sample_rates.all,
553*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
554*b843c749SSergey Zigachev SUPPORTED_FREQUENCIES);
555*b843c749SSergey Zigachev
556*b843c749SSergey Zigachev set_reg_field_value(value,
557*b843c749SSergey Zigachev byte2,
558*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
559*b843c749SSergey Zigachev DESCRIPTOR_BYTE_2);
560*b843c749SSergey Zigachev } /* if */
561*b843c749SSergey Zigachev
562*b843c749SSergey Zigachev AZ_REG_WRITE(
563*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0 + format_index,
564*b843c749SSergey Zigachev value);
565*b843c749SSergey Zigachev } /* for */
566*b843c749SSergey Zigachev
567*b843c749SSergey Zigachev if (is_ac3_supported)
568*b843c749SSergey Zigachev /* todo: this reg global. why program global register? */
569*b843c749SSergey Zigachev REG_WRITE(AZALIA_F0_CODEC_FUNCTION_PARAMETER_STREAM_FORMATS,
570*b843c749SSergey Zigachev 0x05);
571*b843c749SSergey Zigachev
572*b843c749SSergey Zigachev /* check for 192khz/8-Ch support for HBR requirements */
573*b843c749SSergey Zigachev sample_rate.all = 0;
574*b843c749SSergey Zigachev sample_rate.rate.RATE_192 = 1;
575*b843c749SSergey Zigachev
576*b843c749SSergey Zigachev check_audio_bandwidth(
577*b843c749SSergey Zigachev crtc_info,
578*b843c749SSergey Zigachev 8,
579*b843c749SSergey Zigachev signal,
580*b843c749SSergey Zigachev &sample_rate);
581*b843c749SSergey Zigachev
582*b843c749SSergey Zigachev set_high_bit_rate_capable(audio, sample_rate.rate.RATE_192);
583*b843c749SSergey Zigachev
584*b843c749SSergey Zigachev /* Audio and Video Lipsync */
585*b843c749SSergey Zigachev set_video_latency(audio, audio_info->video_latency);
586*b843c749SSergey Zigachev set_audio_latency(audio, audio_info->audio_latency);
587*b843c749SSergey Zigachev
588*b843c749SSergey Zigachev value = 0;
589*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->manufacture_id,
590*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
591*b843c749SSergey Zigachev MANUFACTURER_ID);
592*b843c749SSergey Zigachev
593*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->product_id,
594*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
595*b843c749SSergey Zigachev PRODUCT_ID);
596*b843c749SSergey Zigachev
597*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
598*b843c749SSergey Zigachev value);
599*b843c749SSergey Zigachev
600*b843c749SSergey Zigachev value = 0;
601*b843c749SSergey Zigachev
602*b843c749SSergey Zigachev /*get display name string length */
603*b843c749SSergey Zigachev while (audio_info->display_name[strlen++] != '\0') {
604*b843c749SSergey Zigachev if (strlen >=
605*b843c749SSergey Zigachev MAX_HW_AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS)
606*b843c749SSergey Zigachev break;
607*b843c749SSergey Zigachev }
608*b843c749SSergey Zigachev set_reg_field_value(value, strlen,
609*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO1,
610*b843c749SSergey Zigachev SINK_DESCRIPTION_LEN);
611*b843c749SSergey Zigachev
612*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO1,
613*b843c749SSergey Zigachev value);
614*b843c749SSergey Zigachev DC_LOG_HW_AUDIO("\n\tAUDIO:az_configure: index: %u data, 0x%x, displayName %s: \n",
615*b843c749SSergey Zigachev audio->inst, value, audio_info->display_name);
616*b843c749SSergey Zigachev
617*b843c749SSergey Zigachev /*
618*b843c749SSergey Zigachev *write the port ID:
619*b843c749SSergey Zigachev *PORT_ID0 = display index
620*b843c749SSergey Zigachev *PORT_ID1 = 16bit BDF
621*b843c749SSergey Zigachev *(format MSB->LSB: 8bit Bus, 5bit Device, 3bit Function)
622*b843c749SSergey Zigachev */
623*b843c749SSergey Zigachev
624*b843c749SSergey Zigachev value = 0;
625*b843c749SSergey Zigachev
626*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->port_id[0],
627*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO2,
628*b843c749SSergey Zigachev PORT_ID0);
629*b843c749SSergey Zigachev
630*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO2, value);
631*b843c749SSergey Zigachev
632*b843c749SSergey Zigachev value = 0;
633*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->port_id[1],
634*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO3,
635*b843c749SSergey Zigachev PORT_ID1);
636*b843c749SSergey Zigachev
637*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO3, value);
638*b843c749SSergey Zigachev
639*b843c749SSergey Zigachev /*write the 18 char monitor string */
640*b843c749SSergey Zigachev
641*b843c749SSergey Zigachev value = 0;
642*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[0],
643*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
644*b843c749SSergey Zigachev DESCRIPTION0);
645*b843c749SSergey Zigachev
646*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[1],
647*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
648*b843c749SSergey Zigachev DESCRIPTION1);
649*b843c749SSergey Zigachev
650*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[2],
651*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
652*b843c749SSergey Zigachev DESCRIPTION2);
653*b843c749SSergey Zigachev
654*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[3],
655*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
656*b843c749SSergey Zigachev DESCRIPTION3);
657*b843c749SSergey Zigachev
658*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4, value);
659*b843c749SSergey Zigachev
660*b843c749SSergey Zigachev value = 0;
661*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[4],
662*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
663*b843c749SSergey Zigachev DESCRIPTION4);
664*b843c749SSergey Zigachev
665*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[5],
666*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
667*b843c749SSergey Zigachev DESCRIPTION5);
668*b843c749SSergey Zigachev
669*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[6],
670*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
671*b843c749SSergey Zigachev DESCRIPTION6);
672*b843c749SSergey Zigachev
673*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[7],
674*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
675*b843c749SSergey Zigachev DESCRIPTION7);
676*b843c749SSergey Zigachev
677*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5, value);
678*b843c749SSergey Zigachev
679*b843c749SSergey Zigachev value = 0;
680*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[8],
681*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
682*b843c749SSergey Zigachev DESCRIPTION8);
683*b843c749SSergey Zigachev
684*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[9],
685*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
686*b843c749SSergey Zigachev DESCRIPTION9);
687*b843c749SSergey Zigachev
688*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[10],
689*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
690*b843c749SSergey Zigachev DESCRIPTION10);
691*b843c749SSergey Zigachev
692*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[11],
693*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
694*b843c749SSergey Zigachev DESCRIPTION11);
695*b843c749SSergey Zigachev
696*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6, value);
697*b843c749SSergey Zigachev
698*b843c749SSergey Zigachev value = 0;
699*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[12],
700*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
701*b843c749SSergey Zigachev DESCRIPTION12);
702*b843c749SSergey Zigachev
703*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[13],
704*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
705*b843c749SSergey Zigachev DESCRIPTION13);
706*b843c749SSergey Zigachev
707*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[14],
708*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
709*b843c749SSergey Zigachev DESCRIPTION14);
710*b843c749SSergey Zigachev
711*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[15],
712*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
713*b843c749SSergey Zigachev DESCRIPTION15);
714*b843c749SSergey Zigachev
715*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7, value);
716*b843c749SSergey Zigachev
717*b843c749SSergey Zigachev value = 0;
718*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[16],
719*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8,
720*b843c749SSergey Zigachev DESCRIPTION16);
721*b843c749SSergey Zigachev
722*b843c749SSergey Zigachev set_reg_field_value(value, audio_info->display_name[17],
723*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8,
724*b843c749SSergey Zigachev DESCRIPTION17);
725*b843c749SSergey Zigachev
726*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8, value);
727*b843c749SSergey Zigachev value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
728*b843c749SSergey Zigachev set_reg_field_value(value, 0,
729*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
730*b843c749SSergey Zigachev CLOCK_GATING_DISABLE);
731*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
732*b843c749SSergey Zigachev }
733*b843c749SSergey Zigachev
734*b843c749SSergey Zigachev /*
735*b843c749SSergey Zigachev * todo: wall clk related functionality probably belong to clock_src.
736*b843c749SSergey Zigachev */
737*b843c749SSergey Zigachev
738*b843c749SSergey Zigachev /* search pixel clock value for Azalia HDMI Audio */
get_azalia_clock_info_hdmi(uint32_t crtc_pixel_clock_in_khz,uint32_t actual_pixel_clock_in_khz,struct azalia_clock_info * azalia_clock_info)739*b843c749SSergey Zigachev static void get_azalia_clock_info_hdmi(
740*b843c749SSergey Zigachev uint32_t crtc_pixel_clock_in_khz,
741*b843c749SSergey Zigachev uint32_t actual_pixel_clock_in_khz,
742*b843c749SSergey Zigachev struct azalia_clock_info *azalia_clock_info)
743*b843c749SSergey Zigachev {
744*b843c749SSergey Zigachev /* audio_dto_phase= 24 * 10,000;
745*b843c749SSergey Zigachev * 24MHz in [100Hz] units */
746*b843c749SSergey Zigachev azalia_clock_info->audio_dto_phase =
747*b843c749SSergey Zigachev 24 * 10000;
748*b843c749SSergey Zigachev
749*b843c749SSergey Zigachev /* audio_dto_module = PCLKFrequency * 10,000;
750*b843c749SSergey Zigachev * [khz] -> [100Hz] */
751*b843c749SSergey Zigachev azalia_clock_info->audio_dto_module =
752*b843c749SSergey Zigachev actual_pixel_clock_in_khz * 10;
753*b843c749SSergey Zigachev }
754*b843c749SSergey Zigachev
get_azalia_clock_info_dp(uint32_t requested_pixel_clock_in_khz,const struct audio_pll_info * pll_info,struct azalia_clock_info * azalia_clock_info)755*b843c749SSergey Zigachev static void get_azalia_clock_info_dp(
756*b843c749SSergey Zigachev uint32_t requested_pixel_clock_in_khz,
757*b843c749SSergey Zigachev const struct audio_pll_info *pll_info,
758*b843c749SSergey Zigachev struct azalia_clock_info *azalia_clock_info)
759*b843c749SSergey Zigachev {
760*b843c749SSergey Zigachev /* Reported dpDtoSourceClockInkhz value for
761*b843c749SSergey Zigachev * DCE8 already adjusted for SS, do not need any
762*b843c749SSergey Zigachev * adjustment here anymore
763*b843c749SSergey Zigachev */
764*b843c749SSergey Zigachev
765*b843c749SSergey Zigachev /*audio_dto_phase = 24 * 10,000;
766*b843c749SSergey Zigachev * 24MHz in [100Hz] units */
767*b843c749SSergey Zigachev azalia_clock_info->audio_dto_phase = 24 * 10000;
768*b843c749SSergey Zigachev
769*b843c749SSergey Zigachev /*audio_dto_module = dpDtoSourceClockInkhz * 10,000;
770*b843c749SSergey Zigachev * [khz] ->[100Hz] */
771*b843c749SSergey Zigachev azalia_clock_info->audio_dto_module =
772*b843c749SSergey Zigachev pll_info->dp_dto_source_clock_in_khz * 10;
773*b843c749SSergey Zigachev }
774*b843c749SSergey Zigachev
dce_aud_wall_dto_setup(struct audio * audio,enum signal_type signal,const struct audio_crtc_info * crtc_info,const struct audio_pll_info * pll_info)775*b843c749SSergey Zigachev void dce_aud_wall_dto_setup(
776*b843c749SSergey Zigachev struct audio *audio,
777*b843c749SSergey Zigachev enum signal_type signal,
778*b843c749SSergey Zigachev const struct audio_crtc_info *crtc_info,
779*b843c749SSergey Zigachev const struct audio_pll_info *pll_info)
780*b843c749SSergey Zigachev {
781*b843c749SSergey Zigachev struct dce_audio *aud = DCE_AUD(audio);
782*b843c749SSergey Zigachev
783*b843c749SSergey Zigachev struct azalia_clock_info clock_info = { 0 };
784*b843c749SSergey Zigachev
785*b843c749SSergey Zigachev if (dc_is_hdmi_signal(signal)) {
786*b843c749SSergey Zigachev uint32_t src_sel;
787*b843c749SSergey Zigachev
788*b843c749SSergey Zigachev /*DTO0 Programming goal:
789*b843c749SSergey Zigachev -generate 24MHz, 128*Fs from 24MHz
790*b843c749SSergey Zigachev -use DTO0 when an active HDMI port is connected
791*b843c749SSergey Zigachev (optionally a DP is connected) */
792*b843c749SSergey Zigachev
793*b843c749SSergey Zigachev /* calculate DTO settings */
794*b843c749SSergey Zigachev get_azalia_clock_info_hdmi(
795*b843c749SSergey Zigachev crtc_info->requested_pixel_clock,
796*b843c749SSergey Zigachev crtc_info->calculated_pixel_clock,
797*b843c749SSergey Zigachev &clock_info);
798*b843c749SSergey Zigachev
799*b843c749SSergey Zigachev DC_LOG_HW_AUDIO("\n%s:Input::requested_pixel_clock = %d"\
800*b843c749SSergey Zigachev "calculated_pixel_clock =%d\n"\
801*b843c749SSergey Zigachev "audio_dto_module = %d audio_dto_phase =%d \n\n", __func__,\
802*b843c749SSergey Zigachev crtc_info->requested_pixel_clock,\
803*b843c749SSergey Zigachev crtc_info->calculated_pixel_clock,\
804*b843c749SSergey Zigachev clock_info.audio_dto_module,\
805*b843c749SSergey Zigachev clock_info.audio_dto_phase);
806*b843c749SSergey Zigachev
807*b843c749SSergey Zigachev /* On TN/SI, Program DTO source select and DTO select before
808*b843c749SSergey Zigachev programming DTO modulo and DTO phase. These bits must be
809*b843c749SSergey Zigachev programmed first, otherwise there will be no HDMI audio at boot
810*b843c749SSergey Zigachev up. This is a HW sequence change (different from old ASICs).
811*b843c749SSergey Zigachev Caution when changing this programming sequence.
812*b843c749SSergey Zigachev
813*b843c749SSergey Zigachev HDMI enabled, using DTO0
814*b843c749SSergey Zigachev program master CRTC for DTO0 */
815*b843c749SSergey Zigachev src_sel = pll_info->dto_source - DTO_SOURCE_ID0;
816*b843c749SSergey Zigachev REG_UPDATE_2(DCCG_AUDIO_DTO_SOURCE,
817*b843c749SSergey Zigachev DCCG_AUDIO_DTO0_SOURCE_SEL, src_sel,
818*b843c749SSergey Zigachev DCCG_AUDIO_DTO_SEL, 0);
819*b843c749SSergey Zigachev
820*b843c749SSergey Zigachev /* module */
821*b843c749SSergey Zigachev REG_UPDATE(DCCG_AUDIO_DTO0_MODULE,
822*b843c749SSergey Zigachev DCCG_AUDIO_DTO0_MODULE, clock_info.audio_dto_module);
823*b843c749SSergey Zigachev
824*b843c749SSergey Zigachev /* phase */
825*b843c749SSergey Zigachev REG_UPDATE(DCCG_AUDIO_DTO0_PHASE,
826*b843c749SSergey Zigachev DCCG_AUDIO_DTO0_PHASE, clock_info.audio_dto_phase);
827*b843c749SSergey Zigachev } else {
828*b843c749SSergey Zigachev /*DTO1 Programming goal:
829*b843c749SSergey Zigachev -generate 24MHz, 512*Fs, 128*Fs from 24MHz
830*b843c749SSergey Zigachev -default is to used DTO1, and switch to DTO0 when an audio
831*b843c749SSergey Zigachev master HDMI port is connected
832*b843c749SSergey Zigachev -use as default for DP
833*b843c749SSergey Zigachev
834*b843c749SSergey Zigachev calculate DTO settings */
835*b843c749SSergey Zigachev get_azalia_clock_info_dp(
836*b843c749SSergey Zigachev crtc_info->requested_pixel_clock,
837*b843c749SSergey Zigachev pll_info,
838*b843c749SSergey Zigachev &clock_info);
839*b843c749SSergey Zigachev
840*b843c749SSergey Zigachev /* Program DTO select before programming DTO modulo and DTO
841*b843c749SSergey Zigachev phase. default to use DTO1 */
842*b843c749SSergey Zigachev
843*b843c749SSergey Zigachev REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
844*b843c749SSergey Zigachev DCCG_AUDIO_DTO_SEL, 1);
845*b843c749SSergey Zigachev
846*b843c749SSergey Zigachev REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
847*b843c749SSergey Zigachev DCCG_AUDIO_DTO_SEL, 1);
848*b843c749SSergey Zigachev /* DCCG_AUDIO_DTO2_USE_512FBR_DTO, 1)
849*b843c749SSergey Zigachev * Select 512fs for DP TODO: web register definition
850*b843c749SSergey Zigachev * does not match register header file
851*b843c749SSergey Zigachev * DCE11 version it's commented out while DCE8 it's set to 1
852*b843c749SSergey Zigachev */
853*b843c749SSergey Zigachev
854*b843c749SSergey Zigachev /* module */
855*b843c749SSergey Zigachev REG_UPDATE(DCCG_AUDIO_DTO1_MODULE,
856*b843c749SSergey Zigachev DCCG_AUDIO_DTO1_MODULE, clock_info.audio_dto_module);
857*b843c749SSergey Zigachev
858*b843c749SSergey Zigachev /* phase */
859*b843c749SSergey Zigachev REG_UPDATE(DCCG_AUDIO_DTO1_PHASE,
860*b843c749SSergey Zigachev DCCG_AUDIO_DTO1_PHASE, clock_info.audio_dto_phase);
861*b843c749SSergey Zigachev
862*b843c749SSergey Zigachev REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
863*b843c749SSergey Zigachev DCCG_AUDIO_DTO2_USE_512FBR_DTO, 1);
864*b843c749SSergey Zigachev
865*b843c749SSergey Zigachev }
866*b843c749SSergey Zigachev }
867*b843c749SSergey Zigachev
dce_aud_endpoint_valid(struct audio * audio)868*b843c749SSergey Zigachev static bool dce_aud_endpoint_valid(struct audio *audio)
869*b843c749SSergey Zigachev {
870*b843c749SSergey Zigachev uint32_t value;
871*b843c749SSergey Zigachev uint32_t port_connectivity;
872*b843c749SSergey Zigachev
873*b843c749SSergey Zigachev value = AZ_REG_READ(
874*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
875*b843c749SSergey Zigachev
876*b843c749SSergey Zigachev port_connectivity = get_reg_field_value(value,
877*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT,
878*b843c749SSergey Zigachev PORT_CONNECTIVITY);
879*b843c749SSergey Zigachev
880*b843c749SSergey Zigachev return !(port_connectivity == 1);
881*b843c749SSergey Zigachev }
882*b843c749SSergey Zigachev
883*b843c749SSergey Zigachev /* initialize HW state */
dce_aud_hw_init(struct audio * audio)884*b843c749SSergey Zigachev void dce_aud_hw_init(
885*b843c749SSergey Zigachev struct audio *audio)
886*b843c749SSergey Zigachev {
887*b843c749SSergey Zigachev uint32_t value;
888*b843c749SSergey Zigachev struct dce_audio *aud = DCE_AUD(audio);
889*b843c749SSergey Zigachev
890*b843c749SSergey Zigachev /* we only need to program the following registers once, so we only do
891*b843c749SSergey Zigachev it for the inst 0*/
892*b843c749SSergey Zigachev if (audio->inst != 0)
893*b843c749SSergey Zigachev return;
894*b843c749SSergey Zigachev
895*b843c749SSergey Zigachev /* Suport R5 - 32khz
896*b843c749SSergey Zigachev * Suport R6 - 44.1khz
897*b843c749SSergey Zigachev * Suport R7 - 48khz
898*b843c749SSergey Zigachev */
899*b843c749SSergey Zigachev /*disable clock gating before write to endpoint register*/
900*b843c749SSergey Zigachev value = AZ_REG_READ(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
901*b843c749SSergey Zigachev set_reg_field_value(value, 1,
902*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
903*b843c749SSergey Zigachev CLOCK_GATING_DISABLE);
904*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
905*b843c749SSergey Zigachev REG_UPDATE(AZALIA_F0_CODEC_FUNCTION_PARAMETER_SUPPORTED_SIZE_RATES,
906*b843c749SSergey Zigachev AUDIO_RATE_CAPABILITIES, 0x70);
907*b843c749SSergey Zigachev
908*b843c749SSergey Zigachev /*Keep alive bit to verify HW block in BU. */
909*b843c749SSergey Zigachev REG_UPDATE_2(AZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES,
910*b843c749SSergey Zigachev CLKSTOP, 1,
911*b843c749SSergey Zigachev EPSS, 1);
912*b843c749SSergey Zigachev set_reg_field_value(value, 0,
913*b843c749SSergey Zigachev AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
914*b843c749SSergey Zigachev CLOCK_GATING_DISABLE);
915*b843c749SSergey Zigachev AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL, value);
916*b843c749SSergey Zigachev }
917*b843c749SSergey Zigachev
918*b843c749SSergey Zigachev static const struct audio_funcs funcs = {
919*b843c749SSergey Zigachev .endpoint_valid = dce_aud_endpoint_valid,
920*b843c749SSergey Zigachev .hw_init = dce_aud_hw_init,
921*b843c749SSergey Zigachev .wall_dto_setup = dce_aud_wall_dto_setup,
922*b843c749SSergey Zigachev .az_enable = dce_aud_az_enable,
923*b843c749SSergey Zigachev .az_disable = dce_aud_az_disable,
924*b843c749SSergey Zigachev .az_configure = dce_aud_az_configure,
925*b843c749SSergey Zigachev .destroy = dce_aud_destroy,
926*b843c749SSergey Zigachev };
dce_aud_destroy(struct audio ** audio)927*b843c749SSergey Zigachev void dce_aud_destroy(struct audio **audio)
928*b843c749SSergey Zigachev {
929*b843c749SSergey Zigachev struct dce_audio *aud = DCE_AUD(*audio);
930*b843c749SSergey Zigachev
931*b843c749SSergey Zigachev kfree(aud);
932*b843c749SSergey Zigachev *audio = NULL;
933*b843c749SSergey Zigachev }
934*b843c749SSergey Zigachev
dce_audio_create(struct dc_context * ctx,unsigned int inst,const struct dce_audio_registers * reg,const struct dce_audio_shift * shifts,const struct dce_aduio_mask * masks)935*b843c749SSergey Zigachev struct audio *dce_audio_create(
936*b843c749SSergey Zigachev struct dc_context *ctx,
937*b843c749SSergey Zigachev unsigned int inst,
938*b843c749SSergey Zigachev const struct dce_audio_registers *reg,
939*b843c749SSergey Zigachev const struct dce_audio_shift *shifts,
940*b843c749SSergey Zigachev const struct dce_aduio_mask *masks
941*b843c749SSergey Zigachev )
942*b843c749SSergey Zigachev {
943*b843c749SSergey Zigachev struct dce_audio *audio = kzalloc(sizeof(*audio), GFP_KERNEL);
944*b843c749SSergey Zigachev
945*b843c749SSergey Zigachev if (audio == NULL) {
946*b843c749SSergey Zigachev ASSERT_CRITICAL(audio);
947*b843c749SSergey Zigachev return NULL;
948*b843c749SSergey Zigachev }
949*b843c749SSergey Zigachev
950*b843c749SSergey Zigachev audio->base.ctx = ctx;
951*b843c749SSergey Zigachev audio->base.inst = inst;
952*b843c749SSergey Zigachev audio->base.funcs = &funcs;
953*b843c749SSergey Zigachev
954*b843c749SSergey Zigachev audio->regs = reg;
955*b843c749SSergey Zigachev audio->shifts = shifts;
956*b843c749SSergey Zigachev audio->masks = masks;
957*b843c749SSergey Zigachev return &audio->base;
958*b843c749SSergey Zigachev }
959*b843c749SSergey Zigachev
960