xref: /dragonfly/sys/dev/drm/radeon/radeon_audio.c (revision 3f2dd94a)
1c59a5c48SFrançois Tigeot /*
2c59a5c48SFrançois Tigeot  * Copyright 2014 Advanced Micro Devices, Inc.
3c59a5c48SFrançois Tigeot  *
4c59a5c48SFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
5c59a5c48SFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
6c59a5c48SFrançois Tigeot  * to deal in the Software without restriction, including without limitation
7c59a5c48SFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c59a5c48SFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
9c59a5c48SFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
10c59a5c48SFrançois Tigeot  *
11c59a5c48SFrançois Tigeot  * The above copyright notice and this permission notice shall be included in
12c59a5c48SFrançois Tigeot  * all copies or substantial portions of the Software.
13c59a5c48SFrançois Tigeot  *
14c59a5c48SFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15c59a5c48SFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16c59a5c48SFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17c59a5c48SFrançois Tigeot  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18c59a5c48SFrançois Tigeot  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19c59a5c48SFrançois Tigeot  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20c59a5c48SFrançois Tigeot  * OTHER DEALINGS IN THE SOFTWARE.
21c59a5c48SFrançois Tigeot  *
22c59a5c48SFrançois Tigeot  * Authors: Slava Grigorev <slava.grigorev@amd.com>
23c59a5c48SFrançois Tigeot  */
24c59a5c48SFrançois Tigeot 
25c59a5c48SFrançois Tigeot #include <linux/gcd.h>
26c59a5c48SFrançois Tigeot #include <drm/drmP.h>
27c59a5c48SFrançois Tigeot #include <drm/drm_crtc.h>
28c59a5c48SFrançois Tigeot #include "radeon.h"
29c59a5c48SFrançois Tigeot #include "atom.h"
30c59a5c48SFrançois Tigeot #include "radeon_audio.h"
31c59a5c48SFrançois Tigeot 
32c59a5c48SFrançois Tigeot #if 0
33c59a5c48SFrançois Tigeot void r600_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
34c59a5c48SFrançois Tigeot 		u8 enable_mask);
35c59a5c48SFrançois Tigeot #endif
36c59a5c48SFrançois Tigeot void dce4_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
37c59a5c48SFrançois Tigeot 		u8 enable_mask);
38c59a5c48SFrançois Tigeot #if 0
39c59a5c48SFrançois Tigeot void dce6_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
40c59a5c48SFrançois Tigeot 		u8 enable_mask);
41c59a5c48SFrançois Tigeot #endif
42c59a5c48SFrançois Tigeot u32 dce6_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg);
43c59a5c48SFrançois Tigeot void dce6_endpoint_wreg(struct radeon_device *rdev,
44c59a5c48SFrançois Tigeot 		u32 offset, u32 reg, u32 v);
45c59a5c48SFrançois Tigeot void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder,
46c59a5c48SFrançois Tigeot 		struct cea_sad *sads, int sad_count);
47c59a5c48SFrançois Tigeot void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder,
48c59a5c48SFrançois Tigeot 		struct cea_sad *sads, int sad_count);
49c59a5c48SFrançois Tigeot void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
50c59a5c48SFrançois Tigeot 		struct cea_sad *sads, int sad_count);
51c59a5c48SFrançois Tigeot void dce3_2_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
52c59a5c48SFrançois Tigeot 		u8 *sadb, int sad_count);
53c59a5c48SFrançois Tigeot void dce3_2_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
54c59a5c48SFrançois Tigeot 		u8 *sadb, int sad_count);
55c59a5c48SFrançois Tigeot void dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
56c59a5c48SFrançois Tigeot 		u8 *sadb, int sad_count);
57c59a5c48SFrançois Tigeot void dce4_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
58c59a5c48SFrançois Tigeot 		u8 *sadb, int sad_count);
59c59a5c48SFrançois Tigeot void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
60c59a5c48SFrançois Tigeot 		u8 *sadb, int sad_count);
61c59a5c48SFrançois Tigeot void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
62c59a5c48SFrançois Tigeot 		u8 *sadb, int sad_count);
63c59a5c48SFrançois Tigeot void dce4_afmt_write_latency_fields(struct drm_encoder *encoder,
64c59a5c48SFrançois Tigeot 		struct drm_connector *connector, struct drm_display_mode *mode);
65c59a5c48SFrançois Tigeot void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
66c59a5c48SFrançois Tigeot 		struct drm_connector *connector, struct drm_display_mode *mode);
67c59a5c48SFrançois Tigeot #if 0
68c59a5c48SFrançois Tigeot struct r600_audio_pin* r600_audio_get_pin(struct radeon_device *rdev);
69c59a5c48SFrançois Tigeot struct r600_audio_pin* dce6_audio_get_pin(struct radeon_device *rdev);
70c59a5c48SFrançois Tigeot #endif
71c59a5c48SFrançois Tigeot void dce6_afmt_select_pin(struct drm_encoder *encoder);
72c59a5c48SFrançois Tigeot void r600_hdmi_audio_set_dto(struct radeon_device *rdev,
73c59a5c48SFrançois Tigeot 	struct radeon_crtc *crtc, unsigned int clock);
74c59a5c48SFrançois Tigeot void dce3_2_audio_set_dto(struct radeon_device *rdev,
75c59a5c48SFrançois Tigeot 	struct radeon_crtc *crtc, unsigned int clock);
76c59a5c48SFrançois Tigeot void dce4_hdmi_audio_set_dto(struct radeon_device *rdev,
77c59a5c48SFrançois Tigeot 	struct radeon_crtc *crtc, unsigned int clock);
78c59a5c48SFrançois Tigeot void dce4_dp_audio_set_dto(struct radeon_device *rdev,
79c59a5c48SFrançois Tigeot 	struct radeon_crtc *crtc, unsigned int clock);
80c59a5c48SFrançois Tigeot void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
81c59a5c48SFrançois Tigeot 	struct radeon_crtc *crtc, unsigned int clock);
82c59a5c48SFrançois Tigeot void dce6_dp_audio_set_dto(struct radeon_device *rdev,
83c59a5c48SFrançois Tigeot 	struct radeon_crtc *crtc, unsigned int clock);
84c59a5c48SFrançois Tigeot void r600_set_avi_packet(struct radeon_device *rdev, u32 offset,
85c59a5c48SFrançois Tigeot 	unsigned char *buffer, size_t size);
86c59a5c48SFrançois Tigeot void evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset,
87c59a5c48SFrançois Tigeot 	unsigned char *buffer, size_t size);
88c59a5c48SFrançois Tigeot void r600_hdmi_update_acr(struct drm_encoder *encoder, long offset,
89c59a5c48SFrançois Tigeot 	const struct radeon_hdmi_acr *acr);
90c59a5c48SFrançois Tigeot void dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset,
91c59a5c48SFrançois Tigeot 	const struct radeon_hdmi_acr *acr);
92c59a5c48SFrançois Tigeot void evergreen_hdmi_update_acr(struct drm_encoder *encoder, long offset,
93c59a5c48SFrançois Tigeot 	const struct radeon_hdmi_acr *acr);
94c59a5c48SFrançois Tigeot void r600_set_vbi_packet(struct drm_encoder *encoder, u32 offset);
95c59a5c48SFrançois Tigeot void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset);
96c59a5c48SFrançois Tigeot void dce4_hdmi_set_color_depth(struct drm_encoder *encoder,
97c59a5c48SFrançois Tigeot 	u32 offset, int bpc);
98c59a5c48SFrançois Tigeot void r600_set_audio_packet(struct drm_encoder *encoder, u32 offset);
99c59a5c48SFrançois Tigeot void dce3_2_set_audio_packet(struct drm_encoder *encoder, u32 offset);
100c59a5c48SFrançois Tigeot void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset);
101c59a5c48SFrançois Tigeot void r600_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
102c59a5c48SFrançois Tigeot void dce3_2_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
103c59a5c48SFrançois Tigeot void dce4_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
104c59a5c48SFrançois Tigeot static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
105c59a5c48SFrançois Tigeot 	struct drm_display_mode *mode);
106c59a5c48SFrançois Tigeot static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
107c59a5c48SFrançois Tigeot 	struct drm_display_mode *mode);
108c59a5c48SFrançois Tigeot void r600_hdmi_enable(struct drm_encoder *encoder, bool enable);
109c59a5c48SFrançois Tigeot void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
110c59a5c48SFrançois Tigeot void evergreen_dp_enable(struct drm_encoder *encoder, bool enable);
111c59a5c48SFrançois Tigeot 
112c59a5c48SFrançois Tigeot static const u32 pin_offsets[7] =
113c59a5c48SFrançois Tigeot {
114c59a5c48SFrançois Tigeot 	(0x5e00 - 0x5e00),
115c59a5c48SFrançois Tigeot 	(0x5e18 - 0x5e00),
116c59a5c48SFrançois Tigeot 	(0x5e30 - 0x5e00),
117c59a5c48SFrançois Tigeot 	(0x5e48 - 0x5e00),
118c59a5c48SFrançois Tigeot 	(0x5e60 - 0x5e00),
119c59a5c48SFrançois Tigeot 	(0x5e78 - 0x5e00),
120c59a5c48SFrançois Tigeot 	(0x5e90 - 0x5e00),
121c59a5c48SFrançois Tigeot };
122c59a5c48SFrançois Tigeot 
radeon_audio_rreg(struct radeon_device * rdev,u32 offset,u32 reg)123c59a5c48SFrançois Tigeot static u32 radeon_audio_rreg(struct radeon_device *rdev, u32 offset, u32 reg)
124c59a5c48SFrançois Tigeot {
125c59a5c48SFrançois Tigeot 	return RREG32(reg);
126c59a5c48SFrançois Tigeot }
127c59a5c48SFrançois Tigeot 
radeon_audio_wreg(struct radeon_device * rdev,u32 offset,u32 reg,u32 v)128c59a5c48SFrançois Tigeot static void radeon_audio_wreg(struct radeon_device *rdev, u32 offset,
129c59a5c48SFrançois Tigeot 		u32 reg, u32 v)
130c59a5c48SFrançois Tigeot {
131c59a5c48SFrançois Tigeot 	WREG32(reg, v);
132c59a5c48SFrançois Tigeot }
133c59a5c48SFrançois Tigeot 
134c59a5c48SFrançois Tigeot static struct radeon_audio_basic_funcs r600_funcs = {
135c59a5c48SFrançois Tigeot 	.endpoint_rreg = radeon_audio_rreg,
136c59a5c48SFrançois Tigeot 	.endpoint_wreg = radeon_audio_wreg,
137c59a5c48SFrançois Tigeot 	.enable = r600_audio_enable,
138c59a5c48SFrançois Tigeot };
139c59a5c48SFrançois Tigeot 
140c59a5c48SFrançois Tigeot static struct radeon_audio_basic_funcs dce32_funcs = {
141c59a5c48SFrançois Tigeot 	.endpoint_rreg = radeon_audio_rreg,
142c59a5c48SFrançois Tigeot 	.endpoint_wreg = radeon_audio_wreg,
143c59a5c48SFrançois Tigeot 	.enable = r600_audio_enable,
144c59a5c48SFrançois Tigeot };
145c59a5c48SFrançois Tigeot 
146c59a5c48SFrançois Tigeot static struct radeon_audio_basic_funcs dce4_funcs = {
147c59a5c48SFrançois Tigeot 	.endpoint_rreg = radeon_audio_rreg,
148c59a5c48SFrançois Tigeot 	.endpoint_wreg = radeon_audio_wreg,
149c59a5c48SFrançois Tigeot 	.enable = dce4_audio_enable,
150c59a5c48SFrançois Tigeot };
151c59a5c48SFrançois Tigeot 
152c59a5c48SFrançois Tigeot static struct radeon_audio_basic_funcs dce6_funcs = {
153c59a5c48SFrançois Tigeot 	.endpoint_rreg = dce6_endpoint_rreg,
154c59a5c48SFrançois Tigeot 	.endpoint_wreg = dce6_endpoint_wreg,
155c59a5c48SFrançois Tigeot 	.enable = dce6_audio_enable,
156c59a5c48SFrançois Tigeot };
157c59a5c48SFrançois Tigeot 
158c59a5c48SFrançois Tigeot static struct radeon_audio_funcs r600_hdmi_funcs = {
159c59a5c48SFrançois Tigeot 	.get_pin = r600_audio_get_pin,
160c59a5c48SFrançois Tigeot 	.set_dto = r600_hdmi_audio_set_dto,
161c59a5c48SFrançois Tigeot 	.update_acr = r600_hdmi_update_acr,
162c59a5c48SFrançois Tigeot 	.set_vbi_packet = r600_set_vbi_packet,
163c59a5c48SFrançois Tigeot 	.set_avi_packet = r600_set_avi_packet,
164c59a5c48SFrançois Tigeot 	.set_audio_packet = r600_set_audio_packet,
165c59a5c48SFrançois Tigeot 	.set_mute = r600_set_mute,
166c59a5c48SFrançois Tigeot 	.mode_set = radeon_audio_hdmi_mode_set,
167c59a5c48SFrançois Tigeot 	.dpms = r600_hdmi_enable,
168c59a5c48SFrançois Tigeot };
169c59a5c48SFrançois Tigeot 
170c59a5c48SFrançois Tigeot static struct radeon_audio_funcs dce32_hdmi_funcs = {
171c59a5c48SFrançois Tigeot 	.get_pin = r600_audio_get_pin,
172c59a5c48SFrançois Tigeot 	.write_sad_regs = dce3_2_afmt_write_sad_regs,
173c59a5c48SFrançois Tigeot 	.write_speaker_allocation = dce3_2_afmt_hdmi_write_speaker_allocation,
174c59a5c48SFrançois Tigeot 	.set_dto = dce3_2_audio_set_dto,
175c59a5c48SFrançois Tigeot 	.update_acr = dce3_2_hdmi_update_acr,
176c59a5c48SFrançois Tigeot 	.set_vbi_packet = r600_set_vbi_packet,
177c59a5c48SFrançois Tigeot 	.set_avi_packet = r600_set_avi_packet,
178c59a5c48SFrançois Tigeot 	.set_audio_packet = dce3_2_set_audio_packet,
179c59a5c48SFrançois Tigeot 	.set_mute = dce3_2_set_mute,
180c59a5c48SFrançois Tigeot 	.mode_set = radeon_audio_hdmi_mode_set,
181c59a5c48SFrançois Tigeot 	.dpms = r600_hdmi_enable,
182c59a5c48SFrançois Tigeot };
183c59a5c48SFrançois Tigeot 
184c59a5c48SFrançois Tigeot static struct radeon_audio_funcs dce32_dp_funcs = {
185c59a5c48SFrançois Tigeot 	.get_pin = r600_audio_get_pin,
186c59a5c48SFrançois Tigeot 	.write_sad_regs = dce3_2_afmt_write_sad_regs,
187c59a5c48SFrançois Tigeot 	.write_speaker_allocation = dce3_2_afmt_dp_write_speaker_allocation,
188c59a5c48SFrançois Tigeot 	.set_dto = dce3_2_audio_set_dto,
189c59a5c48SFrançois Tigeot 	.set_avi_packet = r600_set_avi_packet,
190c59a5c48SFrançois Tigeot 	.set_audio_packet = dce3_2_set_audio_packet,
191c59a5c48SFrançois Tigeot };
192c59a5c48SFrançois Tigeot 
193c59a5c48SFrançois Tigeot static struct radeon_audio_funcs dce4_hdmi_funcs = {
194c59a5c48SFrançois Tigeot 	.get_pin = r600_audio_get_pin,
195c59a5c48SFrançois Tigeot 	.write_sad_regs = evergreen_hdmi_write_sad_regs,
196c59a5c48SFrançois Tigeot 	.write_speaker_allocation = dce4_afmt_hdmi_write_speaker_allocation,
197c59a5c48SFrançois Tigeot 	.write_latency_fields = dce4_afmt_write_latency_fields,
198c59a5c48SFrançois Tigeot 	.set_dto = dce4_hdmi_audio_set_dto,
199c59a5c48SFrançois Tigeot 	.update_acr = evergreen_hdmi_update_acr,
200c59a5c48SFrançois Tigeot 	.set_vbi_packet = dce4_set_vbi_packet,
201c59a5c48SFrançois Tigeot 	.set_color_depth = dce4_hdmi_set_color_depth,
202c59a5c48SFrançois Tigeot 	.set_avi_packet = evergreen_set_avi_packet,
203c59a5c48SFrançois Tigeot 	.set_audio_packet = dce4_set_audio_packet,
204c59a5c48SFrançois Tigeot 	.set_mute = dce4_set_mute,
205c59a5c48SFrançois Tigeot 	.mode_set = radeon_audio_hdmi_mode_set,
206c59a5c48SFrançois Tigeot 	.dpms = evergreen_hdmi_enable,
207c59a5c48SFrançois Tigeot };
208c59a5c48SFrançois Tigeot 
209c59a5c48SFrançois Tigeot static struct radeon_audio_funcs dce4_dp_funcs = {
210c59a5c48SFrançois Tigeot 	.get_pin = r600_audio_get_pin,
211c59a5c48SFrançois Tigeot 	.write_sad_regs = evergreen_hdmi_write_sad_regs,
212c59a5c48SFrançois Tigeot 	.write_speaker_allocation = dce4_afmt_dp_write_speaker_allocation,
213c59a5c48SFrançois Tigeot 	.write_latency_fields = dce4_afmt_write_latency_fields,
214c59a5c48SFrançois Tigeot 	.set_dto = dce4_dp_audio_set_dto,
215c59a5c48SFrançois Tigeot 	.set_avi_packet = evergreen_set_avi_packet,
216c59a5c48SFrançois Tigeot 	.set_audio_packet = dce4_set_audio_packet,
217c59a5c48SFrançois Tigeot 	.mode_set = radeon_audio_dp_mode_set,
218c59a5c48SFrançois Tigeot 	.dpms = evergreen_dp_enable,
219c59a5c48SFrançois Tigeot };
220c59a5c48SFrançois Tigeot 
221c59a5c48SFrançois Tigeot static struct radeon_audio_funcs dce6_hdmi_funcs = {
222c59a5c48SFrançois Tigeot 	.select_pin = dce6_afmt_select_pin,
223c59a5c48SFrançois Tigeot 	.get_pin = dce6_audio_get_pin,
224c59a5c48SFrançois Tigeot 	.write_sad_regs = dce6_afmt_write_sad_regs,
225c59a5c48SFrançois Tigeot 	.write_speaker_allocation = dce6_afmt_hdmi_write_speaker_allocation,
226c59a5c48SFrançois Tigeot 	.write_latency_fields = dce6_afmt_write_latency_fields,
227c59a5c48SFrançois Tigeot 	.set_dto = dce6_hdmi_audio_set_dto,
228c59a5c48SFrançois Tigeot 	.update_acr = evergreen_hdmi_update_acr,
229c59a5c48SFrançois Tigeot 	.set_vbi_packet = dce4_set_vbi_packet,
230c59a5c48SFrançois Tigeot 	.set_color_depth = dce4_hdmi_set_color_depth,
231c59a5c48SFrançois Tigeot 	.set_avi_packet = evergreen_set_avi_packet,
232c59a5c48SFrançois Tigeot 	.set_audio_packet = dce4_set_audio_packet,
233c59a5c48SFrançois Tigeot 	.set_mute = dce4_set_mute,
234c59a5c48SFrançois Tigeot 	.mode_set = radeon_audio_hdmi_mode_set,
235c59a5c48SFrançois Tigeot 	.dpms = evergreen_hdmi_enable,
236c59a5c48SFrançois Tigeot };
237c59a5c48SFrançois Tigeot 
238c59a5c48SFrançois Tigeot static struct radeon_audio_funcs dce6_dp_funcs = {
239c59a5c48SFrançois Tigeot 	.select_pin = dce6_afmt_select_pin,
240c59a5c48SFrançois Tigeot 	.get_pin = dce6_audio_get_pin,
241c59a5c48SFrançois Tigeot 	.write_sad_regs = dce6_afmt_write_sad_regs,
242c59a5c48SFrançois Tigeot 	.write_speaker_allocation = dce6_afmt_dp_write_speaker_allocation,
243c59a5c48SFrançois Tigeot 	.write_latency_fields = dce6_afmt_write_latency_fields,
244c59a5c48SFrançois Tigeot 	.set_dto = dce6_dp_audio_set_dto,
245c59a5c48SFrançois Tigeot 	.set_avi_packet = evergreen_set_avi_packet,
246c59a5c48SFrançois Tigeot 	.set_audio_packet = dce4_set_audio_packet,
247c59a5c48SFrançois Tigeot 	.mode_set = radeon_audio_dp_mode_set,
248c59a5c48SFrançois Tigeot 	.dpms = evergreen_dp_enable,
249c59a5c48SFrançois Tigeot };
250c59a5c48SFrançois Tigeot 
radeon_audio_enable(struct radeon_device * rdev,struct r600_audio_pin * pin,u8 enable_mask)251c59a5c48SFrançois Tigeot static void radeon_audio_enable(struct radeon_device *rdev,
252c59a5c48SFrançois Tigeot 				struct r600_audio_pin *pin, u8 enable_mask)
253c59a5c48SFrançois Tigeot {
254c59a5c48SFrançois Tigeot 	struct drm_encoder *encoder;
255c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder;
256c59a5c48SFrançois Tigeot 	struct radeon_encoder_atom_dig *dig;
257c59a5c48SFrançois Tigeot 	int pin_count = 0;
258c59a5c48SFrançois Tigeot 
259c59a5c48SFrançois Tigeot 	if (!pin)
260c59a5c48SFrançois Tigeot 		return;
261c59a5c48SFrançois Tigeot 
262c59a5c48SFrançois Tigeot 	if (rdev->mode_info.mode_config_initialized) {
263c59a5c48SFrançois Tigeot 		list_for_each_entry(encoder, &rdev->ddev->mode_config.encoder_list, head) {
264c59a5c48SFrançois Tigeot 			if (radeon_encoder_is_digital(encoder)) {
265c59a5c48SFrançois Tigeot 				radeon_encoder = to_radeon_encoder(encoder);
266c59a5c48SFrançois Tigeot 				dig = radeon_encoder->enc_priv;
267c59a5c48SFrançois Tigeot 				if (dig->pin == pin)
268c59a5c48SFrançois Tigeot 					pin_count++;
269c59a5c48SFrançois Tigeot 			}
270c59a5c48SFrançois Tigeot 		}
271c59a5c48SFrançois Tigeot 
272c59a5c48SFrançois Tigeot 		if ((pin_count > 1) && (enable_mask == 0))
273c59a5c48SFrançois Tigeot 			return;
274c59a5c48SFrançois Tigeot 	}
275c59a5c48SFrançois Tigeot 
276c59a5c48SFrançois Tigeot 	if (rdev->audio.funcs->enable)
277c59a5c48SFrançois Tigeot 		rdev->audio.funcs->enable(rdev, pin, enable_mask);
278c59a5c48SFrançois Tigeot }
279c59a5c48SFrançois Tigeot 
radeon_audio_interface_init(struct radeon_device * rdev)280c59a5c48SFrançois Tigeot static void radeon_audio_interface_init(struct radeon_device *rdev)
281c59a5c48SFrançois Tigeot {
282c59a5c48SFrançois Tigeot 	if (ASIC_IS_DCE6(rdev)) {
283c59a5c48SFrançois Tigeot 		rdev->audio.funcs = &dce6_funcs;
284c59a5c48SFrançois Tigeot 		rdev->audio.hdmi_funcs = &dce6_hdmi_funcs;
285c59a5c48SFrançois Tigeot 		rdev->audio.dp_funcs = &dce6_dp_funcs;
286c59a5c48SFrançois Tigeot 	} else if (ASIC_IS_DCE4(rdev)) {
287c59a5c48SFrançois Tigeot 		rdev->audio.funcs = &dce4_funcs;
288c59a5c48SFrançois Tigeot 		rdev->audio.hdmi_funcs = &dce4_hdmi_funcs;
289c59a5c48SFrançois Tigeot 		rdev->audio.dp_funcs = &dce4_dp_funcs;
290c59a5c48SFrançois Tigeot 	} else if (ASIC_IS_DCE32(rdev)) {
291c59a5c48SFrançois Tigeot 		rdev->audio.funcs = &dce32_funcs;
292c59a5c48SFrançois Tigeot 		rdev->audio.hdmi_funcs = &dce32_hdmi_funcs;
293c59a5c48SFrançois Tigeot 		rdev->audio.dp_funcs = &dce32_dp_funcs;
294c59a5c48SFrançois Tigeot 	} else {
295c59a5c48SFrançois Tigeot 		rdev->audio.funcs = &r600_funcs;
296c59a5c48SFrançois Tigeot 		rdev->audio.hdmi_funcs = &r600_hdmi_funcs;
297c59a5c48SFrançois Tigeot 		rdev->audio.dp_funcs = 0;
298c59a5c48SFrançois Tigeot 	}
299c59a5c48SFrançois Tigeot }
300c59a5c48SFrançois Tigeot 
radeon_audio_chipset_supported(struct radeon_device * rdev)301c59a5c48SFrançois Tigeot static int radeon_audio_chipset_supported(struct radeon_device *rdev)
302c59a5c48SFrançois Tigeot {
303c59a5c48SFrançois Tigeot 	return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
304c59a5c48SFrançois Tigeot }
305c59a5c48SFrançois Tigeot 
radeon_audio_init(struct radeon_device * rdev)306c59a5c48SFrançois Tigeot int radeon_audio_init(struct radeon_device *rdev)
307c59a5c48SFrançois Tigeot {
308c59a5c48SFrançois Tigeot 	int i;
309c59a5c48SFrançois Tigeot 
310c59a5c48SFrançois Tigeot 	if (!radeon_audio || !radeon_audio_chipset_supported(rdev))
311c59a5c48SFrançois Tigeot 		return 0;
312c59a5c48SFrançois Tigeot 
313c59a5c48SFrançois Tigeot 	rdev->audio.enabled = true;
314c59a5c48SFrançois Tigeot 
315c59a5c48SFrançois Tigeot 	if (ASIC_IS_DCE83(rdev))		/* KB: 2 streams, 3 endpoints */
316c59a5c48SFrançois Tigeot 		rdev->audio.num_pins = 3;
317c59a5c48SFrançois Tigeot 	else if (ASIC_IS_DCE81(rdev))	/* KV: 4 streams, 7 endpoints */
318c59a5c48SFrançois Tigeot 		rdev->audio.num_pins = 7;
319c59a5c48SFrançois Tigeot 	else if (ASIC_IS_DCE8(rdev))	/* BN/HW: 6 streams, 7 endpoints */
320c59a5c48SFrançois Tigeot 		rdev->audio.num_pins = 7;
321c59a5c48SFrançois Tigeot 	else if (ASIC_IS_DCE64(rdev))	/* OL: 2 streams, 2 endpoints */
322c59a5c48SFrançois Tigeot 		rdev->audio.num_pins = 2;
323c59a5c48SFrançois Tigeot 	else if (ASIC_IS_DCE61(rdev))	/* TN: 4 streams, 6 endpoints */
324c59a5c48SFrançois Tigeot 		rdev->audio.num_pins = 6;
325c59a5c48SFrançois Tigeot 	else if (ASIC_IS_DCE6(rdev))	/* SI: 6 streams, 6 endpoints */
326c59a5c48SFrançois Tigeot 		rdev->audio.num_pins = 6;
327c59a5c48SFrançois Tigeot 	else
328c59a5c48SFrançois Tigeot 		rdev->audio.num_pins = 1;
329c59a5c48SFrançois Tigeot 
330c59a5c48SFrançois Tigeot 	for (i = 0; i < rdev->audio.num_pins; i++) {
331c59a5c48SFrançois Tigeot 		rdev->audio.pin[i].channels = -1;
332c59a5c48SFrançois Tigeot 		rdev->audio.pin[i].rate = -1;
333c59a5c48SFrançois Tigeot 		rdev->audio.pin[i].bits_per_sample = -1;
334c59a5c48SFrançois Tigeot 		rdev->audio.pin[i].status_bits = 0;
335c59a5c48SFrançois Tigeot 		rdev->audio.pin[i].category_code = 0;
336c59a5c48SFrançois Tigeot 		rdev->audio.pin[i].connected = false;
337c59a5c48SFrançois Tigeot 		rdev->audio.pin[i].offset = pin_offsets[i];
338c59a5c48SFrançois Tigeot 		rdev->audio.pin[i].id = i;
339c59a5c48SFrançois Tigeot 	}
340c59a5c48SFrançois Tigeot 
341c59a5c48SFrançois Tigeot 	radeon_audio_interface_init(rdev);
342c59a5c48SFrançois Tigeot 
343c59a5c48SFrançois Tigeot 	/* disable audio.  it will be set up later */
344c59a5c48SFrançois Tigeot 	for (i = 0; i < rdev->audio.num_pins; i++)
345c59a5c48SFrançois Tigeot 		radeon_audio_enable(rdev, &rdev->audio.pin[i], 0);
346c59a5c48SFrançois Tigeot 
347c59a5c48SFrançois Tigeot 	return 0;
348c59a5c48SFrançois Tigeot }
349c59a5c48SFrançois Tigeot 
radeon_audio_endpoint_rreg(struct radeon_device * rdev,u32 offset,u32 reg)350c59a5c48SFrançois Tigeot u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg)
351c59a5c48SFrançois Tigeot {
352c59a5c48SFrançois Tigeot 	if (rdev->audio.funcs->endpoint_rreg)
353c59a5c48SFrançois Tigeot 		return rdev->audio.funcs->endpoint_rreg(rdev, offset, reg);
354c59a5c48SFrançois Tigeot 
355c59a5c48SFrançois Tigeot 	return 0;
356c59a5c48SFrançois Tigeot }
357c59a5c48SFrançois Tigeot 
radeon_audio_endpoint_wreg(struct radeon_device * rdev,u32 offset,u32 reg,u32 v)358c59a5c48SFrançois Tigeot void radeon_audio_endpoint_wreg(struct radeon_device *rdev, u32 offset,
359c59a5c48SFrançois Tigeot 	u32 reg, u32 v)
360c59a5c48SFrançois Tigeot {
361c59a5c48SFrançois Tigeot 	if (rdev->audio.funcs->endpoint_wreg)
362c59a5c48SFrançois Tigeot 		rdev->audio.funcs->endpoint_wreg(rdev, offset, reg, v);
363c59a5c48SFrançois Tigeot }
364c59a5c48SFrançois Tigeot 
radeon_audio_write_sad_regs(struct drm_encoder * encoder)365c59a5c48SFrançois Tigeot static void radeon_audio_write_sad_regs(struct drm_encoder *encoder)
366c59a5c48SFrançois Tigeot {
367c59a5c48SFrançois Tigeot 	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
368c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
369c59a5c48SFrançois Tigeot 	struct cea_sad *sads;
370c59a5c48SFrançois Tigeot 	int sad_count;
371c59a5c48SFrançois Tigeot 
372c59a5c48SFrançois Tigeot 	if (!connector)
373c59a5c48SFrançois Tigeot 		return;
374c59a5c48SFrançois Tigeot 
375c59a5c48SFrançois Tigeot 	sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads);
376c59a5c48SFrançois Tigeot 	if (sad_count <= 0) {
377c59a5c48SFrançois Tigeot 		DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
378c59a5c48SFrançois Tigeot 		return;
379c59a5c48SFrançois Tigeot 	}
380c59a5c48SFrançois Tigeot 	BUG_ON(!sads);
381c59a5c48SFrançois Tigeot 
382c59a5c48SFrançois Tigeot 	if (radeon_encoder->audio && radeon_encoder->audio->write_sad_regs)
383c59a5c48SFrançois Tigeot 		radeon_encoder->audio->write_sad_regs(encoder, sads, sad_count);
384c59a5c48SFrançois Tigeot 
385c59a5c48SFrançois Tigeot 	kfree(sads);
386c59a5c48SFrançois Tigeot }
387c59a5c48SFrançois Tigeot 
radeon_audio_write_speaker_allocation(struct drm_encoder * encoder)388c59a5c48SFrançois Tigeot static void radeon_audio_write_speaker_allocation(struct drm_encoder *encoder)
389c59a5c48SFrançois Tigeot {
390c59a5c48SFrançois Tigeot 	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
391c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
392c59a5c48SFrançois Tigeot 	u8 *sadb = NULL;
393c59a5c48SFrançois Tigeot 	int sad_count;
394c59a5c48SFrançois Tigeot 
395c59a5c48SFrançois Tigeot 	if (!connector)
396c59a5c48SFrançois Tigeot 		return;
397c59a5c48SFrançois Tigeot 
398c59a5c48SFrançois Tigeot 	sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector),
399c59a5c48SFrançois Tigeot 						   &sadb);
400c59a5c48SFrançois Tigeot 	if (sad_count < 0) {
401c59a5c48SFrançois Tigeot 		DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n",
402c59a5c48SFrançois Tigeot 			  sad_count);
403c59a5c48SFrançois Tigeot 		sad_count = 0;
404c59a5c48SFrançois Tigeot 	}
405c59a5c48SFrançois Tigeot 
406c59a5c48SFrançois Tigeot 	if (radeon_encoder->audio && radeon_encoder->audio->write_speaker_allocation)
407c59a5c48SFrançois Tigeot 		radeon_encoder->audio->write_speaker_allocation(encoder, sadb, sad_count);
408c59a5c48SFrançois Tigeot 
409c59a5c48SFrançois Tigeot 	kfree(sadb);
410c59a5c48SFrançois Tigeot }
411c59a5c48SFrançois Tigeot 
radeon_audio_write_latency_fields(struct drm_encoder * encoder,struct drm_display_mode * mode)412c59a5c48SFrançois Tigeot static void radeon_audio_write_latency_fields(struct drm_encoder *encoder,
413c59a5c48SFrançois Tigeot 					      struct drm_display_mode *mode)
414c59a5c48SFrançois Tigeot {
415c59a5c48SFrançois Tigeot 	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
416c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
417c59a5c48SFrançois Tigeot 
418c59a5c48SFrançois Tigeot 	if (!connector)
419c59a5c48SFrançois Tigeot 		return;
420c59a5c48SFrançois Tigeot 
421c59a5c48SFrançois Tigeot 	if (radeon_encoder->audio && radeon_encoder->audio->write_latency_fields)
422c59a5c48SFrançois Tigeot 		radeon_encoder->audio->write_latency_fields(encoder, connector, mode);
423c59a5c48SFrançois Tigeot }
424c59a5c48SFrançois Tigeot 
radeon_audio_get_pin(struct drm_encoder * encoder)425c59a5c48SFrançois Tigeot struct r600_audio_pin* radeon_audio_get_pin(struct drm_encoder *encoder)
426c59a5c48SFrançois Tigeot {
427c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = encoder->dev->dev_private;
428c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
429c59a5c48SFrançois Tigeot 
430c59a5c48SFrançois Tigeot 	if (radeon_encoder->audio && radeon_encoder->audio->get_pin)
431c59a5c48SFrançois Tigeot 		return radeon_encoder->audio->get_pin(rdev);
432c59a5c48SFrançois Tigeot 
433c59a5c48SFrançois Tigeot 	return NULL;
434c59a5c48SFrançois Tigeot }
435c59a5c48SFrançois Tigeot 
radeon_audio_select_pin(struct drm_encoder * encoder)436c59a5c48SFrançois Tigeot static void radeon_audio_select_pin(struct drm_encoder *encoder)
437c59a5c48SFrançois Tigeot {
438c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
439c59a5c48SFrançois Tigeot 
440c59a5c48SFrançois Tigeot 	if (radeon_encoder->audio && radeon_encoder->audio->select_pin)
441c59a5c48SFrançois Tigeot 		radeon_encoder->audio->select_pin(encoder);
442c59a5c48SFrançois Tigeot }
443c59a5c48SFrançois Tigeot 
radeon_audio_detect(struct drm_connector * connector,struct drm_encoder * encoder,enum drm_connector_status status)444c59a5c48SFrançois Tigeot void radeon_audio_detect(struct drm_connector *connector,
445c59a5c48SFrançois Tigeot 			 struct drm_encoder *encoder,
446c59a5c48SFrançois Tigeot 			 enum drm_connector_status status)
447c59a5c48SFrançois Tigeot {
448c59a5c48SFrançois Tigeot 	struct drm_device *dev = connector->dev;
449c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
450c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
451c59a5c48SFrançois Tigeot 	struct radeon_encoder_atom_dig *dig;
452c59a5c48SFrançois Tigeot 
453c59a5c48SFrançois Tigeot 	if (!radeon_audio_chipset_supported(rdev))
454c59a5c48SFrançois Tigeot 		return;
455c59a5c48SFrançois Tigeot 
456c59a5c48SFrançois Tigeot 	if (!radeon_encoder_is_digital(encoder))
457c59a5c48SFrançois Tigeot 		return;
458c59a5c48SFrançois Tigeot 
459c59a5c48SFrançois Tigeot 	dig = radeon_encoder->enc_priv;
460c59a5c48SFrançois Tigeot 
461c59a5c48SFrançois Tigeot 	if (status == connector_status_connected) {
462c59a5c48SFrançois Tigeot 		if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
463c59a5c48SFrançois Tigeot 			struct radeon_connector *radeon_connector = to_radeon_connector(connector);
464c59a5c48SFrançois Tigeot 
465c59a5c48SFrançois Tigeot 			if (radeon_dp_getsinktype(radeon_connector) ==
466c59a5c48SFrançois Tigeot 			    CONNECTOR_OBJECT_ID_DISPLAYPORT)
467c59a5c48SFrançois Tigeot 				radeon_encoder->audio = rdev->audio.dp_funcs;
468c59a5c48SFrançois Tigeot 			else
469c59a5c48SFrançois Tigeot 				radeon_encoder->audio = rdev->audio.hdmi_funcs;
470c59a5c48SFrançois Tigeot 		} else {
471c59a5c48SFrançois Tigeot 			radeon_encoder->audio = rdev->audio.hdmi_funcs;
472c59a5c48SFrançois Tigeot 		}
473c59a5c48SFrançois Tigeot 
474c59a5c48SFrançois Tigeot 		if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
475c59a5c48SFrançois Tigeot 			if (!dig->pin)
476c59a5c48SFrançois Tigeot 				dig->pin = radeon_audio_get_pin(encoder);
477c59a5c48SFrançois Tigeot 			radeon_audio_enable(rdev, dig->pin, 0xf);
478c59a5c48SFrançois Tigeot 		} else {
479c59a5c48SFrançois Tigeot 			radeon_audio_enable(rdev, dig->pin, 0);
480c59a5c48SFrançois Tigeot 			dig->pin = NULL;
481c59a5c48SFrançois Tigeot 		}
482c59a5c48SFrançois Tigeot 	} else {
483c59a5c48SFrançois Tigeot 		radeon_audio_enable(rdev, dig->pin, 0);
484c59a5c48SFrançois Tigeot 		dig->pin = NULL;
485c59a5c48SFrançois Tigeot 	}
486c59a5c48SFrançois Tigeot }
487c59a5c48SFrançois Tigeot 
radeon_audio_fini(struct radeon_device * rdev)488c59a5c48SFrançois Tigeot void radeon_audio_fini(struct radeon_device *rdev)
489c59a5c48SFrançois Tigeot {
490c59a5c48SFrançois Tigeot 	int i;
491c59a5c48SFrançois Tigeot 
492c59a5c48SFrançois Tigeot 	if (!rdev->audio.enabled)
493c59a5c48SFrançois Tigeot 		return;
494c59a5c48SFrançois Tigeot 
495c59a5c48SFrançois Tigeot 	for (i = 0; i < rdev->audio.num_pins; i++)
496c59a5c48SFrançois Tigeot 		radeon_audio_enable(rdev, &rdev->audio.pin[i], 0);
497c59a5c48SFrançois Tigeot 
498c59a5c48SFrançois Tigeot 	rdev->audio.enabled = false;
499c59a5c48SFrançois Tigeot }
500c59a5c48SFrançois Tigeot 
radeon_audio_set_dto(struct drm_encoder * encoder,unsigned int clock)501c59a5c48SFrançois Tigeot static void radeon_audio_set_dto(struct drm_encoder *encoder, unsigned int clock)
502c59a5c48SFrançois Tigeot {
503c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = encoder->dev->dev_private;
504c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
505c59a5c48SFrançois Tigeot 	struct radeon_crtc *crtc = to_radeon_crtc(encoder->crtc);
506c59a5c48SFrançois Tigeot 
507c59a5c48SFrançois Tigeot 	if (radeon_encoder->audio && radeon_encoder->audio->set_dto)
508c59a5c48SFrançois Tigeot 		radeon_encoder->audio->set_dto(rdev, crtc, clock);
509c59a5c48SFrançois Tigeot }
510c59a5c48SFrançois Tigeot 
radeon_audio_set_avi_packet(struct drm_encoder * encoder,struct drm_display_mode * mode)511c59a5c48SFrançois Tigeot static int radeon_audio_set_avi_packet(struct drm_encoder *encoder,
512c59a5c48SFrançois Tigeot 				       struct drm_display_mode *mode)
513c59a5c48SFrançois Tigeot {
514c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = encoder->dev->dev_private;
515c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
516c59a5c48SFrançois Tigeot 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
517c59a5c48SFrançois Tigeot 	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
518c59a5c48SFrançois Tigeot 	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
519c59a5c48SFrançois Tigeot 	struct hdmi_avi_infoframe frame;
520c59a5c48SFrançois Tigeot 	int err;
521c59a5c48SFrançois Tigeot 
522c59a5c48SFrançois Tigeot 	if (!connector)
523c59a5c48SFrançois Tigeot 		return -EINVAL;
524c59a5c48SFrançois Tigeot 
525*3f2dd94aSFrançois Tigeot 	err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
526c59a5c48SFrançois Tigeot 	if (err < 0) {
527c59a5c48SFrançois Tigeot 		DRM_ERROR("failed to setup AVI infoframe: %d\n", err);
528c59a5c48SFrançois Tigeot 		return err;
529c59a5c48SFrançois Tigeot 	}
530c59a5c48SFrançois Tigeot 
531c59a5c48SFrançois Tigeot 	if (radeon_encoder->output_csc != RADEON_OUTPUT_CSC_BYPASS) {
532c59a5c48SFrançois Tigeot 		if (drm_rgb_quant_range_selectable(radeon_connector_edid(connector))) {
533c59a5c48SFrançois Tigeot 			if (radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB)
534c59a5c48SFrançois Tigeot 				frame.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED;
535c59a5c48SFrançois Tigeot 			else
536c59a5c48SFrançois Tigeot 				frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL;
537c59a5c48SFrançois Tigeot 		} else {
538c59a5c48SFrançois Tigeot 			frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
539c59a5c48SFrançois Tigeot 		}
540c59a5c48SFrançois Tigeot 	}
541c59a5c48SFrançois Tigeot 
542c59a5c48SFrançois Tigeot 	err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
543c59a5c48SFrançois Tigeot 	if (err < 0) {
544c59a5c48SFrançois Tigeot 		DRM_ERROR("failed to pack AVI infoframe: %d\n", err);
545c59a5c48SFrançois Tigeot 		return err;
546c59a5c48SFrançois Tigeot 	}
547c59a5c48SFrançois Tigeot 
548c59a5c48SFrançois Tigeot 	if (dig && dig->afmt && radeon_encoder->audio &&
549c59a5c48SFrançois Tigeot 	    radeon_encoder->audio->set_avi_packet)
550c59a5c48SFrançois Tigeot 		radeon_encoder->audio->set_avi_packet(rdev, dig->afmt->offset,
551c59a5c48SFrançois Tigeot 			buffer, sizeof(buffer));
552c59a5c48SFrançois Tigeot 
553c59a5c48SFrançois Tigeot 	return 0;
554c59a5c48SFrançois Tigeot }
555c59a5c48SFrançois Tigeot 
556c59a5c48SFrançois Tigeot /*
557c59a5c48SFrançois Tigeot  * calculate CTS and N values if they are not found in the table
558c59a5c48SFrançois Tigeot  */
radeon_audio_calc_cts(unsigned int clock,int * CTS,int * N,int freq)559c59a5c48SFrançois Tigeot static void radeon_audio_calc_cts(unsigned int clock, int *CTS, int *N, int freq)
560c59a5c48SFrançois Tigeot {
561c59a5c48SFrançois Tigeot 	int n, cts;
562c59a5c48SFrançois Tigeot 	unsigned long div, mul;
563c59a5c48SFrançois Tigeot 
564c59a5c48SFrançois Tigeot 	/* Safe, but overly large values */
565c59a5c48SFrançois Tigeot 	n = 128 * freq;
566c59a5c48SFrançois Tigeot 	cts = clock * 1000;
567c59a5c48SFrançois Tigeot 
568c59a5c48SFrançois Tigeot 	/* Smallest valid fraction */
569c59a5c48SFrançois Tigeot 	div = gcd(n, cts);
570c59a5c48SFrançois Tigeot 
571c59a5c48SFrançois Tigeot 	n /= div;
572c59a5c48SFrançois Tigeot 	cts /= div;
573c59a5c48SFrançois Tigeot 
574c59a5c48SFrançois Tigeot 	/*
575c59a5c48SFrançois Tigeot 	 * The optimal N is 128*freq/1000. Calculate the closest larger
576c59a5c48SFrançois Tigeot 	 * value that doesn't truncate any bits.
577c59a5c48SFrançois Tigeot 	 */
578c59a5c48SFrançois Tigeot 	mul = ((128*freq/1000) + (n-1))/n;
579c59a5c48SFrançois Tigeot 
580c59a5c48SFrançois Tigeot 	n *= mul;
581c59a5c48SFrançois Tigeot 	cts *= mul;
582c59a5c48SFrançois Tigeot 
583c59a5c48SFrançois Tigeot 	/* Check that we are in spec (not always possible) */
584c59a5c48SFrançois Tigeot 	if (n < (128*freq/1500))
585a85cb24fSFrançois Tigeot 		pr_warn("Calculated ACR N value is too small. You may experience audio problems.\n");
586c59a5c48SFrançois Tigeot 	if (n > (128*freq/300))
587a85cb24fSFrançois Tigeot 		pr_warn("Calculated ACR N value is too large. You may experience audio problems.\n");
588c59a5c48SFrançois Tigeot 
589c59a5c48SFrançois Tigeot 	*N = n;
590c59a5c48SFrançois Tigeot 	*CTS = cts;
591c59a5c48SFrançois Tigeot 
592c59a5c48SFrançois Tigeot 	DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n",
593c59a5c48SFrançois Tigeot 		*N, *CTS, freq);
594c59a5c48SFrançois Tigeot }
595c59a5c48SFrançois Tigeot 
radeon_audio_acr(unsigned int clock)596c59a5c48SFrançois Tigeot static const struct radeon_hdmi_acr* radeon_audio_acr(unsigned int clock)
597c59a5c48SFrançois Tigeot {
598c59a5c48SFrançois Tigeot 	static struct radeon_hdmi_acr res;
599c59a5c48SFrançois Tigeot 	u8 i;
600c59a5c48SFrançois Tigeot 
601c59a5c48SFrançois Tigeot 	static const struct radeon_hdmi_acr hdmi_predefined_acr[] = {
602c59a5c48SFrançois Tigeot 		/*       32kHz    44.1kHz   48kHz    */
603c59a5c48SFrançois Tigeot 		/* Clock      N     CTS      N     CTS      N     CTS */
604c59a5c48SFrançois Tigeot 		{  25175,  4096,  25175, 28224, 125875,  6144,  25175 }, /*  25,20/1.001 MHz */
605c59a5c48SFrançois Tigeot 		{  25200,  4096,  25200,  6272,  28000,  6144,  25200 }, /*  25.20       MHz */
606c59a5c48SFrançois Tigeot 		{  27000,  4096,  27000,  6272,  30000,  6144,  27000 }, /*  27.00       MHz */
607c59a5c48SFrançois Tigeot 		{  27027,  4096,  27027,  6272,  30030,  6144,  27027 }, /*  27.00*1.001 MHz */
608c59a5c48SFrançois Tigeot 		{  54000,  4096,  54000,  6272,  60000,  6144,  54000 }, /*  54.00       MHz */
609c59a5c48SFrançois Tigeot 		{  54054,  4096,  54054,  6272,  60060,  6144,  54054 }, /*  54.00*1.001 MHz */
610c59a5c48SFrançois Tigeot 		{  74176,  4096,  74176,  5733,  75335,  6144,  74176 }, /*  74.25/1.001 MHz */
611c59a5c48SFrançois Tigeot 		{  74250,  4096,  74250,  6272,  82500,  6144,  74250 }, /*  74.25       MHz */
612c59a5c48SFrançois Tigeot 		{ 148352,  4096, 148352,  5733, 150670,  6144, 148352 }, /* 148.50/1.001 MHz */
613c59a5c48SFrançois Tigeot 		{ 148500,  4096, 148500,  6272, 165000,  6144, 148500 }, /* 148.50       MHz */
614c59a5c48SFrançois Tigeot 	};
615c59a5c48SFrançois Tigeot 
616c59a5c48SFrançois Tigeot 	/* Precalculated values for common clocks */
617c59a5c48SFrançois Tigeot 	for (i = 0; i < ARRAY_SIZE(hdmi_predefined_acr); i++)
618c59a5c48SFrançois Tigeot 		if (hdmi_predefined_acr[i].clock == clock)
619c59a5c48SFrançois Tigeot 			return &hdmi_predefined_acr[i];
620c59a5c48SFrançois Tigeot 
621c59a5c48SFrançois Tigeot 	/* And odd clocks get manually calculated */
622c59a5c48SFrançois Tigeot 	radeon_audio_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000);
623c59a5c48SFrançois Tigeot 	radeon_audio_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100);
624c59a5c48SFrançois Tigeot 	radeon_audio_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000);
625c59a5c48SFrançois Tigeot 
626c59a5c48SFrançois Tigeot 	return &res;
627c59a5c48SFrançois Tigeot }
628c59a5c48SFrançois Tigeot 
629c59a5c48SFrançois Tigeot /*
630c59a5c48SFrançois Tigeot  * update the N and CTS parameters for a given pixel clock rate
631c59a5c48SFrançois Tigeot  */
radeon_audio_update_acr(struct drm_encoder * encoder,unsigned int clock)632c59a5c48SFrançois Tigeot static void radeon_audio_update_acr(struct drm_encoder *encoder, unsigned int clock)
633c59a5c48SFrançois Tigeot {
634c59a5c48SFrançois Tigeot 	const struct radeon_hdmi_acr *acr = radeon_audio_acr(clock);
635c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
636c59a5c48SFrançois Tigeot 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
637c59a5c48SFrançois Tigeot 
638c59a5c48SFrançois Tigeot 	if (!dig || !dig->afmt)
639c59a5c48SFrançois Tigeot 		return;
640c59a5c48SFrançois Tigeot 
641c59a5c48SFrançois Tigeot 	if (radeon_encoder->audio && radeon_encoder->audio->update_acr)
642c59a5c48SFrançois Tigeot 		radeon_encoder->audio->update_acr(encoder, dig->afmt->offset, acr);
643c59a5c48SFrançois Tigeot }
644c59a5c48SFrançois Tigeot 
radeon_audio_set_vbi_packet(struct drm_encoder * encoder)645c59a5c48SFrançois Tigeot static void radeon_audio_set_vbi_packet(struct drm_encoder *encoder)
646c59a5c48SFrançois Tigeot {
647c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
648c59a5c48SFrançois Tigeot 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
649c59a5c48SFrançois Tigeot 
650c59a5c48SFrançois Tigeot 	if (!dig || !dig->afmt)
651c59a5c48SFrançois Tigeot 		return;
652c59a5c48SFrançois Tigeot 
653c59a5c48SFrançois Tigeot 	if (radeon_encoder->audio && radeon_encoder->audio->set_vbi_packet)
654c59a5c48SFrançois Tigeot 		radeon_encoder->audio->set_vbi_packet(encoder, dig->afmt->offset);
655c59a5c48SFrançois Tigeot }
656c59a5c48SFrançois Tigeot 
radeon_hdmi_set_color_depth(struct drm_encoder * encoder)657c59a5c48SFrançois Tigeot static void radeon_hdmi_set_color_depth(struct drm_encoder *encoder)
658c59a5c48SFrançois Tigeot {
659c59a5c48SFrançois Tigeot 	int bpc = 8;
660c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
661c59a5c48SFrançois Tigeot 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
662c59a5c48SFrançois Tigeot 
663c59a5c48SFrançois Tigeot 	if (!dig || !dig->afmt)
664c59a5c48SFrançois Tigeot 		return;
665c59a5c48SFrançois Tigeot 
666c59a5c48SFrançois Tigeot 	if (encoder->crtc) {
667c59a5c48SFrançois Tigeot 		struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
668c59a5c48SFrançois Tigeot 		bpc = radeon_crtc->bpc;
669c59a5c48SFrançois Tigeot 	}
670c59a5c48SFrançois Tigeot 
671c59a5c48SFrançois Tigeot 	if (radeon_encoder->audio && radeon_encoder->audio->set_color_depth)
672c59a5c48SFrançois Tigeot 		radeon_encoder->audio->set_color_depth(encoder, dig->afmt->offset, bpc);
673c59a5c48SFrançois Tigeot }
674c59a5c48SFrançois Tigeot 
radeon_audio_set_audio_packet(struct drm_encoder * encoder)675c59a5c48SFrançois Tigeot static void radeon_audio_set_audio_packet(struct drm_encoder *encoder)
676c59a5c48SFrançois Tigeot {
677c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
678c59a5c48SFrançois Tigeot 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
679c59a5c48SFrançois Tigeot 
680c59a5c48SFrançois Tigeot 	if (!dig || !dig->afmt)
681c59a5c48SFrançois Tigeot 		return;
682c59a5c48SFrançois Tigeot 
683c59a5c48SFrançois Tigeot 	if (radeon_encoder->audio && radeon_encoder->audio->set_audio_packet)
684c59a5c48SFrançois Tigeot 		radeon_encoder->audio->set_audio_packet(encoder, dig->afmt->offset);
685c59a5c48SFrançois Tigeot }
686c59a5c48SFrançois Tigeot 
radeon_audio_set_mute(struct drm_encoder * encoder,bool mute)687c59a5c48SFrançois Tigeot static void radeon_audio_set_mute(struct drm_encoder *encoder, bool mute)
688c59a5c48SFrançois Tigeot {
689c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
690c59a5c48SFrançois Tigeot 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
691c59a5c48SFrançois Tigeot 
692c59a5c48SFrançois Tigeot 	if (!dig || !dig->afmt)
693c59a5c48SFrançois Tigeot 		return;
694c59a5c48SFrançois Tigeot 
695c59a5c48SFrançois Tigeot 	if (radeon_encoder->audio && radeon_encoder->audio->set_mute)
696c59a5c48SFrançois Tigeot 		radeon_encoder->audio->set_mute(encoder, dig->afmt->offset, mute);
697c59a5c48SFrançois Tigeot }
698c59a5c48SFrançois Tigeot 
699c59a5c48SFrançois Tigeot /*
700c59a5c48SFrançois Tigeot  * update the info frames with the data from the current display mode
701c59a5c48SFrançois Tigeot  */
radeon_audio_hdmi_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode)702c59a5c48SFrançois Tigeot static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
703c59a5c48SFrançois Tigeot 				       struct drm_display_mode *mode)
704c59a5c48SFrançois Tigeot {
705c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
706c59a5c48SFrançois Tigeot 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
707c59a5c48SFrançois Tigeot 	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
708c59a5c48SFrançois Tigeot 
709c59a5c48SFrançois Tigeot 	if (!dig || !dig->afmt)
710c59a5c48SFrançois Tigeot 		return;
711c59a5c48SFrançois Tigeot 
712c59a5c48SFrançois Tigeot 	if (!connector)
713c59a5c48SFrançois Tigeot 		return;
714c59a5c48SFrançois Tigeot 
715c59a5c48SFrançois Tigeot 	if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
716c59a5c48SFrançois Tigeot 		radeon_audio_set_mute(encoder, true);
717c59a5c48SFrançois Tigeot 
718c59a5c48SFrançois Tigeot 		radeon_audio_write_speaker_allocation(encoder);
719c59a5c48SFrançois Tigeot 		radeon_audio_write_sad_regs(encoder);
720c59a5c48SFrançois Tigeot 		radeon_audio_write_latency_fields(encoder, mode);
721c59a5c48SFrançois Tigeot 		radeon_audio_set_dto(encoder, mode->clock);
722c59a5c48SFrançois Tigeot 		radeon_audio_set_vbi_packet(encoder);
723c59a5c48SFrançois Tigeot 		radeon_hdmi_set_color_depth(encoder);
724c59a5c48SFrançois Tigeot 		radeon_audio_update_acr(encoder, mode->clock);
725c59a5c48SFrançois Tigeot 		radeon_audio_set_audio_packet(encoder);
726c59a5c48SFrançois Tigeot 		radeon_audio_select_pin(encoder);
727c59a5c48SFrançois Tigeot 
728c59a5c48SFrançois Tigeot 		if (radeon_audio_set_avi_packet(encoder, mode) < 0)
729c59a5c48SFrançois Tigeot 			return;
730c59a5c48SFrançois Tigeot 
731c59a5c48SFrançois Tigeot 		radeon_audio_set_mute(encoder, false);
732c59a5c48SFrançois Tigeot 	} else {
733c59a5c48SFrançois Tigeot 		radeon_hdmi_set_color_depth(encoder);
734c59a5c48SFrançois Tigeot 
735c59a5c48SFrançois Tigeot 		if (radeon_audio_set_avi_packet(encoder, mode) < 0)
736c59a5c48SFrançois Tigeot 			return;
737c59a5c48SFrançois Tigeot 	}
738c59a5c48SFrançois Tigeot }
739c59a5c48SFrançois Tigeot 
radeon_audio_dp_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode)740c59a5c48SFrançois Tigeot static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
741c59a5c48SFrançois Tigeot 				     struct drm_display_mode *mode)
742c59a5c48SFrançois Tigeot {
743c59a5c48SFrançois Tigeot 	struct drm_device *dev = encoder->dev;
744c59a5c48SFrançois Tigeot 	struct radeon_device *rdev = dev->dev_private;
745c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
746c59a5c48SFrançois Tigeot 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
747c59a5c48SFrançois Tigeot 	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
748c59a5c48SFrançois Tigeot 
749c59a5c48SFrançois Tigeot 	if (!dig || !dig->afmt)
750c59a5c48SFrançois Tigeot 		return;
751c59a5c48SFrançois Tigeot 
752c59a5c48SFrançois Tigeot 	if (!connector)
753c59a5c48SFrançois Tigeot 		return;
754c59a5c48SFrançois Tigeot 
755c59a5c48SFrançois Tigeot 	if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
756c59a5c48SFrançois Tigeot 		radeon_audio_write_speaker_allocation(encoder);
757c59a5c48SFrançois Tigeot 		radeon_audio_write_sad_regs(encoder);
758c59a5c48SFrançois Tigeot 		radeon_audio_write_latency_fields(encoder, mode);
759c59a5c48SFrançois Tigeot 		radeon_audio_set_dto(encoder, rdev->clock.vco_freq * 10);
760c59a5c48SFrançois Tigeot 		radeon_audio_set_audio_packet(encoder);
761c59a5c48SFrançois Tigeot 		radeon_audio_select_pin(encoder);
762c59a5c48SFrançois Tigeot 
763c59a5c48SFrançois Tigeot 		if (radeon_audio_set_avi_packet(encoder, mode) < 0)
764c59a5c48SFrançois Tigeot 			return;
765c59a5c48SFrançois Tigeot 	}
766c59a5c48SFrançois Tigeot }
767c59a5c48SFrançois Tigeot 
radeon_audio_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode)768c59a5c48SFrançois Tigeot void radeon_audio_mode_set(struct drm_encoder *encoder,
769c59a5c48SFrançois Tigeot 			   struct drm_display_mode *mode)
770c59a5c48SFrançois Tigeot {
771c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
772c59a5c48SFrançois Tigeot 
773c59a5c48SFrançois Tigeot 	if (radeon_encoder->audio && radeon_encoder->audio->mode_set)
774c59a5c48SFrançois Tigeot 		radeon_encoder->audio->mode_set(encoder, mode);
775c59a5c48SFrançois Tigeot }
776c59a5c48SFrançois Tigeot 
radeon_audio_dpms(struct drm_encoder * encoder,int mode)777c59a5c48SFrançois Tigeot void radeon_audio_dpms(struct drm_encoder *encoder, int mode)
778c59a5c48SFrançois Tigeot {
779c59a5c48SFrançois Tigeot 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
780c59a5c48SFrançois Tigeot 
781c59a5c48SFrançois Tigeot 	if (radeon_encoder->audio && radeon_encoder->audio->dpms)
782c59a5c48SFrançois Tigeot 		radeon_encoder->audio->dpms(encoder, mode == DRM_MODE_DPMS_ON);
783c59a5c48SFrançois Tigeot }
784c59a5c48SFrançois Tigeot 
radeon_audio_decode_dfs_div(unsigned int div)785c59a5c48SFrançois Tigeot unsigned int radeon_audio_decode_dfs_div(unsigned int div)
786c59a5c48SFrançois Tigeot {
787c59a5c48SFrançois Tigeot 	if (div >= 8 && div < 64)
788c59a5c48SFrançois Tigeot 		return (div - 8) * 25 + 200;
789c59a5c48SFrançois Tigeot 	else if (div >= 64 && div < 96)
790c59a5c48SFrançois Tigeot 		return (div - 64) * 50 + 1600;
791c59a5c48SFrançois Tigeot 	else if (div >= 96 && div < 128)
792c59a5c48SFrançois Tigeot 		return (div - 96) * 100 + 3200;
793c59a5c48SFrançois Tigeot 	else
794c59a5c48SFrançois Tigeot 		return 0;
795c59a5c48SFrançois Tigeot }
796