14cd92098Szrj /*
24cd92098Szrj * Copyright 2013 Advanced Micro Devices, Inc.
34cd92098Szrj *
44cd92098Szrj * Permission is hereby granted, free of charge, to any person obtaining a
54cd92098Szrj * copy of this software and associated documentation files (the "Software"),
64cd92098Szrj * to deal in the Software without restriction, including without limitation
74cd92098Szrj * the rights to use, copy, modify, merge, publish, distribute, sublicense,
84cd92098Szrj * and/or sell copies of the Software, and to permit persons to whom the
94cd92098Szrj * Software is furnished to do so, subject to the following conditions:
104cd92098Szrj *
114cd92098Szrj * The above copyright notice and this permission notice shall be included in
124cd92098Szrj * all copies or substantial portions of the Software.
134cd92098Szrj *
144cd92098Szrj * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
154cd92098Szrj * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
164cd92098Szrj * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
174cd92098Szrj * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
184cd92098Szrj * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
194cd92098Szrj * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
204cd92098Szrj * OTHER DEALINGS IN THE SOFTWARE.
214cd92098Szrj *
224cd92098Szrj */
234cd92098Szrj #include <linux/hdmi.h>
244cd92098Szrj #include <drm/drmP.h>
254cd92098Szrj #include "radeon.h"
26c59a5c48SFrançois Tigeot #include "radeon_audio.h"
274cd92098Szrj #include "sid.h"
284cd92098Szrj
29c59a5c48SFrançois Tigeot #define DCE8_DCCG_AUDIO_DTO1_PHASE 0x05b8
30c59a5c48SFrançois Tigeot #define DCE8_DCCG_AUDIO_DTO1_MODULE 0x05bc
31c59a5c48SFrançois Tigeot
32c59a5c48SFrançois Tigeot u32 dce6_endpoint_rreg(struct radeon_device *rdev,
33c59a5c48SFrançois Tigeot u32 block_offset, u32 reg);
34c59a5c48SFrançois Tigeot void dce6_endpoint_wreg(struct radeon_device *rdev,
35c59a5c48SFrançois Tigeot u32 block_offset, u32 reg, u32 v);
36c59a5c48SFrançois Tigeot void dce6_afmt_select_pin(struct drm_encoder *encoder);
37c59a5c48SFrançois Tigeot void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
38c59a5c48SFrançois Tigeot struct drm_connector *connector, struct drm_display_mode *mode);
39c59a5c48SFrançois Tigeot void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder);
40c59a5c48SFrançois Tigeot void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
41c59a5c48SFrançois Tigeot struct cea_sad *sads, int sad_count);
42c59a5c48SFrançois Tigeot void dce6_audio_fini(struct radeon_device *rdev);
43c59a5c48SFrançois Tigeot
dce6_endpoint_rreg(struct radeon_device * rdev,u32 block_offset,u32 reg)44c59a5c48SFrançois Tigeot u32 dce6_endpoint_rreg(struct radeon_device *rdev,
454cd92098Szrj u32 block_offset, u32 reg)
464cd92098Szrj {
474cd92098Szrj u32 r;
484cd92098Szrj
49*ec5b6af4SFrançois Tigeot lockmgr(&rdev->end_idx_lock, LK_EXCLUSIVE);
504cd92098Szrj WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset, reg);
514cd92098Szrj r = RREG32(AZ_F0_CODEC_ENDPOINT_DATA + block_offset);
52*ec5b6af4SFrançois Tigeot lockmgr(&rdev->end_idx_lock, LK_RELEASE);
53c6f73aabSFrançois Tigeot
544cd92098Szrj return r;
554cd92098Szrj }
564cd92098Szrj
dce6_endpoint_wreg(struct radeon_device * rdev,u32 block_offset,u32 reg,u32 v)57c59a5c48SFrançois Tigeot void dce6_endpoint_wreg(struct radeon_device *rdev,
584cd92098Szrj u32 block_offset, u32 reg, u32 v)
594cd92098Szrj {
60*ec5b6af4SFrançois Tigeot lockmgr(&rdev->end_idx_lock, LK_EXCLUSIVE);
614cd92098Szrj if (ASIC_IS_DCE8(rdev))
624cd92098Szrj WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset, reg);
634cd92098Szrj else
644cd92098Szrj WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset,
654cd92098Szrj AZ_ENDPOINT_REG_WRITE_EN | AZ_ENDPOINT_REG_INDEX(reg));
664cd92098Szrj WREG32(AZ_F0_CODEC_ENDPOINT_DATA + block_offset, v);
67*ec5b6af4SFrançois Tigeot lockmgr(&rdev->end_idx_lock, LK_RELEASE);
684cd92098Szrj }
694cd92098Szrj
dce6_afmt_get_connected_pins(struct radeon_device * rdev)704cd92098Szrj static void dce6_afmt_get_connected_pins(struct radeon_device *rdev)
714cd92098Szrj {
724cd92098Szrj int i;
734cd92098Szrj u32 offset, tmp;
744cd92098Szrj
754cd92098Szrj for (i = 0; i < rdev->audio.num_pins; i++) {
764cd92098Szrj offset = rdev->audio.pin[i].offset;
774cd92098Szrj tmp = RREG32_ENDPOINT(offset,
784cd92098Szrj AZ_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT);
794cd92098Szrj if (((tmp & PORT_CONNECTIVITY_MASK) >> PORT_CONNECTIVITY_SHIFT) == 1)
804cd92098Szrj rdev->audio.pin[i].connected = false;
814cd92098Szrj else
824cd92098Szrj rdev->audio.pin[i].connected = true;
834cd92098Szrj }
844cd92098Szrj }
854cd92098Szrj
dce6_audio_get_pin(struct radeon_device * rdev)864cd92098Szrj struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev)
874cd92098Szrj {
88c59a5c48SFrançois Tigeot struct drm_encoder *encoder;
89c59a5c48SFrançois Tigeot struct radeon_encoder *radeon_encoder;
90c59a5c48SFrançois Tigeot struct radeon_encoder_atom_dig *dig;
91c59a5c48SFrançois Tigeot struct r600_audio_pin *pin = NULL;
92c59a5c48SFrançois Tigeot int i, pin_count;
934cd92098Szrj
944cd92098Szrj dce6_afmt_get_connected_pins(rdev);
954cd92098Szrj
964cd92098Szrj for (i = 0; i < rdev->audio.num_pins; i++) {
97c59a5c48SFrançois Tigeot if (rdev->audio.pin[i].connected) {
98c59a5c48SFrançois Tigeot pin = &rdev->audio.pin[i];
99c59a5c48SFrançois Tigeot pin_count = 0;
100c59a5c48SFrançois Tigeot
101c59a5c48SFrançois Tigeot list_for_each_entry(encoder, &rdev->ddev->mode_config.encoder_list, head) {
102c59a5c48SFrançois Tigeot if (radeon_encoder_is_digital(encoder)) {
103c59a5c48SFrançois Tigeot radeon_encoder = to_radeon_encoder(encoder);
104c59a5c48SFrançois Tigeot dig = radeon_encoder->enc_priv;
105c59a5c48SFrançois Tigeot if (dig->pin == pin)
106c59a5c48SFrançois Tigeot pin_count++;
1074cd92098Szrj }
108c59a5c48SFrançois Tigeot }
109c59a5c48SFrançois Tigeot
110c59a5c48SFrançois Tigeot if (pin_count == 0)
111c59a5c48SFrançois Tigeot return pin;
112c59a5c48SFrançois Tigeot }
113c59a5c48SFrançois Tigeot }
114c59a5c48SFrançois Tigeot if (!pin)
1154cd92098Szrj DRM_ERROR("No connected audio pins found!\n");
116c59a5c48SFrançois Tigeot return pin;
1174cd92098Szrj }
1184cd92098Szrj
dce6_afmt_select_pin(struct drm_encoder * encoder)1194cd92098Szrj void dce6_afmt_select_pin(struct drm_encoder *encoder)
1204cd92098Szrj {
1214cd92098Szrj struct radeon_device *rdev = encoder->dev->dev_private;
1224cd92098Szrj struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
1234cd92098Szrj struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
1244cd92098Szrj
125c59a5c48SFrançois Tigeot if (!dig || !dig->afmt || !dig->pin)
1264cd92098Szrj return;
1274cd92098Szrj
128c59a5c48SFrançois Tigeot WREG32(AFMT_AUDIO_SRC_CONTROL + dig->afmt->offset,
129c59a5c48SFrançois Tigeot AFMT_AUDIO_SRC_SELECT(dig->pin->id));
1304cd92098Szrj }
1314cd92098Szrj
dce6_afmt_write_latency_fields(struct drm_encoder * encoder,struct drm_connector * connector,struct drm_display_mode * mode)132c6f73aabSFrançois Tigeot void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
133c59a5c48SFrançois Tigeot struct drm_connector *connector,
134c6f73aabSFrançois Tigeot struct drm_display_mode *mode)
135c6f73aabSFrançois Tigeot {
136c6f73aabSFrançois Tigeot struct radeon_device *rdev = encoder->dev->dev_private;
137c6f73aabSFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
138c6f73aabSFrançois Tigeot struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
139c59a5c48SFrançois Tigeot u32 tmp = 0;
140c6f73aabSFrançois Tigeot
141c59a5c48SFrançois Tigeot if (!dig || !dig->afmt || !dig->pin)
142c6f73aabSFrançois Tigeot return;
143c6f73aabSFrançois Tigeot
144c6f73aabSFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
145c6f73aabSFrançois Tigeot if (connector->latency_present[1])
146c6f73aabSFrançois Tigeot tmp = VIDEO_LIPSYNC(connector->video_latency[1]) |
147c6f73aabSFrançois Tigeot AUDIO_LIPSYNC(connector->audio_latency[1]);
148c6f73aabSFrançois Tigeot else
149c6f73aabSFrançois Tigeot tmp = VIDEO_LIPSYNC(0) | AUDIO_LIPSYNC(0);
150c6f73aabSFrançois Tigeot } else {
151c6f73aabSFrançois Tigeot if (connector->latency_present[0])
152c6f73aabSFrançois Tigeot tmp = VIDEO_LIPSYNC(connector->video_latency[0]) |
153c6f73aabSFrançois Tigeot AUDIO_LIPSYNC(connector->audio_latency[0]);
154c6f73aabSFrançois Tigeot else
155c6f73aabSFrançois Tigeot tmp = VIDEO_LIPSYNC(0) | AUDIO_LIPSYNC(0);
156c6f73aabSFrançois Tigeot }
157c59a5c48SFrançois Tigeot WREG32_ENDPOINT(dig->pin->offset,
158c59a5c48SFrançois Tigeot AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
159c6f73aabSFrançois Tigeot }
160c6f73aabSFrançois Tigeot
161c59a5c48SFrançois Tigeot void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
162c59a5c48SFrançois Tigeot u8 *sadb, int sad_count);
dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder * encoder,u8 * sadb,int sad_count)163c59a5c48SFrançois Tigeot void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
164c59a5c48SFrançois Tigeot u8 *sadb, int sad_count)
1654cd92098Szrj {
1664cd92098Szrj struct radeon_device *rdev = encoder->dev->dev_private;
1674cd92098Szrj struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
1684cd92098Szrj struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
169c59a5c48SFrançois Tigeot u32 tmp;
1704cd92098Szrj
171c59a5c48SFrançois Tigeot if (!dig || !dig->afmt || !dig->pin)
1724cd92098Szrj return;
1734cd92098Szrj
1744cd92098Szrj /* program the speaker allocation */
175c59a5c48SFrançois Tigeot tmp = RREG32_ENDPOINT(dig->pin->offset,
176c59a5c48SFrançois Tigeot AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
1774cd92098Szrj tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
1784cd92098Szrj /* set HDMI mode */
1794cd92098Szrj tmp |= HDMI_CONNECTION;
1804cd92098Szrj if (sad_count)
1814cd92098Szrj tmp |= SPEAKER_ALLOCATION(sadb[0]);
1824cd92098Szrj else
1834cd92098Szrj tmp |= SPEAKER_ALLOCATION(5); /* stereo */
184c59a5c48SFrançois Tigeot WREG32_ENDPOINT(dig->pin->offset,
185c59a5c48SFrançois Tigeot AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
1864cd92098Szrj }
1874cd92098Szrj
188c59a5c48SFrançois Tigeot void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
189c59a5c48SFrançois Tigeot u8 *sadb, int sad_count);
dce6_afmt_dp_write_speaker_allocation(struct drm_encoder * encoder,u8 * sadb,int sad_count)190c59a5c48SFrançois Tigeot void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
191c59a5c48SFrançois Tigeot u8 *sadb, int sad_count)
1924cd92098Szrj {
1934cd92098Szrj struct radeon_device *rdev = encoder->dev->dev_private;
1944cd92098Szrj struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
1954cd92098Szrj struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
196c59a5c48SFrançois Tigeot u32 tmp;
1974cd92098Szrj
198c59a5c48SFrançois Tigeot if (!dig || !dig->afmt || !dig->pin)
199c59a5c48SFrançois Tigeot return;
200c59a5c48SFrançois Tigeot
201c59a5c48SFrançois Tigeot /* program the speaker allocation */
202c59a5c48SFrançois Tigeot tmp = RREG32_ENDPOINT(dig->pin->offset,
203c59a5c48SFrançois Tigeot AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
204c59a5c48SFrançois Tigeot tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK);
205c59a5c48SFrançois Tigeot /* set DP mode */
206c59a5c48SFrançois Tigeot tmp |= DP_CONNECTION;
207c59a5c48SFrançois Tigeot if (sad_count)
208c59a5c48SFrançois Tigeot tmp |= SPEAKER_ALLOCATION(sadb[0]);
209c59a5c48SFrançois Tigeot else
210c59a5c48SFrançois Tigeot tmp |= SPEAKER_ALLOCATION(5); /* stereo */
211c59a5c48SFrançois Tigeot WREG32_ENDPOINT(dig->pin->offset,
212c59a5c48SFrançois Tigeot AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
213c59a5c48SFrançois Tigeot }
214c59a5c48SFrançois Tigeot
dce6_afmt_write_sad_regs(struct drm_encoder * encoder,struct cea_sad * sads,int sad_count)215c59a5c48SFrançois Tigeot void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
216c59a5c48SFrançois Tigeot struct cea_sad *sads, int sad_count)
217c59a5c48SFrançois Tigeot {
218c59a5c48SFrançois Tigeot int i;
219c59a5c48SFrançois Tigeot struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
220c59a5c48SFrançois Tigeot struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
221c59a5c48SFrançois Tigeot struct radeon_device *rdev = encoder->dev->dev_private;
2224cd92098Szrj static const u16 eld_reg_to_type[][2] = {
2234cd92098Szrj { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
2244cd92098Szrj { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
2254cd92098Szrj { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR2, HDMI_AUDIO_CODING_TYPE_MPEG1 },
2264cd92098Szrj { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR3, HDMI_AUDIO_CODING_TYPE_MP3 },
2274cd92098Szrj { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR4, HDMI_AUDIO_CODING_TYPE_MPEG2 },
2284cd92098Szrj { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR5, HDMI_AUDIO_CODING_TYPE_AAC_LC },
2294cd92098Szrj { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR6, HDMI_AUDIO_CODING_TYPE_DTS },
2304cd92098Szrj { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR7, HDMI_AUDIO_CODING_TYPE_ATRAC },
2314cd92098Szrj { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR9, HDMI_AUDIO_CODING_TYPE_EAC3 },
2324cd92098Szrj { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR10, HDMI_AUDIO_CODING_TYPE_DTS_HD },
2334cd92098Szrj { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR11, HDMI_AUDIO_CODING_TYPE_MLP },
2344cd92098Szrj { AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
2354cd92098Szrj };
2364cd92098Szrj
237c59a5c48SFrançois Tigeot if (!dig || !dig->afmt || !dig->pin)
2384cd92098Szrj return;
2394cd92098Szrj
2404cd92098Szrj for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
2414cd92098Szrj u32 value = 0;
242c6f73aabSFrançois Tigeot u8 stereo_freqs = 0;
243c6f73aabSFrançois Tigeot int max_channels = -1;
2444cd92098Szrj int j;
2454cd92098Szrj
2464cd92098Szrj for (j = 0; j < sad_count; j++) {
2474cd92098Szrj struct cea_sad *sad = &sads[j];
2484cd92098Szrj
2494cd92098Szrj if (sad->format == eld_reg_to_type[i][1]) {
250c6f73aabSFrançois Tigeot if (sad->channels > max_channels) {
2514cd92098Szrj value = MAX_CHANNELS(sad->channels) |
2524cd92098Szrj DESCRIPTOR_BYTE_2(sad->byte2) |
2534cd92098Szrj SUPPORTED_FREQUENCIES(sad->freq);
254c6f73aabSFrançois Tigeot max_channels = sad->channels;
255c6f73aabSFrançois Tigeot }
256c6f73aabSFrançois Tigeot
2574cd92098Szrj if (sad->format == HDMI_AUDIO_CODING_TYPE_PCM)
258c6f73aabSFrançois Tigeot stereo_freqs |= sad->freq;
259c6f73aabSFrançois Tigeot else
2604cd92098Szrj break;
2614cd92098Szrj }
2624cd92098Szrj }
263c6f73aabSFrançois Tigeot
264c6f73aabSFrançois Tigeot value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
265c6f73aabSFrançois Tigeot
266c59a5c48SFrançois Tigeot WREG32_ENDPOINT(dig->pin->offset, eld_reg_to_type[i][0], value);
2674cd92098Szrj }
2684cd92098Szrj }
2694cd92098Szrj
dce6_audio_enable(struct radeon_device * rdev,struct r600_audio_pin * pin,u8 enable_mask)270c6f73aabSFrançois Tigeot void dce6_audio_enable(struct radeon_device *rdev,
2714cd92098Szrj struct r600_audio_pin *pin,
272591d5043SFrançois Tigeot u8 enable_mask)
2734cd92098Szrj {
274c6f73aabSFrançois Tigeot if (!pin)
275c6f73aabSFrançois Tigeot return;
276c6f73aabSFrançois Tigeot
277591d5043SFrançois Tigeot WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
278591d5043SFrançois Tigeot enable_mask ? AUDIO_ENABLED : 0);
2794cd92098Szrj }
2804cd92098Szrj
281c59a5c48SFrançois Tigeot void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
282c59a5c48SFrançois Tigeot struct radeon_crtc *crtc, unsigned int clock);
dce6_hdmi_audio_set_dto(struct radeon_device * rdev,struct radeon_crtc * crtc,unsigned int clock)283c59a5c48SFrançois Tigeot void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
284c59a5c48SFrançois Tigeot struct radeon_crtc *crtc, unsigned int clock)
2854cd92098Szrj {
286c59a5c48SFrançois Tigeot /* Two dtos; generally use dto0 for HDMI */
287c59a5c48SFrançois Tigeot u32 value = 0;
2884cd92098Szrj
289c59a5c48SFrançois Tigeot if (crtc)
290c59a5c48SFrançois Tigeot value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
2914cd92098Szrj
292c59a5c48SFrançois Tigeot WREG32(DCCG_AUDIO_DTO_SOURCE, value);
2934cd92098Szrj
294c59a5c48SFrançois Tigeot /* Express [24MHz / target pixel clock] as an exact rational
295c59a5c48SFrançois Tigeot * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
296c59a5c48SFrançois Tigeot * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
297c59a5c48SFrançois Tigeot */
298c59a5c48SFrançois Tigeot WREG32(DCCG_AUDIO_DTO0_PHASE, 24000);
299c59a5c48SFrançois Tigeot WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
3004cd92098Szrj }
3014cd92098Szrj
302c59a5c48SFrançois Tigeot void dce6_dp_audio_set_dto(struct radeon_device *rdev,
303c59a5c48SFrançois Tigeot struct radeon_crtc *crtc, unsigned int clock);
dce6_dp_audio_set_dto(struct radeon_device * rdev,struct radeon_crtc * crtc,unsigned int clock)304c59a5c48SFrançois Tigeot void dce6_dp_audio_set_dto(struct radeon_device *rdev,
305c59a5c48SFrançois Tigeot struct radeon_crtc *crtc, unsigned int clock)
306ee479021SImre Vadász {
307c59a5c48SFrançois Tigeot /* Two dtos; generally use dto1 for DP */
308c59a5c48SFrançois Tigeot u32 value = 0;
309c59a5c48SFrançois Tigeot value |= DCCG_AUDIO_DTO_SEL;
310ee479021SImre Vadász
311c59a5c48SFrançois Tigeot if (crtc)
312c59a5c48SFrançois Tigeot value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
313ee479021SImre Vadász
314c59a5c48SFrançois Tigeot WREG32(DCCG_AUDIO_DTO_SOURCE, value);
315ee479021SImre Vadász
316c59a5c48SFrançois Tigeot /* Express [24MHz / target pixel clock] as an exact rational
317c59a5c48SFrançois Tigeot * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
318c59a5c48SFrançois Tigeot * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
319c59a5c48SFrançois Tigeot */
320c59a5c48SFrançois Tigeot if (ASIC_IS_DCE8(rdev)) {
321c59a5c48SFrançois Tigeot unsigned int div = (RREG32(DENTIST_DISPCLK_CNTL) &
322c59a5c48SFrançois Tigeot DENTIST_DPREFCLK_WDIVIDER_MASK) >>
323c59a5c48SFrançois Tigeot DENTIST_DPREFCLK_WDIVIDER_SHIFT;
324c59a5c48SFrançois Tigeot div = radeon_audio_decode_dfs_div(div);
325c59a5c48SFrançois Tigeot
326c59a5c48SFrançois Tigeot if (div)
327c59a5c48SFrançois Tigeot clock = clock * 100 / div;
328c59a5c48SFrançois Tigeot
329c59a5c48SFrançois Tigeot WREG32(DCE8_DCCG_AUDIO_DTO1_PHASE, 24000);
330c59a5c48SFrançois Tigeot WREG32(DCE8_DCCG_AUDIO_DTO1_MODULE, clock);
331c59a5c48SFrançois Tigeot } else {
332c59a5c48SFrançois Tigeot WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
333c59a5c48SFrançois Tigeot WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
334c59a5c48SFrançois Tigeot }
3354cd92098Szrj }
336