2 * Copyright 2013 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
23 #include <linux/hdmi.h>
28 static u32
dce6_endpoint_rreg(struct radeon_device
*rdev
,
29 u32 block_offset
, u32 reg
)
34 spin_lock_irqsave(&rdev
->end_idx_lock
, flags
);
35 WREG32(AZ_F0_CODEC_ENDPOINT_INDEX
+ block_offset
, reg
);
36 r
= RREG32(AZ_F0_CODEC_ENDPOINT_DATA
+ block_offset
);
37 spin_unlock_irqrestore(&rdev
->end_idx_lock
, flags
);
42 static void dce6_endpoint_wreg(struct radeon_device
*rdev
,
43 u32 block_offset
, u32 reg
, u32 v
)
47 spin_lock_irqsave(&rdev
->end_idx_lock
, flags
);
48 if (ASIC_IS_DCE8(rdev
))
49 WREG32(AZ_F0_CODEC_ENDPOINT_INDEX
+ block_offset
, reg
);
51 WREG32(AZ_F0_CODEC_ENDPOINT_INDEX
+ block_offset
,
52 AZ_ENDPOINT_REG_WRITE_EN
| AZ_ENDPOINT_REG_INDEX(reg
));
53 WREG32(AZ_F0_CODEC_ENDPOINT_DATA
+ block_offset
, v
);
54 spin_unlock_irqrestore(&rdev
->end_idx_lock
, flags
);
57 #define RREG32_ENDPOINT(block, reg) dce6_endpoint_rreg(rdev, (block), (reg))
58 #define WREG32_ENDPOINT(block, reg, v) dce6_endpoint_wreg(rdev, (block), (reg), (v))
61 static void dce6_afmt_get_connected_pins(struct radeon_device
*rdev
)
66 for (i
= 0; i
< rdev
->audio
.num_pins
; i
++) {
67 offset
= rdev
->audio
.pin
[i
].offset
;
68 tmp
= RREG32_ENDPOINT(offset
,
69 AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT
);
70 if (((tmp
& PORT_CONNECTIVITY_MASK
) >> PORT_CONNECTIVITY_SHIFT
) == 1)
71 rdev
->audio
.pin
[i
].connected
= false;
73 rdev
->audio
.pin
[i
].connected
= true;
77 struct r600_audio_pin
*dce6_audio_get_pin(struct radeon_device
*rdev
)
81 dce6_afmt_get_connected_pins(rdev
);
83 for (i
= 0; i
< rdev
->audio
.num_pins
; i
++) {
84 if (rdev
->audio
.pin
[i
].connected
)
85 return &rdev
->audio
.pin
[i
];
87 DRM_ERROR("No connected audio pins found!\n");
91 void dce6_afmt_select_pin(struct drm_encoder
*encoder
)
93 struct radeon_device
*rdev
= encoder
->dev
->dev_private
;
94 struct radeon_encoder
*radeon_encoder
= to_radeon_encoder(encoder
);
95 struct radeon_encoder_atom_dig
*dig
= radeon_encoder
->enc_priv
;
96 u32 offset
= dig
->afmt
->offset
;
101 WREG32(AFMT_AUDIO_SRC_CONTROL
+ offset
,
102 AFMT_AUDIO_SRC_SELECT(dig
->afmt
->pin
->id
));
105 void dce6_afmt_write_speaker_allocation(struct drm_encoder
*encoder
)
107 struct radeon_device
*rdev
= encoder
->dev
->dev_private
;
108 struct radeon_encoder
*radeon_encoder
= to_radeon_encoder(encoder
);
109 struct radeon_encoder_atom_dig
*dig
= radeon_encoder
->enc_priv
;
110 struct drm_connector
*connector
;
111 struct radeon_connector
*radeon_connector
= NULL
;
116 /* XXX: setting this register causes hangs on some asics */
122 offset
= dig
->afmt
->pin
->offset
;
124 list_for_each_entry(connector
, &encoder
->dev
->mode_config
.connector_list
, head
) {
125 if (connector
->encoder
== encoder
)
126 radeon_connector
= to_radeon_connector(connector
);
129 if (!radeon_connector
) {
130 DRM_ERROR("Couldn't find encoder's connector\n");
134 sad_count
= drm_edid_to_speaker_allocation(radeon_connector
->edid
, &sadb
);
135 if (sad_count
<= 0) {
136 DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count
);
140 /* program the speaker allocation */
141 tmp
= RREG32_ENDPOINT(offset
, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER
);
142 tmp
&= ~(DP_CONNECTION
| SPEAKER_ALLOCATION_MASK
);
144 tmp
|= HDMI_CONNECTION
;
146 tmp
|= SPEAKER_ALLOCATION(sadb
[0]);
148 tmp
|= SPEAKER_ALLOCATION(5); /* stereo */
149 WREG32_ENDPOINT(offset
, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER
, tmp
);
154 void dce6_afmt_write_sad_regs(struct drm_encoder
*encoder
)
156 struct radeon_device
*rdev
= encoder
->dev
->dev_private
;
157 struct radeon_encoder
*radeon_encoder
= to_radeon_encoder(encoder
);
158 struct radeon_encoder_atom_dig
*dig
= radeon_encoder
->enc_priv
;
160 struct drm_connector
*connector
;
161 struct radeon_connector
*radeon_connector
= NULL
;
162 struct cea_sad
*sads
;
165 static const u16 eld_reg_to_type
[][2] = {
166 { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0
, HDMI_AUDIO_CODING_TYPE_PCM
},
167 { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1
, HDMI_AUDIO_CODING_TYPE_AC3
},
168 { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR2
, HDMI_AUDIO_CODING_TYPE_MPEG1
},
169 { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR3
, HDMI_AUDIO_CODING_TYPE_MP3
},
170 { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR4
, HDMI_AUDIO_CODING_TYPE_MPEG2
},
171 { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR5
, HDMI_AUDIO_CODING_TYPE_AAC_LC
},
172 { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR6
, HDMI_AUDIO_CODING_TYPE_DTS
},
173 { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR7
, HDMI_AUDIO_CODING_TYPE_ATRAC
},
174 { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR9
, HDMI_AUDIO_CODING_TYPE_EAC3
},
175 { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR10
, HDMI_AUDIO_CODING_TYPE_DTS_HD
},
176 { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR11
, HDMI_AUDIO_CODING_TYPE_MLP
},
177 { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13
, HDMI_AUDIO_CODING_TYPE_WMA_PRO
},
183 offset
= dig
->afmt
->pin
->offset
;
185 list_for_each_entry(connector
, &encoder
->dev
->mode_config
.connector_list
, head
) {
186 if (connector
->encoder
== encoder
)
187 radeon_connector
= to_radeon_connector(connector
);
190 if (!radeon_connector
) {
191 DRM_ERROR("Couldn't find encoder's connector\n");
195 sad_count
= drm_edid_to_sad(radeon_connector
->edid
, &sads
);
196 if (sad_count
<= 0) {
197 DRM_ERROR("Couldn't read SADs: %d\n", sad_count
);
202 for (i
= 0; i
< ARRAY_SIZE(eld_reg_to_type
); i
++) {
206 for (j
= 0; j
< sad_count
; j
++) {
207 struct cea_sad
*sad
= &sads
[j
];
209 if (sad
->format
== eld_reg_to_type
[i
][1]) {
210 value
= MAX_CHANNELS(sad
->channels
) |
211 DESCRIPTOR_BYTE_2(sad
->byte2
) |
212 SUPPORTED_FREQUENCIES(sad
->freq
);
213 if (sad
->format
== HDMI_AUDIO_CODING_TYPE_PCM
)
214 value
|= SUPPORTED_FREQUENCIES_STEREO(sad
->freq
);
218 WREG32_ENDPOINT(offset
, eld_reg_to_type
[i
][0], value
);
224 static int dce6_audio_chipset_supported(struct radeon_device
*rdev
)
226 return !ASIC_IS_NODCE(rdev
);
229 void dce6_audio_enable(struct radeon_device
*rdev
,
230 struct r600_audio_pin
*pin
,
236 WREG32_ENDPOINT(pin
->offset
, AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL
,
237 enable
? AUDIO_ENABLED
: 0);
240 static const u32 pin_offsets
[7] =
251 int dce6_audio_init(struct radeon_device
*rdev
)
255 if (!radeon_audio
|| !dce6_audio_chipset_supported(rdev
))
258 rdev
->audio
.enabled
= true;
260 if (ASIC_IS_DCE8(rdev
))
261 rdev
->audio
.num_pins
= 7;
263 rdev
->audio
.num_pins
= 6;
265 for (i
= 0; i
< rdev
->audio
.num_pins
; i
++) {
266 rdev
->audio
.pin
[i
].channels
= -1;
267 rdev
->audio
.pin
[i
].rate
= -1;
268 rdev
->audio
.pin
[i
].bits_per_sample
= -1;
269 rdev
->audio
.pin
[i
].status_bits
= 0;
270 rdev
->audio
.pin
[i
].category_code
= 0;
271 rdev
->audio
.pin
[i
].connected
= false;
272 rdev
->audio
.pin
[i
].offset
= pin_offsets
[i
];
273 rdev
->audio
.pin
[i
].id
= i
;
274 /* disable audio. it will be set up later */
275 dce6_audio_enable(rdev
, &rdev
->audio
.pin
[i
], false);
281 void dce6_audio_fini(struct radeon_device
*rdev
)
285 if (!rdev
->audio
.enabled
)
288 for (i
= 0; i
< rdev
->audio
.num_pins
; i
++)
289 dce6_audio_enable(rdev
, &rdev
->audio
.pin
[i
], false);
291 rdev
->audio
.enabled
= false;