1254885Sdumbbell/*
2254885Sdumbbell * Copyright 2008 Advanced Micro Devices, Inc.
3254885Sdumbbell * Copyright 2008 Red Hat Inc.
4254885Sdumbbell * Copyright 2009 Christian K��nig.
5254885Sdumbbell *
6254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a
7254885Sdumbbell * copy of this software and associated documentation files (the "Software"),
8254885Sdumbbell * to deal in the Software without restriction, including without limitation
9254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the
11254885Sdumbbell * Software is furnished to do so, subject to the following conditions:
12254885Sdumbbell *
13254885Sdumbbell * The above copyright notice and this permission notice shall be included in
14254885Sdumbbell * all copies or substantial portions of the Software.
15254885Sdumbbell *
16254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19254885Sdumbbell * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22254885Sdumbbell * OTHER DEALINGS IN THE SOFTWARE.
23254885Sdumbbell *
24254885Sdumbbell * Authors: Christian K��nig
25254885Sdumbbell */
26254885Sdumbbell
27254885Sdumbbell#include <sys/cdefs.h>
28254885Sdumbbell__FBSDID("$FreeBSD: releng/11.0/sys/dev/drm2/radeon/r600_audio.c 254885 2013-08-25 19:37:15Z dumbbell $");
29254885Sdumbbell
30254885Sdumbbell#include <dev/drm2/drmP.h>
31254885Sdumbbell#include "radeon.h"
32254885Sdumbbell#include "radeon_reg.h"
33254885Sdumbbell#include "radeon_asic.h"
34254885Sdumbbell#include "atom.h"
35254885Sdumbbell
36254885Sdumbbell/*
37254885Sdumbbell * check if enc_priv stores radeon_encoder_atom_dig
38254885Sdumbbell */
39254885Sdumbbellstatic bool radeon_dig_encoder(struct drm_encoder *encoder)
40254885Sdumbbell{
41254885Sdumbbell	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
42254885Sdumbbell	switch (radeon_encoder->encoder_id) {
43254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_LVDS:
44254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
45254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
46254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
47254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_DVO1:
48254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
49254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_DDI:
50254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
51254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
52254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
53254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
54254885Sdumbbell		return true;
55254885Sdumbbell	}
56254885Sdumbbell	return false;
57254885Sdumbbell}
58254885Sdumbbell
59254885Sdumbbell/*
60254885Sdumbbell * check if the chipset is supported
61254885Sdumbbell */
62254885Sdumbbellstatic int r600_audio_chipset_supported(struct radeon_device *rdev)
63254885Sdumbbell{
64254885Sdumbbell	return (rdev->family >= CHIP_R600 && !ASIC_IS_DCE6(rdev))
65254885Sdumbbell		|| rdev->family == CHIP_RS600
66254885Sdumbbell		|| rdev->family == CHIP_RS690
67254885Sdumbbell		|| rdev->family == CHIP_RS740;
68254885Sdumbbell}
69254885Sdumbbell
70254885Sdumbbellstruct r600_audio r600_audio_status(struct radeon_device *rdev)
71254885Sdumbbell{
72254885Sdumbbell	struct r600_audio status;
73254885Sdumbbell	uint32_t value;
74254885Sdumbbell
75254885Sdumbbell	value = RREG32(R600_AUDIO_RATE_BPS_CHANNEL);
76254885Sdumbbell
77254885Sdumbbell	/* number of channels */
78254885Sdumbbell	status.channels = (value & 0x7) + 1;
79254885Sdumbbell
80254885Sdumbbell	/* bits per sample */
81254885Sdumbbell	switch ((value & 0xF0) >> 4) {
82254885Sdumbbell	case 0x0:
83254885Sdumbbell		status.bits_per_sample = 8;
84254885Sdumbbell		break;
85254885Sdumbbell	case 0x1:
86254885Sdumbbell		status.bits_per_sample = 16;
87254885Sdumbbell		break;
88254885Sdumbbell	case 0x2:
89254885Sdumbbell		status.bits_per_sample = 20;
90254885Sdumbbell		break;
91254885Sdumbbell	case 0x3:
92254885Sdumbbell		status.bits_per_sample = 24;
93254885Sdumbbell		break;
94254885Sdumbbell	case 0x4:
95254885Sdumbbell		status.bits_per_sample = 32;
96254885Sdumbbell		break;
97254885Sdumbbell	default:
98254885Sdumbbell		dev_err(rdev->dev, "Unknown bits per sample 0x%x, using 16\n",
99254885Sdumbbell			(int)value);
100254885Sdumbbell		status.bits_per_sample = 16;
101254885Sdumbbell	}
102254885Sdumbbell
103254885Sdumbbell	/* current sampling rate in HZ */
104254885Sdumbbell	if (value & 0x4000)
105254885Sdumbbell		status.rate = 44100;
106254885Sdumbbell	else
107254885Sdumbbell		status.rate = 48000;
108254885Sdumbbell	status.rate *= ((value >> 11) & 0x7) + 1;
109254885Sdumbbell	status.rate /= ((value >> 8) & 0x7) + 1;
110254885Sdumbbell
111254885Sdumbbell	value = RREG32(R600_AUDIO_STATUS_BITS);
112254885Sdumbbell
113254885Sdumbbell	/* iec 60958 status bits */
114254885Sdumbbell	status.status_bits = value & 0xff;
115254885Sdumbbell
116254885Sdumbbell	/* iec 60958 category code */
117254885Sdumbbell	status.category_code = (value >> 8) & 0xff;
118254885Sdumbbell
119254885Sdumbbell	return status;
120254885Sdumbbell}
121254885Sdumbbell
122254885Sdumbbell/*
123254885Sdumbbell * update all hdmi interfaces with current audio parameters
124254885Sdumbbell */
125254885Sdumbbellvoid r600_audio_update_hdmi(void *arg, int pending)
126254885Sdumbbell{
127254885Sdumbbell	struct radeon_device *rdev = arg;
128254885Sdumbbell	struct drm_device *dev = rdev->ddev;
129254885Sdumbbell	struct r600_audio audio_status = r600_audio_status(rdev);
130254885Sdumbbell	struct drm_encoder *encoder;
131254885Sdumbbell	bool changed = false;
132254885Sdumbbell
133254885Sdumbbell	if (rdev->audio_status.channels != audio_status.channels ||
134254885Sdumbbell	    rdev->audio_status.rate != audio_status.rate ||
135254885Sdumbbell	    rdev->audio_status.bits_per_sample != audio_status.bits_per_sample ||
136254885Sdumbbell	    rdev->audio_status.status_bits != audio_status.status_bits ||
137254885Sdumbbell	    rdev->audio_status.category_code != audio_status.category_code) {
138254885Sdumbbell		rdev->audio_status = audio_status;
139254885Sdumbbell		changed = true;
140254885Sdumbbell	}
141254885Sdumbbell
142254885Sdumbbell	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
143254885Sdumbbell		if (!radeon_dig_encoder(encoder))
144254885Sdumbbell			continue;
145254885Sdumbbell		if (changed || r600_hdmi_buffer_status_changed(encoder))
146254885Sdumbbell			r600_hdmi_update_audio_settings(encoder);
147254885Sdumbbell	}
148254885Sdumbbell}
149254885Sdumbbell
150254885Sdumbbell/*
151254885Sdumbbell * turn on/off audio engine
152254885Sdumbbell */
153254885Sdumbbellstatic void r600_audio_engine_enable(struct radeon_device *rdev, bool enable)
154254885Sdumbbell{
155254885Sdumbbell	u32 value = 0;
156254885Sdumbbell	DRM_INFO("%s audio support\n", enable ? "Enabling" : "Disabling");
157254885Sdumbbell	if (ASIC_IS_DCE4(rdev)) {
158254885Sdumbbell		if (enable) {
159254885Sdumbbell			value |= 0x81000000; /* Required to enable audio */
160254885Sdumbbell			value |= 0x0e1000f0; /* fglrx sets that too */
161254885Sdumbbell		}
162254885Sdumbbell		WREG32(EVERGREEN_AUDIO_ENABLE, value);
163254885Sdumbbell	} else {
164254885Sdumbbell		WREG32_P(R600_AUDIO_ENABLE,
165254885Sdumbbell			 enable ? 0x81000000 : 0x0, ~0x81000000);
166254885Sdumbbell	}
167254885Sdumbbell	rdev->audio_enabled = enable;
168254885Sdumbbell}
169254885Sdumbbell
170254885Sdumbbell/*
171254885Sdumbbell * initialize the audio vars
172254885Sdumbbell */
173254885Sdumbbellint r600_audio_init(struct radeon_device *rdev)
174254885Sdumbbell{
175254885Sdumbbell	if (!radeon_audio || !r600_audio_chipset_supported(rdev))
176254885Sdumbbell		return 0;
177254885Sdumbbell
178254885Sdumbbell	r600_audio_engine_enable(rdev, true);
179254885Sdumbbell
180254885Sdumbbell	rdev->audio_status.channels = -1;
181254885Sdumbbell	rdev->audio_status.rate = -1;
182254885Sdumbbell	rdev->audio_status.bits_per_sample = -1;
183254885Sdumbbell	rdev->audio_status.status_bits = 0;
184254885Sdumbbell	rdev->audio_status.category_code = 0;
185254885Sdumbbell
186254885Sdumbbell	return 0;
187254885Sdumbbell}
188254885Sdumbbell
189254885Sdumbbell/*
190254885Sdumbbell * atach the audio codec to the clock source of the encoder
191254885Sdumbbell */
192254885Sdumbbellvoid r600_audio_set_clock(struct drm_encoder *encoder, int clock)
193254885Sdumbbell{
194254885Sdumbbell	struct drm_device *dev = encoder->dev;
195254885Sdumbbell	struct radeon_device *rdev = dev->dev_private;
196254885Sdumbbell	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
197254885Sdumbbell	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
198254885Sdumbbell	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
199254885Sdumbbell	int base_rate = 48000;
200254885Sdumbbell
201254885Sdumbbell	switch (radeon_encoder->encoder_id) {
202254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
203254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
204254885Sdumbbell		WREG32_P(R600_AUDIO_TIMING, 0, ~0x301);
205254885Sdumbbell		break;
206254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
207254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
208254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
209254885Sdumbbell	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
210254885Sdumbbell		WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301);
211254885Sdumbbell		break;
212254885Sdumbbell	default:
213254885Sdumbbell		dev_err(rdev->dev, "Unsupported encoder type 0x%02X\n",
214254885Sdumbbell			  radeon_encoder->encoder_id);
215254885Sdumbbell		return;
216254885Sdumbbell	}
217254885Sdumbbell
218254885Sdumbbell	if (ASIC_IS_DCE4(rdev)) {
219254885Sdumbbell		/* TODO: other PLLs? */
220254885Sdumbbell		WREG32(EVERGREEN_AUDIO_PLL1_MUL, base_rate * 10);
221254885Sdumbbell		WREG32(EVERGREEN_AUDIO_PLL1_DIV, clock * 10);
222254885Sdumbbell		WREG32(EVERGREEN_AUDIO_PLL1_UNK, 0x00000071);
223254885Sdumbbell
224254885Sdumbbell		/* Select DTO source */
225254885Sdumbbell		WREG32(0x5ac, radeon_crtc->crtc_id);
226254885Sdumbbell	} else {
227254885Sdumbbell		switch (dig->dig_encoder) {
228254885Sdumbbell		case 0:
229254885Sdumbbell			WREG32(R600_AUDIO_PLL1_MUL, base_rate * 50);
230254885Sdumbbell			WREG32(R600_AUDIO_PLL1_DIV, clock * 100);
231254885Sdumbbell			WREG32(R600_AUDIO_CLK_SRCSEL, 0);
232254885Sdumbbell			break;
233254885Sdumbbell
234254885Sdumbbell		case 1:
235254885Sdumbbell			WREG32(R600_AUDIO_PLL2_MUL, base_rate * 50);
236254885Sdumbbell			WREG32(R600_AUDIO_PLL2_DIV, clock * 100);
237254885Sdumbbell			WREG32(R600_AUDIO_CLK_SRCSEL, 1);
238254885Sdumbbell			break;
239254885Sdumbbell		default:
240254885Sdumbbell			dev_err(rdev->dev,
241254885Sdumbbell				"Unsupported DIG on encoder 0x%02X\n",
242254885Sdumbbell				radeon_encoder->encoder_id);
243254885Sdumbbell			return;
244254885Sdumbbell		}
245254885Sdumbbell	}
246254885Sdumbbell}
247254885Sdumbbell
248254885Sdumbbell/*
249254885Sdumbbell * release the audio timer
250254885Sdumbbell * TODO: How to do this correctly on SMP systems?
251254885Sdumbbell */
252254885Sdumbbellvoid r600_audio_fini(struct radeon_device *rdev)
253254885Sdumbbell{
254254885Sdumbbell	if (!rdev->audio_enabled)
255254885Sdumbbell		return;
256254885Sdumbbell
257254885Sdumbbell	r600_audio_engine_enable(rdev, false);
258254885Sdumbbell}
259