162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2014 Advanced Micro Devices, Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
1262306a36Sopenharmony_ci * all copies or substantial portions of the Software.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1762306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1862306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1962306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2062306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * Authors: Slava Grigorev <slava.grigorev@amd.com>
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <linux/gcd.h>
2662306a36Sopenharmony_ci#include <linux/component.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include <drm/drm_crtc.h>
2962306a36Sopenharmony_ci#include "dce6_afmt.h"
3062306a36Sopenharmony_ci#include "evergreen_hdmi.h"
3162306a36Sopenharmony_ci#include "radeon.h"
3262306a36Sopenharmony_ci#include "atom.h"
3362306a36Sopenharmony_ci#include "r600.h"
3462306a36Sopenharmony_ci#include "radeon_audio.h"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_civoid dce6_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
3762306a36Sopenharmony_ci		u8 enable_mask);
3862306a36Sopenharmony_cistruct r600_audio_pin* r600_audio_get_pin(struct radeon_device *rdev);
3962306a36Sopenharmony_cistruct r600_audio_pin* dce6_audio_get_pin(struct radeon_device *rdev);
4062306a36Sopenharmony_cistatic void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
4162306a36Sopenharmony_ci	struct drm_display_mode *mode);
4262306a36Sopenharmony_cistatic void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
4362306a36Sopenharmony_ci	struct drm_display_mode *mode);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic const u32 pin_offsets[7] =
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	(0x5e00 - 0x5e00),
4862306a36Sopenharmony_ci	(0x5e18 - 0x5e00),
4962306a36Sopenharmony_ci	(0x5e30 - 0x5e00),
5062306a36Sopenharmony_ci	(0x5e48 - 0x5e00),
5162306a36Sopenharmony_ci	(0x5e60 - 0x5e00),
5262306a36Sopenharmony_ci	(0x5e78 - 0x5e00),
5362306a36Sopenharmony_ci	(0x5e90 - 0x5e00),
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic u32 radeon_audio_rreg(struct radeon_device *rdev, u32 offset, u32 reg)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	return RREG32(reg);
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic void radeon_audio_wreg(struct radeon_device *rdev, u32 offset,
6262306a36Sopenharmony_ci		u32 reg, u32 v)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	WREG32(reg, v);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic struct radeon_audio_basic_funcs r600_funcs = {
6862306a36Sopenharmony_ci	.endpoint_rreg = radeon_audio_rreg,
6962306a36Sopenharmony_ci	.endpoint_wreg = radeon_audio_wreg,
7062306a36Sopenharmony_ci	.enable = r600_audio_enable,
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic struct radeon_audio_basic_funcs dce32_funcs = {
7462306a36Sopenharmony_ci	.endpoint_rreg = radeon_audio_rreg,
7562306a36Sopenharmony_ci	.endpoint_wreg = radeon_audio_wreg,
7662306a36Sopenharmony_ci	.enable = r600_audio_enable,
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic struct radeon_audio_basic_funcs dce4_funcs = {
8062306a36Sopenharmony_ci	.endpoint_rreg = radeon_audio_rreg,
8162306a36Sopenharmony_ci	.endpoint_wreg = radeon_audio_wreg,
8262306a36Sopenharmony_ci	.enable = dce4_audio_enable,
8362306a36Sopenharmony_ci};
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic struct radeon_audio_basic_funcs dce6_funcs = {
8662306a36Sopenharmony_ci	.endpoint_rreg = dce6_endpoint_rreg,
8762306a36Sopenharmony_ci	.endpoint_wreg = dce6_endpoint_wreg,
8862306a36Sopenharmony_ci	.enable = dce6_audio_enable,
8962306a36Sopenharmony_ci};
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic struct radeon_audio_funcs r600_hdmi_funcs = {
9262306a36Sopenharmony_ci	.get_pin = r600_audio_get_pin,
9362306a36Sopenharmony_ci	.set_dto = r600_hdmi_audio_set_dto,
9462306a36Sopenharmony_ci	.update_acr = r600_hdmi_update_acr,
9562306a36Sopenharmony_ci	.set_vbi_packet = r600_set_vbi_packet,
9662306a36Sopenharmony_ci	.set_avi_packet = r600_set_avi_packet,
9762306a36Sopenharmony_ci	.set_audio_packet = r600_set_audio_packet,
9862306a36Sopenharmony_ci	.set_mute = r600_set_mute,
9962306a36Sopenharmony_ci	.mode_set = radeon_audio_hdmi_mode_set,
10062306a36Sopenharmony_ci	.dpms = r600_hdmi_enable,
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic struct radeon_audio_funcs dce32_hdmi_funcs = {
10462306a36Sopenharmony_ci	.get_pin = r600_audio_get_pin,
10562306a36Sopenharmony_ci	.write_sad_regs = dce3_2_afmt_write_sad_regs,
10662306a36Sopenharmony_ci	.write_speaker_allocation = dce3_2_afmt_hdmi_write_speaker_allocation,
10762306a36Sopenharmony_ci	.set_dto = dce3_2_audio_set_dto,
10862306a36Sopenharmony_ci	.update_acr = dce3_2_hdmi_update_acr,
10962306a36Sopenharmony_ci	.set_vbi_packet = r600_set_vbi_packet,
11062306a36Sopenharmony_ci	.set_avi_packet = r600_set_avi_packet,
11162306a36Sopenharmony_ci	.set_audio_packet = dce3_2_set_audio_packet,
11262306a36Sopenharmony_ci	.set_mute = dce3_2_set_mute,
11362306a36Sopenharmony_ci	.mode_set = radeon_audio_hdmi_mode_set,
11462306a36Sopenharmony_ci	.dpms = r600_hdmi_enable,
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic struct radeon_audio_funcs dce32_dp_funcs = {
11862306a36Sopenharmony_ci	.get_pin = r600_audio_get_pin,
11962306a36Sopenharmony_ci	.write_sad_regs = dce3_2_afmt_write_sad_regs,
12062306a36Sopenharmony_ci	.write_speaker_allocation = dce3_2_afmt_dp_write_speaker_allocation,
12162306a36Sopenharmony_ci	.set_dto = dce3_2_audio_set_dto,
12262306a36Sopenharmony_ci	.set_avi_packet = r600_set_avi_packet,
12362306a36Sopenharmony_ci	.set_audio_packet = dce3_2_set_audio_packet,
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic struct radeon_audio_funcs dce4_hdmi_funcs = {
12762306a36Sopenharmony_ci	.get_pin = r600_audio_get_pin,
12862306a36Sopenharmony_ci	.write_sad_regs = evergreen_hdmi_write_sad_regs,
12962306a36Sopenharmony_ci	.write_speaker_allocation = dce4_afmt_hdmi_write_speaker_allocation,
13062306a36Sopenharmony_ci	.write_latency_fields = dce4_afmt_write_latency_fields,
13162306a36Sopenharmony_ci	.set_dto = dce4_hdmi_audio_set_dto,
13262306a36Sopenharmony_ci	.update_acr = evergreen_hdmi_update_acr,
13362306a36Sopenharmony_ci	.set_vbi_packet = dce4_set_vbi_packet,
13462306a36Sopenharmony_ci	.set_color_depth = dce4_hdmi_set_color_depth,
13562306a36Sopenharmony_ci	.set_avi_packet = evergreen_set_avi_packet,
13662306a36Sopenharmony_ci	.set_audio_packet = dce4_set_audio_packet,
13762306a36Sopenharmony_ci	.set_mute = dce4_set_mute,
13862306a36Sopenharmony_ci	.mode_set = radeon_audio_hdmi_mode_set,
13962306a36Sopenharmony_ci	.dpms = evergreen_hdmi_enable,
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic struct radeon_audio_funcs dce4_dp_funcs = {
14362306a36Sopenharmony_ci	.get_pin = r600_audio_get_pin,
14462306a36Sopenharmony_ci	.write_sad_regs = evergreen_hdmi_write_sad_regs,
14562306a36Sopenharmony_ci	.write_speaker_allocation = dce4_afmt_dp_write_speaker_allocation,
14662306a36Sopenharmony_ci	.write_latency_fields = dce4_afmt_write_latency_fields,
14762306a36Sopenharmony_ci	.set_dto = dce4_dp_audio_set_dto,
14862306a36Sopenharmony_ci	.set_avi_packet = evergreen_set_avi_packet,
14962306a36Sopenharmony_ci	.set_audio_packet = dce4_set_audio_packet,
15062306a36Sopenharmony_ci	.mode_set = radeon_audio_dp_mode_set,
15162306a36Sopenharmony_ci	.dpms = evergreen_dp_enable,
15262306a36Sopenharmony_ci};
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic struct radeon_audio_funcs dce6_hdmi_funcs = {
15562306a36Sopenharmony_ci	.select_pin = dce6_afmt_select_pin,
15662306a36Sopenharmony_ci	.get_pin = dce6_audio_get_pin,
15762306a36Sopenharmony_ci	.write_sad_regs = dce6_afmt_write_sad_regs,
15862306a36Sopenharmony_ci	.write_speaker_allocation = dce6_afmt_hdmi_write_speaker_allocation,
15962306a36Sopenharmony_ci	.write_latency_fields = dce6_afmt_write_latency_fields,
16062306a36Sopenharmony_ci	.set_dto = dce6_hdmi_audio_set_dto,
16162306a36Sopenharmony_ci	.update_acr = evergreen_hdmi_update_acr,
16262306a36Sopenharmony_ci	.set_vbi_packet = dce4_set_vbi_packet,
16362306a36Sopenharmony_ci	.set_color_depth = dce4_hdmi_set_color_depth,
16462306a36Sopenharmony_ci	.set_avi_packet = evergreen_set_avi_packet,
16562306a36Sopenharmony_ci	.set_audio_packet = dce4_set_audio_packet,
16662306a36Sopenharmony_ci	.set_mute = dce4_set_mute,
16762306a36Sopenharmony_ci	.mode_set = radeon_audio_hdmi_mode_set,
16862306a36Sopenharmony_ci	.dpms = evergreen_hdmi_enable,
16962306a36Sopenharmony_ci};
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic struct radeon_audio_funcs dce6_dp_funcs = {
17262306a36Sopenharmony_ci	.select_pin = dce6_afmt_select_pin,
17362306a36Sopenharmony_ci	.get_pin = dce6_audio_get_pin,
17462306a36Sopenharmony_ci	.write_sad_regs = dce6_afmt_write_sad_regs,
17562306a36Sopenharmony_ci	.write_speaker_allocation = dce6_afmt_dp_write_speaker_allocation,
17662306a36Sopenharmony_ci	.write_latency_fields = dce6_afmt_write_latency_fields,
17762306a36Sopenharmony_ci	.set_dto = dce6_dp_audio_set_dto,
17862306a36Sopenharmony_ci	.set_avi_packet = evergreen_set_avi_packet,
17962306a36Sopenharmony_ci	.set_audio_packet = dce4_set_audio_packet,
18062306a36Sopenharmony_ci	.mode_set = radeon_audio_dp_mode_set,
18162306a36Sopenharmony_ci	.dpms = evergreen_dp_enable,
18262306a36Sopenharmony_ci};
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic void radeon_audio_component_notify(struct radeon_device *rdev, int port);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic void radeon_audio_enable(struct radeon_device *rdev,
18762306a36Sopenharmony_ci				struct r600_audio_pin *pin, u8 enable_mask)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct drm_encoder *encoder;
19062306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder;
19162306a36Sopenharmony_ci	struct radeon_encoder_atom_dig *dig;
19262306a36Sopenharmony_ci	int pin_count = 0;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	if (!pin)
19562306a36Sopenharmony_ci		return;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (rdev->mode_info.mode_config_initialized) {
19862306a36Sopenharmony_ci		list_for_each_entry(encoder, &rdev->ddev->mode_config.encoder_list, head) {
19962306a36Sopenharmony_ci			if (radeon_encoder_is_digital(encoder)) {
20062306a36Sopenharmony_ci				radeon_encoder = to_radeon_encoder(encoder);
20162306a36Sopenharmony_ci				dig = radeon_encoder->enc_priv;
20262306a36Sopenharmony_ci				if (dig->pin == pin)
20362306a36Sopenharmony_ci					pin_count++;
20462306a36Sopenharmony_ci			}
20562306a36Sopenharmony_ci		}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci		if ((pin_count > 1) && (enable_mask == 0))
20862306a36Sopenharmony_ci			return;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (rdev->audio.funcs->enable)
21262306a36Sopenharmony_ci		rdev->audio.funcs->enable(rdev, pin, enable_mask);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	radeon_audio_component_notify(rdev, pin->id);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic void radeon_audio_interface_init(struct radeon_device *rdev)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	if (ASIC_IS_DCE6(rdev)) {
22062306a36Sopenharmony_ci		rdev->audio.funcs = &dce6_funcs;
22162306a36Sopenharmony_ci		rdev->audio.hdmi_funcs = &dce6_hdmi_funcs;
22262306a36Sopenharmony_ci		rdev->audio.dp_funcs = &dce6_dp_funcs;
22362306a36Sopenharmony_ci	} else if (ASIC_IS_DCE4(rdev)) {
22462306a36Sopenharmony_ci		rdev->audio.funcs = &dce4_funcs;
22562306a36Sopenharmony_ci		rdev->audio.hdmi_funcs = &dce4_hdmi_funcs;
22662306a36Sopenharmony_ci		rdev->audio.dp_funcs = &dce4_dp_funcs;
22762306a36Sopenharmony_ci	} else if (ASIC_IS_DCE32(rdev)) {
22862306a36Sopenharmony_ci		rdev->audio.funcs = &dce32_funcs;
22962306a36Sopenharmony_ci		rdev->audio.hdmi_funcs = &dce32_hdmi_funcs;
23062306a36Sopenharmony_ci		rdev->audio.dp_funcs = &dce32_dp_funcs;
23162306a36Sopenharmony_ci	} else {
23262306a36Sopenharmony_ci		rdev->audio.funcs = &r600_funcs;
23362306a36Sopenharmony_ci		rdev->audio.hdmi_funcs = &r600_hdmi_funcs;
23462306a36Sopenharmony_ci		rdev->audio.dp_funcs = NULL;
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic int radeon_audio_chipset_supported(struct radeon_device *rdev)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ciint radeon_audio_init(struct radeon_device *rdev)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	int i;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (!radeon_audio || !radeon_audio_chipset_supported(rdev))
24862306a36Sopenharmony_ci		return 0;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	rdev->audio.enabled = true;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if (ASIC_IS_DCE83(rdev))		/* KB: 2 streams, 3 endpoints */
25362306a36Sopenharmony_ci		rdev->audio.num_pins = 3;
25462306a36Sopenharmony_ci	else if (ASIC_IS_DCE81(rdev))	/* KV: 4 streams, 7 endpoints */
25562306a36Sopenharmony_ci		rdev->audio.num_pins = 7;
25662306a36Sopenharmony_ci	else if (ASIC_IS_DCE8(rdev))	/* BN/HW: 6 streams, 7 endpoints */
25762306a36Sopenharmony_ci		rdev->audio.num_pins = 7;
25862306a36Sopenharmony_ci	else if (ASIC_IS_DCE64(rdev))	/* OL: 2 streams, 2 endpoints */
25962306a36Sopenharmony_ci		rdev->audio.num_pins = 2;
26062306a36Sopenharmony_ci	else if (ASIC_IS_DCE61(rdev))	/* TN: 4 streams, 6 endpoints */
26162306a36Sopenharmony_ci		rdev->audio.num_pins = 6;
26262306a36Sopenharmony_ci	else if (ASIC_IS_DCE6(rdev))	/* SI: 6 streams, 6 endpoints */
26362306a36Sopenharmony_ci		rdev->audio.num_pins = 6;
26462306a36Sopenharmony_ci	else
26562306a36Sopenharmony_ci		rdev->audio.num_pins = 1;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	for (i = 0; i < rdev->audio.num_pins; i++) {
26862306a36Sopenharmony_ci		rdev->audio.pin[i].channels = -1;
26962306a36Sopenharmony_ci		rdev->audio.pin[i].rate = -1;
27062306a36Sopenharmony_ci		rdev->audio.pin[i].bits_per_sample = -1;
27162306a36Sopenharmony_ci		rdev->audio.pin[i].status_bits = 0;
27262306a36Sopenharmony_ci		rdev->audio.pin[i].category_code = 0;
27362306a36Sopenharmony_ci		rdev->audio.pin[i].connected = false;
27462306a36Sopenharmony_ci		rdev->audio.pin[i].offset = pin_offsets[i];
27562306a36Sopenharmony_ci		rdev->audio.pin[i].id = i;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	radeon_audio_interface_init(rdev);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* disable audio.  it will be set up later */
28162306a36Sopenharmony_ci	for (i = 0; i < rdev->audio.num_pins; i++)
28262306a36Sopenharmony_ci		radeon_audio_enable(rdev, &rdev->audio.pin[i], 0);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	return 0;
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ciu32 radeon_audio_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	if (rdev->audio.funcs->endpoint_rreg)
29062306a36Sopenharmony_ci		return rdev->audio.funcs->endpoint_rreg(rdev, offset, reg);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	return 0;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_civoid radeon_audio_endpoint_wreg(struct radeon_device *rdev, u32 offset,
29662306a36Sopenharmony_ci	u32 reg, u32 v)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	if (rdev->audio.funcs->endpoint_wreg)
29962306a36Sopenharmony_ci		rdev->audio.funcs->endpoint_wreg(rdev, offset, reg, v);
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic void radeon_audio_write_sad_regs(struct drm_encoder *encoder)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
30562306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
30662306a36Sopenharmony_ci	struct cea_sad *sads;
30762306a36Sopenharmony_ci	int sad_count;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (!connector)
31062306a36Sopenharmony_ci		return;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads);
31362306a36Sopenharmony_ci	if (sad_count < 0)
31462306a36Sopenharmony_ci		DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
31562306a36Sopenharmony_ci	if (sad_count <= 0)
31662306a36Sopenharmony_ci		return;
31762306a36Sopenharmony_ci	BUG_ON(!sads);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->write_sad_regs)
32062306a36Sopenharmony_ci		radeon_encoder->audio->write_sad_regs(encoder, sads, sad_count);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	kfree(sads);
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic void radeon_audio_write_speaker_allocation(struct drm_encoder *encoder)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
32862306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
32962306a36Sopenharmony_ci	u8 *sadb = NULL;
33062306a36Sopenharmony_ci	int sad_count;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (!connector)
33362306a36Sopenharmony_ci		return;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector),
33662306a36Sopenharmony_ci						   &sadb);
33762306a36Sopenharmony_ci	if (sad_count < 0) {
33862306a36Sopenharmony_ci		DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n",
33962306a36Sopenharmony_ci			  sad_count);
34062306a36Sopenharmony_ci		sad_count = 0;
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->write_speaker_allocation)
34462306a36Sopenharmony_ci		radeon_encoder->audio->write_speaker_allocation(encoder, sadb, sad_count);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	kfree(sadb);
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic void radeon_audio_write_latency_fields(struct drm_encoder *encoder,
35062306a36Sopenharmony_ci					      struct drm_display_mode *mode)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
35362306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (!connector)
35662306a36Sopenharmony_ci		return;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->write_latency_fields)
35962306a36Sopenharmony_ci		radeon_encoder->audio->write_latency_fields(encoder, connector, mode);
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistruct r600_audio_pin* radeon_audio_get_pin(struct drm_encoder *encoder)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	struct radeon_device *rdev = encoder->dev->dev_private;
36562306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->get_pin)
36862306a36Sopenharmony_ci		return radeon_encoder->audio->get_pin(rdev);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	return NULL;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic void radeon_audio_select_pin(struct drm_encoder *encoder)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->select_pin)
37862306a36Sopenharmony_ci		radeon_encoder->audio->select_pin(encoder);
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_civoid radeon_audio_detect(struct drm_connector *connector,
38262306a36Sopenharmony_ci			 struct drm_encoder *encoder,
38362306a36Sopenharmony_ci			 enum drm_connector_status status)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	struct drm_device *dev = connector->dev;
38662306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
38762306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
38862306a36Sopenharmony_ci	struct radeon_encoder_atom_dig *dig;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (!radeon_audio_chipset_supported(rdev))
39162306a36Sopenharmony_ci		return;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	if (!radeon_encoder_is_digital(encoder))
39462306a36Sopenharmony_ci		return;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	dig = radeon_encoder->enc_priv;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (status == connector_status_connected) {
39962306a36Sopenharmony_ci		if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
40062306a36Sopenharmony_ci			struct radeon_connector *radeon_connector = to_radeon_connector(connector);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci			if (radeon_dp_getsinktype(radeon_connector) ==
40362306a36Sopenharmony_ci			    CONNECTOR_OBJECT_ID_DISPLAYPORT)
40462306a36Sopenharmony_ci				radeon_encoder->audio = rdev->audio.dp_funcs;
40562306a36Sopenharmony_ci			else
40662306a36Sopenharmony_ci				radeon_encoder->audio = rdev->audio.hdmi_funcs;
40762306a36Sopenharmony_ci		} else {
40862306a36Sopenharmony_ci			radeon_encoder->audio = rdev->audio.hdmi_funcs;
40962306a36Sopenharmony_ci		}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci		if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
41262306a36Sopenharmony_ci			if (!dig->pin)
41362306a36Sopenharmony_ci				dig->pin = radeon_audio_get_pin(encoder);
41462306a36Sopenharmony_ci			radeon_audio_enable(rdev, dig->pin, 0xf);
41562306a36Sopenharmony_ci		} else {
41662306a36Sopenharmony_ci			radeon_audio_enable(rdev, dig->pin, 0);
41762306a36Sopenharmony_ci			dig->pin = NULL;
41862306a36Sopenharmony_ci		}
41962306a36Sopenharmony_ci	} else {
42062306a36Sopenharmony_ci		radeon_audio_enable(rdev, dig->pin, 0);
42162306a36Sopenharmony_ci		dig->pin = NULL;
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_civoid radeon_audio_fini(struct radeon_device *rdev)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	int i;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	if (!rdev->audio.enabled)
43062306a36Sopenharmony_ci		return;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	for (i = 0; i < rdev->audio.num_pins; i++)
43362306a36Sopenharmony_ci		radeon_audio_enable(rdev, &rdev->audio.pin[i], 0);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	rdev->audio.enabled = false;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic void radeon_audio_set_dto(struct drm_encoder *encoder, unsigned int clock)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	struct radeon_device *rdev = encoder->dev->dev_private;
44162306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
44262306a36Sopenharmony_ci	struct radeon_crtc *crtc = to_radeon_crtc(encoder->crtc);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->set_dto)
44562306a36Sopenharmony_ci		radeon_encoder->audio->set_dto(rdev, crtc, clock);
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic int radeon_audio_set_avi_packet(struct drm_encoder *encoder,
44962306a36Sopenharmony_ci				       struct drm_display_mode *mode)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct radeon_device *rdev = encoder->dev->dev_private;
45262306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
45362306a36Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
45462306a36Sopenharmony_ci	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
45562306a36Sopenharmony_ci	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
45662306a36Sopenharmony_ci	struct hdmi_avi_infoframe frame;
45762306a36Sopenharmony_ci	int err;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	if (!connector)
46062306a36Sopenharmony_ci		return -EINVAL;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode);
46362306a36Sopenharmony_ci	if (err < 0) {
46462306a36Sopenharmony_ci		DRM_ERROR("failed to setup AVI infoframe: %d\n", err);
46562306a36Sopenharmony_ci		return err;
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	if (radeon_encoder->output_csc != RADEON_OUTPUT_CSC_BYPASS) {
46962306a36Sopenharmony_ci		drm_hdmi_avi_infoframe_quant_range(&frame, connector, mode,
47062306a36Sopenharmony_ci						   radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB ?
47162306a36Sopenharmony_ci						   HDMI_QUANTIZATION_RANGE_LIMITED :
47262306a36Sopenharmony_ci						   HDMI_QUANTIZATION_RANGE_FULL);
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
47662306a36Sopenharmony_ci	if (err < 0) {
47762306a36Sopenharmony_ci		DRM_ERROR("failed to pack AVI infoframe: %d\n", err);
47862306a36Sopenharmony_ci		return err;
47962306a36Sopenharmony_ci	}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	if (dig && dig->afmt && radeon_encoder->audio &&
48262306a36Sopenharmony_ci	    radeon_encoder->audio->set_avi_packet)
48362306a36Sopenharmony_ci		radeon_encoder->audio->set_avi_packet(rdev, dig->afmt->offset,
48462306a36Sopenharmony_ci			buffer, sizeof(buffer));
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	return 0;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci/*
49062306a36Sopenharmony_ci * calculate CTS and N values if they are not found in the table
49162306a36Sopenharmony_ci */
49262306a36Sopenharmony_cistatic void radeon_audio_calc_cts(unsigned int clock, int *CTS, int *N, int freq)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	int n, cts;
49562306a36Sopenharmony_ci	unsigned long div, mul;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	/* Safe, but overly large values */
49862306a36Sopenharmony_ci	n = 128 * freq;
49962306a36Sopenharmony_ci	cts = clock * 1000;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	/* Smallest valid fraction */
50262306a36Sopenharmony_ci	div = gcd(n, cts);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	n /= div;
50562306a36Sopenharmony_ci	cts /= div;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	/*
50862306a36Sopenharmony_ci	 * The optimal N is 128*freq/1000. Calculate the closest larger
50962306a36Sopenharmony_ci	 * value that doesn't truncate any bits.
51062306a36Sopenharmony_ci	 */
51162306a36Sopenharmony_ci	mul = ((128*freq/1000) + (n-1))/n;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	n *= mul;
51462306a36Sopenharmony_ci	cts *= mul;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	/* Check that we are in spec (not always possible) */
51762306a36Sopenharmony_ci	if (n < (128*freq/1500))
51862306a36Sopenharmony_ci		pr_warn("Calculated ACR N value is too small. You may experience audio problems.\n");
51962306a36Sopenharmony_ci	if (n > (128*freq/300))
52062306a36Sopenharmony_ci		pr_warn("Calculated ACR N value is too large. You may experience audio problems.\n");
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	*N = n;
52362306a36Sopenharmony_ci	*CTS = cts;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n",
52662306a36Sopenharmony_ci		*N, *CTS, freq);
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic const struct radeon_hdmi_acr* radeon_audio_acr(unsigned int clock)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	static struct radeon_hdmi_acr res;
53262306a36Sopenharmony_ci	u8 i;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	static const struct radeon_hdmi_acr hdmi_predefined_acr[] = {
53562306a36Sopenharmony_ci		/*       32kHz    44.1kHz   48kHz    */
53662306a36Sopenharmony_ci		/* Clock      N     CTS      N     CTS      N     CTS */
53762306a36Sopenharmony_ci		{  25175,  4096,  25175, 28224, 125875,  6144,  25175 }, /*  25,20/1.001 MHz */
53862306a36Sopenharmony_ci		{  25200,  4096,  25200,  6272,  28000,  6144,  25200 }, /*  25.20       MHz */
53962306a36Sopenharmony_ci		{  27000,  4096,  27000,  6272,  30000,  6144,  27000 }, /*  27.00       MHz */
54062306a36Sopenharmony_ci		{  27027,  4096,  27027,  6272,  30030,  6144,  27027 }, /*  27.00*1.001 MHz */
54162306a36Sopenharmony_ci		{  54000,  4096,  54000,  6272,  60000,  6144,  54000 }, /*  54.00       MHz */
54262306a36Sopenharmony_ci		{  54054,  4096,  54054,  6272,  60060,  6144,  54054 }, /*  54.00*1.001 MHz */
54362306a36Sopenharmony_ci		{  74176,  4096,  74176,  5733,  75335,  6144,  74176 }, /*  74.25/1.001 MHz */
54462306a36Sopenharmony_ci		{  74250,  4096,  74250,  6272,  82500,  6144,  74250 }, /*  74.25       MHz */
54562306a36Sopenharmony_ci		{ 148352,  4096, 148352,  5733, 150670,  6144, 148352 }, /* 148.50/1.001 MHz */
54662306a36Sopenharmony_ci		{ 148500,  4096, 148500,  6272, 165000,  6144, 148500 }, /* 148.50       MHz */
54762306a36Sopenharmony_ci	};
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	/* Precalculated values for common clocks */
55062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(hdmi_predefined_acr); i++)
55162306a36Sopenharmony_ci		if (hdmi_predefined_acr[i].clock == clock)
55262306a36Sopenharmony_ci			return &hdmi_predefined_acr[i];
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	/* And odd clocks get manually calculated */
55562306a36Sopenharmony_ci	radeon_audio_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000);
55662306a36Sopenharmony_ci	radeon_audio_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100);
55762306a36Sopenharmony_ci	radeon_audio_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	return &res;
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci/*
56362306a36Sopenharmony_ci * update the N and CTS parameters for a given pixel clock rate
56462306a36Sopenharmony_ci */
56562306a36Sopenharmony_cistatic void radeon_audio_update_acr(struct drm_encoder *encoder, unsigned int clock)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	const struct radeon_hdmi_acr *acr = radeon_audio_acr(clock);
56862306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
56962306a36Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	if (!dig || !dig->afmt)
57262306a36Sopenharmony_ci		return;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->update_acr)
57562306a36Sopenharmony_ci		radeon_encoder->audio->update_acr(encoder, dig->afmt->offset, acr);
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cistatic void radeon_audio_set_vbi_packet(struct drm_encoder *encoder)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
58162306a36Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	if (!dig || !dig->afmt)
58462306a36Sopenharmony_ci		return;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->set_vbi_packet)
58762306a36Sopenharmony_ci		radeon_encoder->audio->set_vbi_packet(encoder, dig->afmt->offset);
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic void radeon_hdmi_set_color_depth(struct drm_encoder *encoder)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	int bpc = 8;
59362306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
59462306a36Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	if (!dig || !dig->afmt)
59762306a36Sopenharmony_ci		return;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	if (encoder->crtc) {
60062306a36Sopenharmony_ci		struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
60162306a36Sopenharmony_ci		bpc = radeon_crtc->bpc;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->set_color_depth)
60562306a36Sopenharmony_ci		radeon_encoder->audio->set_color_depth(encoder, dig->afmt->offset, bpc);
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic void radeon_audio_set_audio_packet(struct drm_encoder *encoder)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
61162306a36Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (!dig || !dig->afmt)
61462306a36Sopenharmony_ci		return;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->set_audio_packet)
61762306a36Sopenharmony_ci		radeon_encoder->audio->set_audio_packet(encoder, dig->afmt->offset);
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_cistatic void radeon_audio_set_mute(struct drm_encoder *encoder, bool mute)
62162306a36Sopenharmony_ci{
62262306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
62362306a36Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	if (!dig || !dig->afmt)
62662306a36Sopenharmony_ci		return;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->set_mute)
62962306a36Sopenharmony_ci		radeon_encoder->audio->set_mute(encoder, dig->afmt->offset, mute);
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci/*
63362306a36Sopenharmony_ci * update the info frames with the data from the current display mode
63462306a36Sopenharmony_ci */
63562306a36Sopenharmony_cistatic void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
63662306a36Sopenharmony_ci				       struct drm_display_mode *mode)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
63962306a36Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
64062306a36Sopenharmony_ci	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (!dig || !dig->afmt)
64362306a36Sopenharmony_ci		return;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	if (!connector)
64662306a36Sopenharmony_ci		return;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
64962306a36Sopenharmony_ci		radeon_audio_set_mute(encoder, true);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		radeon_audio_write_speaker_allocation(encoder);
65262306a36Sopenharmony_ci		radeon_audio_write_sad_regs(encoder);
65362306a36Sopenharmony_ci		radeon_audio_write_latency_fields(encoder, mode);
65462306a36Sopenharmony_ci		radeon_audio_set_dto(encoder, mode->clock);
65562306a36Sopenharmony_ci		radeon_audio_set_vbi_packet(encoder);
65662306a36Sopenharmony_ci		radeon_hdmi_set_color_depth(encoder);
65762306a36Sopenharmony_ci		radeon_audio_update_acr(encoder, mode->clock);
65862306a36Sopenharmony_ci		radeon_audio_set_audio_packet(encoder);
65962306a36Sopenharmony_ci		radeon_audio_select_pin(encoder);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci		if (radeon_audio_set_avi_packet(encoder, mode) < 0)
66262306a36Sopenharmony_ci			return;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci		radeon_audio_set_mute(encoder, false);
66562306a36Sopenharmony_ci	} else {
66662306a36Sopenharmony_ci		radeon_hdmi_set_color_depth(encoder);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci		if (radeon_audio_set_avi_packet(encoder, mode) < 0)
66962306a36Sopenharmony_ci			return;
67062306a36Sopenharmony_ci	}
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
67462306a36Sopenharmony_ci				     struct drm_display_mode *mode)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	struct drm_device *dev = encoder->dev;
67762306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
67862306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
67962306a36Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
68062306a36Sopenharmony_ci	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	if (!dig || !dig->afmt)
68362306a36Sopenharmony_ci		return;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	if (!connector)
68662306a36Sopenharmony_ci		return;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
68962306a36Sopenharmony_ci		radeon_audio_write_speaker_allocation(encoder);
69062306a36Sopenharmony_ci		radeon_audio_write_sad_regs(encoder);
69162306a36Sopenharmony_ci		radeon_audio_write_latency_fields(encoder, mode);
69262306a36Sopenharmony_ci		radeon_audio_set_dto(encoder, rdev->clock.vco_freq * 10);
69362306a36Sopenharmony_ci		radeon_audio_set_audio_packet(encoder);
69462306a36Sopenharmony_ci		radeon_audio_select_pin(encoder);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci		if (radeon_audio_set_avi_packet(encoder, mode) < 0)
69762306a36Sopenharmony_ci			return;
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_civoid radeon_audio_mode_set(struct drm_encoder *encoder,
70262306a36Sopenharmony_ci			   struct drm_display_mode *mode)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->mode_set)
70762306a36Sopenharmony_ci		radeon_encoder->audio->mode_set(encoder, mode);
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_civoid radeon_audio_dpms(struct drm_encoder *encoder, int mode)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->dpms)
71562306a36Sopenharmony_ci		radeon_encoder->audio->dpms(encoder, mode == DRM_MODE_DPMS_ON);
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ciunsigned int radeon_audio_decode_dfs_div(unsigned int div)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	if (div >= 8 && div < 64)
72162306a36Sopenharmony_ci		return (div - 8) * 25 + 200;
72262306a36Sopenharmony_ci	else if (div >= 64 && div < 96)
72362306a36Sopenharmony_ci		return (div - 64) * 50 + 1600;
72462306a36Sopenharmony_ci	else if (div >= 96 && div < 128)
72562306a36Sopenharmony_ci		return (div - 96) * 100 + 3200;
72662306a36Sopenharmony_ci	else
72762306a36Sopenharmony_ci		return 0;
72862306a36Sopenharmony_ci}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci/*
73162306a36Sopenharmony_ci * Audio component support
73262306a36Sopenharmony_ci */
73362306a36Sopenharmony_cistatic void radeon_audio_component_notify(struct radeon_device *rdev, int port)
73462306a36Sopenharmony_ci{
73562306a36Sopenharmony_ci	struct drm_audio_component *acomp;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	mutex_lock(&rdev->audio.component_mutex);
73862306a36Sopenharmony_ci	acomp = rdev->audio.component;
73962306a36Sopenharmony_ci	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
74062306a36Sopenharmony_ci		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
74162306a36Sopenharmony_ci						 port, -1);
74262306a36Sopenharmony_ci	mutex_unlock(&rdev->audio.component_mutex);
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic int radeon_audio_component_get_eld(struct device *kdev, int port,
74662306a36Sopenharmony_ci					  int pipe, bool *enabled,
74762306a36Sopenharmony_ci					  unsigned char *buf, int max_bytes)
74862306a36Sopenharmony_ci{
74962306a36Sopenharmony_ci	struct drm_device *dev = dev_get_drvdata(kdev);
75062306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
75162306a36Sopenharmony_ci	struct drm_encoder *encoder;
75262306a36Sopenharmony_ci	struct radeon_encoder *radeon_encoder;
75362306a36Sopenharmony_ci	struct radeon_encoder_atom_dig *dig;
75462306a36Sopenharmony_ci	struct drm_connector *connector;
75562306a36Sopenharmony_ci	int ret = 0;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	*enabled = false;
75862306a36Sopenharmony_ci	if (!rdev->audio.enabled || !rdev->mode_info.mode_config_initialized)
75962306a36Sopenharmony_ci		return 0;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	list_for_each_entry(encoder, &rdev->ddev->mode_config.encoder_list, head) {
76262306a36Sopenharmony_ci		if (!radeon_encoder_is_digital(encoder))
76362306a36Sopenharmony_ci			continue;
76462306a36Sopenharmony_ci		radeon_encoder = to_radeon_encoder(encoder);
76562306a36Sopenharmony_ci		dig = radeon_encoder->enc_priv;
76662306a36Sopenharmony_ci		if (!dig->pin || dig->pin->id != port)
76762306a36Sopenharmony_ci			continue;
76862306a36Sopenharmony_ci		connector = radeon_get_connector_for_encoder(encoder);
76962306a36Sopenharmony_ci		if (!connector)
77062306a36Sopenharmony_ci			continue;
77162306a36Sopenharmony_ci		*enabled = true;
77262306a36Sopenharmony_ci		ret = drm_eld_size(connector->eld);
77362306a36Sopenharmony_ci		memcpy(buf, connector->eld, min(max_bytes, ret));
77462306a36Sopenharmony_ci		break;
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	return ret;
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_cistatic const struct drm_audio_component_ops radeon_audio_component_ops = {
78162306a36Sopenharmony_ci	.get_eld = radeon_audio_component_get_eld,
78262306a36Sopenharmony_ci};
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_cistatic int radeon_audio_component_bind(struct device *kdev,
78562306a36Sopenharmony_ci				       struct device *hda_kdev, void *data)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	struct drm_device *dev = dev_get_drvdata(kdev);
78862306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
78962306a36Sopenharmony_ci	struct drm_audio_component *acomp = data;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (WARN_ON(!device_link_add(hda_kdev, kdev, DL_FLAG_STATELESS)))
79262306a36Sopenharmony_ci		return -ENOMEM;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	mutex_lock(&rdev->audio.component_mutex);
79562306a36Sopenharmony_ci	acomp->ops = &radeon_audio_component_ops;
79662306a36Sopenharmony_ci	acomp->dev = kdev;
79762306a36Sopenharmony_ci	rdev->audio.component = acomp;
79862306a36Sopenharmony_ci	mutex_unlock(&rdev->audio.component_mutex);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	return 0;
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_cistatic void radeon_audio_component_unbind(struct device *kdev,
80462306a36Sopenharmony_ci					  struct device *hda_kdev, void *data)
80562306a36Sopenharmony_ci{
80662306a36Sopenharmony_ci	struct drm_device *dev = dev_get_drvdata(kdev);
80762306a36Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
80862306a36Sopenharmony_ci	struct drm_audio_component *acomp = data;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	device_link_remove(hda_kdev, kdev);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	mutex_lock(&rdev->audio.component_mutex);
81362306a36Sopenharmony_ci	rdev->audio.component = NULL;
81462306a36Sopenharmony_ci	acomp->ops = NULL;
81562306a36Sopenharmony_ci	acomp->dev = NULL;
81662306a36Sopenharmony_ci	mutex_unlock(&rdev->audio.component_mutex);
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic const struct component_ops radeon_audio_component_bind_ops = {
82062306a36Sopenharmony_ci	.bind	= radeon_audio_component_bind,
82162306a36Sopenharmony_ci	.unbind	= radeon_audio_component_unbind,
82262306a36Sopenharmony_ci};
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_civoid radeon_audio_component_init(struct radeon_device *rdev)
82562306a36Sopenharmony_ci{
82662306a36Sopenharmony_ci	if (rdev->audio.component_registered ||
82762306a36Sopenharmony_ci	    !radeon_audio || !radeon_audio_chipset_supported(rdev))
82862306a36Sopenharmony_ci		return;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	if (!component_add(rdev->dev, &radeon_audio_component_bind_ops))
83162306a36Sopenharmony_ci		rdev->audio.component_registered = true;
83262306a36Sopenharmony_ci}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_civoid radeon_audio_component_fini(struct radeon_device *rdev)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	if (rdev->audio.component_registered) {
83762306a36Sopenharmony_ci		component_del(rdev->dev, &radeon_audio_component_bind_ops);
83862306a36Sopenharmony_ci		rdev->audio.component_registered = false;
83962306a36Sopenharmony_ci	}
84062306a36Sopenharmony_ci}
841