18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2014 Advanced Micro Devices, Inc.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * Authors: Slava Grigorev <slava.grigorev@amd.com>
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <linux/gcd.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <drm/drm_crtc.h>
288c2ecf20Sopenharmony_ci#include "radeon.h"
298c2ecf20Sopenharmony_ci#include "atom.h"
308c2ecf20Sopenharmony_ci#include "radeon_audio.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_civoid r600_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
338c2ecf20Sopenharmony_ci		u8 enable_mask);
348c2ecf20Sopenharmony_civoid dce4_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
358c2ecf20Sopenharmony_ci		u8 enable_mask);
368c2ecf20Sopenharmony_civoid dce6_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
378c2ecf20Sopenharmony_ci		u8 enable_mask);
388c2ecf20Sopenharmony_ciu32 dce6_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg);
398c2ecf20Sopenharmony_civoid dce6_endpoint_wreg(struct radeon_device *rdev,
408c2ecf20Sopenharmony_ci		u32 offset, u32 reg, u32 v);
418c2ecf20Sopenharmony_civoid dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder,
428c2ecf20Sopenharmony_ci		struct cea_sad *sads, int sad_count);
438c2ecf20Sopenharmony_civoid evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder,
448c2ecf20Sopenharmony_ci		struct cea_sad *sads, int sad_count);
458c2ecf20Sopenharmony_civoid dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
468c2ecf20Sopenharmony_ci		struct cea_sad *sads, int sad_count);
478c2ecf20Sopenharmony_civoid dce3_2_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
488c2ecf20Sopenharmony_ci		u8 *sadb, int sad_count);
498c2ecf20Sopenharmony_civoid dce3_2_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
508c2ecf20Sopenharmony_ci		u8 *sadb, int sad_count);
518c2ecf20Sopenharmony_civoid dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
528c2ecf20Sopenharmony_ci		u8 *sadb, int sad_count);
538c2ecf20Sopenharmony_civoid dce4_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
548c2ecf20Sopenharmony_ci		u8 *sadb, int sad_count);
558c2ecf20Sopenharmony_civoid dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
568c2ecf20Sopenharmony_ci		u8 *sadb, int sad_count);
578c2ecf20Sopenharmony_civoid dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
588c2ecf20Sopenharmony_ci		u8 *sadb, int sad_count);
598c2ecf20Sopenharmony_civoid dce4_afmt_write_latency_fields(struct drm_encoder *encoder,
608c2ecf20Sopenharmony_ci		struct drm_connector *connector, struct drm_display_mode *mode);
618c2ecf20Sopenharmony_civoid dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
628c2ecf20Sopenharmony_ci		struct drm_connector *connector, struct drm_display_mode *mode);
638c2ecf20Sopenharmony_cistruct r600_audio_pin* r600_audio_get_pin(struct radeon_device *rdev);
648c2ecf20Sopenharmony_cistruct r600_audio_pin* dce6_audio_get_pin(struct radeon_device *rdev);
658c2ecf20Sopenharmony_civoid dce6_afmt_select_pin(struct drm_encoder *encoder);
668c2ecf20Sopenharmony_civoid r600_hdmi_audio_set_dto(struct radeon_device *rdev,
678c2ecf20Sopenharmony_ci	struct radeon_crtc *crtc, unsigned int clock);
688c2ecf20Sopenharmony_civoid dce3_2_audio_set_dto(struct radeon_device *rdev,
698c2ecf20Sopenharmony_ci	struct radeon_crtc *crtc, unsigned int clock);
708c2ecf20Sopenharmony_civoid dce4_hdmi_audio_set_dto(struct radeon_device *rdev,
718c2ecf20Sopenharmony_ci	struct radeon_crtc *crtc, unsigned int clock);
728c2ecf20Sopenharmony_civoid dce4_dp_audio_set_dto(struct radeon_device *rdev,
738c2ecf20Sopenharmony_ci	struct radeon_crtc *crtc, unsigned int clock);
748c2ecf20Sopenharmony_civoid dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
758c2ecf20Sopenharmony_ci	struct radeon_crtc *crtc, unsigned int clock);
768c2ecf20Sopenharmony_civoid dce6_dp_audio_set_dto(struct radeon_device *rdev,
778c2ecf20Sopenharmony_ci	struct radeon_crtc *crtc, unsigned int clock);
788c2ecf20Sopenharmony_civoid r600_set_avi_packet(struct radeon_device *rdev, u32 offset,
798c2ecf20Sopenharmony_ci	unsigned char *buffer, size_t size);
808c2ecf20Sopenharmony_civoid evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset,
818c2ecf20Sopenharmony_ci	unsigned char *buffer, size_t size);
828c2ecf20Sopenharmony_civoid r600_hdmi_update_acr(struct drm_encoder *encoder, long offset,
838c2ecf20Sopenharmony_ci	const struct radeon_hdmi_acr *acr);
848c2ecf20Sopenharmony_civoid dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset,
858c2ecf20Sopenharmony_ci	const struct radeon_hdmi_acr *acr);
868c2ecf20Sopenharmony_civoid evergreen_hdmi_update_acr(struct drm_encoder *encoder, long offset,
878c2ecf20Sopenharmony_ci	const struct radeon_hdmi_acr *acr);
888c2ecf20Sopenharmony_civoid r600_set_vbi_packet(struct drm_encoder *encoder, u32 offset);
898c2ecf20Sopenharmony_civoid dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset);
908c2ecf20Sopenharmony_civoid dce4_hdmi_set_color_depth(struct drm_encoder *encoder,
918c2ecf20Sopenharmony_ci	u32 offset, int bpc);
928c2ecf20Sopenharmony_civoid r600_set_audio_packet(struct drm_encoder *encoder, u32 offset);
938c2ecf20Sopenharmony_civoid dce3_2_set_audio_packet(struct drm_encoder *encoder, u32 offset);
948c2ecf20Sopenharmony_civoid dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset);
958c2ecf20Sopenharmony_civoid r600_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
968c2ecf20Sopenharmony_civoid dce3_2_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
978c2ecf20Sopenharmony_civoid dce4_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
988c2ecf20Sopenharmony_cistatic void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
998c2ecf20Sopenharmony_ci	struct drm_display_mode *mode);
1008c2ecf20Sopenharmony_cistatic void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
1018c2ecf20Sopenharmony_ci	struct drm_display_mode *mode);
1028c2ecf20Sopenharmony_civoid r600_hdmi_enable(struct drm_encoder *encoder, bool enable);
1038c2ecf20Sopenharmony_civoid evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
1048c2ecf20Sopenharmony_civoid evergreen_dp_enable(struct drm_encoder *encoder, bool enable);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic const u32 pin_offsets[7] =
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	(0x5e00 - 0x5e00),
1098c2ecf20Sopenharmony_ci	(0x5e18 - 0x5e00),
1108c2ecf20Sopenharmony_ci	(0x5e30 - 0x5e00),
1118c2ecf20Sopenharmony_ci	(0x5e48 - 0x5e00),
1128c2ecf20Sopenharmony_ci	(0x5e60 - 0x5e00),
1138c2ecf20Sopenharmony_ci	(0x5e78 - 0x5e00),
1148c2ecf20Sopenharmony_ci	(0x5e90 - 0x5e00),
1158c2ecf20Sopenharmony_ci};
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic u32 radeon_audio_rreg(struct radeon_device *rdev, u32 offset, u32 reg)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	return RREG32(reg);
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic void radeon_audio_wreg(struct radeon_device *rdev, u32 offset,
1238c2ecf20Sopenharmony_ci		u32 reg, u32 v)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	WREG32(reg, v);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic struct radeon_audio_basic_funcs r600_funcs = {
1298c2ecf20Sopenharmony_ci	.endpoint_rreg = radeon_audio_rreg,
1308c2ecf20Sopenharmony_ci	.endpoint_wreg = radeon_audio_wreg,
1318c2ecf20Sopenharmony_ci	.enable = r600_audio_enable,
1328c2ecf20Sopenharmony_ci};
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic struct radeon_audio_basic_funcs dce32_funcs = {
1358c2ecf20Sopenharmony_ci	.endpoint_rreg = radeon_audio_rreg,
1368c2ecf20Sopenharmony_ci	.endpoint_wreg = radeon_audio_wreg,
1378c2ecf20Sopenharmony_ci	.enable = r600_audio_enable,
1388c2ecf20Sopenharmony_ci};
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic struct radeon_audio_basic_funcs dce4_funcs = {
1418c2ecf20Sopenharmony_ci	.endpoint_rreg = radeon_audio_rreg,
1428c2ecf20Sopenharmony_ci	.endpoint_wreg = radeon_audio_wreg,
1438c2ecf20Sopenharmony_ci	.enable = dce4_audio_enable,
1448c2ecf20Sopenharmony_ci};
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic struct radeon_audio_basic_funcs dce6_funcs = {
1478c2ecf20Sopenharmony_ci	.endpoint_rreg = dce6_endpoint_rreg,
1488c2ecf20Sopenharmony_ci	.endpoint_wreg = dce6_endpoint_wreg,
1498c2ecf20Sopenharmony_ci	.enable = dce6_audio_enable,
1508c2ecf20Sopenharmony_ci};
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic struct radeon_audio_funcs r600_hdmi_funcs = {
1538c2ecf20Sopenharmony_ci	.get_pin = r600_audio_get_pin,
1548c2ecf20Sopenharmony_ci	.set_dto = r600_hdmi_audio_set_dto,
1558c2ecf20Sopenharmony_ci	.update_acr = r600_hdmi_update_acr,
1568c2ecf20Sopenharmony_ci	.set_vbi_packet = r600_set_vbi_packet,
1578c2ecf20Sopenharmony_ci	.set_avi_packet = r600_set_avi_packet,
1588c2ecf20Sopenharmony_ci	.set_audio_packet = r600_set_audio_packet,
1598c2ecf20Sopenharmony_ci	.set_mute = r600_set_mute,
1608c2ecf20Sopenharmony_ci	.mode_set = radeon_audio_hdmi_mode_set,
1618c2ecf20Sopenharmony_ci	.dpms = r600_hdmi_enable,
1628c2ecf20Sopenharmony_ci};
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic struct radeon_audio_funcs dce32_hdmi_funcs = {
1658c2ecf20Sopenharmony_ci	.get_pin = r600_audio_get_pin,
1668c2ecf20Sopenharmony_ci	.write_sad_regs = dce3_2_afmt_write_sad_regs,
1678c2ecf20Sopenharmony_ci	.write_speaker_allocation = dce3_2_afmt_hdmi_write_speaker_allocation,
1688c2ecf20Sopenharmony_ci	.set_dto = dce3_2_audio_set_dto,
1698c2ecf20Sopenharmony_ci	.update_acr = dce3_2_hdmi_update_acr,
1708c2ecf20Sopenharmony_ci	.set_vbi_packet = r600_set_vbi_packet,
1718c2ecf20Sopenharmony_ci	.set_avi_packet = r600_set_avi_packet,
1728c2ecf20Sopenharmony_ci	.set_audio_packet = dce3_2_set_audio_packet,
1738c2ecf20Sopenharmony_ci	.set_mute = dce3_2_set_mute,
1748c2ecf20Sopenharmony_ci	.mode_set = radeon_audio_hdmi_mode_set,
1758c2ecf20Sopenharmony_ci	.dpms = r600_hdmi_enable,
1768c2ecf20Sopenharmony_ci};
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic struct radeon_audio_funcs dce32_dp_funcs = {
1798c2ecf20Sopenharmony_ci	.get_pin = r600_audio_get_pin,
1808c2ecf20Sopenharmony_ci	.write_sad_regs = dce3_2_afmt_write_sad_regs,
1818c2ecf20Sopenharmony_ci	.write_speaker_allocation = dce3_2_afmt_dp_write_speaker_allocation,
1828c2ecf20Sopenharmony_ci	.set_dto = dce3_2_audio_set_dto,
1838c2ecf20Sopenharmony_ci	.set_avi_packet = r600_set_avi_packet,
1848c2ecf20Sopenharmony_ci	.set_audio_packet = dce3_2_set_audio_packet,
1858c2ecf20Sopenharmony_ci};
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic struct radeon_audio_funcs dce4_hdmi_funcs = {
1888c2ecf20Sopenharmony_ci	.get_pin = r600_audio_get_pin,
1898c2ecf20Sopenharmony_ci	.write_sad_regs = evergreen_hdmi_write_sad_regs,
1908c2ecf20Sopenharmony_ci	.write_speaker_allocation = dce4_afmt_hdmi_write_speaker_allocation,
1918c2ecf20Sopenharmony_ci	.write_latency_fields = dce4_afmt_write_latency_fields,
1928c2ecf20Sopenharmony_ci	.set_dto = dce4_hdmi_audio_set_dto,
1938c2ecf20Sopenharmony_ci	.update_acr = evergreen_hdmi_update_acr,
1948c2ecf20Sopenharmony_ci	.set_vbi_packet = dce4_set_vbi_packet,
1958c2ecf20Sopenharmony_ci	.set_color_depth = dce4_hdmi_set_color_depth,
1968c2ecf20Sopenharmony_ci	.set_avi_packet = evergreen_set_avi_packet,
1978c2ecf20Sopenharmony_ci	.set_audio_packet = dce4_set_audio_packet,
1988c2ecf20Sopenharmony_ci	.set_mute = dce4_set_mute,
1998c2ecf20Sopenharmony_ci	.mode_set = radeon_audio_hdmi_mode_set,
2008c2ecf20Sopenharmony_ci	.dpms = evergreen_hdmi_enable,
2018c2ecf20Sopenharmony_ci};
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic struct radeon_audio_funcs dce4_dp_funcs = {
2048c2ecf20Sopenharmony_ci	.get_pin = r600_audio_get_pin,
2058c2ecf20Sopenharmony_ci	.write_sad_regs = evergreen_hdmi_write_sad_regs,
2068c2ecf20Sopenharmony_ci	.write_speaker_allocation = dce4_afmt_dp_write_speaker_allocation,
2078c2ecf20Sopenharmony_ci	.write_latency_fields = dce4_afmt_write_latency_fields,
2088c2ecf20Sopenharmony_ci	.set_dto = dce4_dp_audio_set_dto,
2098c2ecf20Sopenharmony_ci	.set_avi_packet = evergreen_set_avi_packet,
2108c2ecf20Sopenharmony_ci	.set_audio_packet = dce4_set_audio_packet,
2118c2ecf20Sopenharmony_ci	.mode_set = radeon_audio_dp_mode_set,
2128c2ecf20Sopenharmony_ci	.dpms = evergreen_dp_enable,
2138c2ecf20Sopenharmony_ci};
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic struct radeon_audio_funcs dce6_hdmi_funcs = {
2168c2ecf20Sopenharmony_ci	.select_pin = dce6_afmt_select_pin,
2178c2ecf20Sopenharmony_ci	.get_pin = dce6_audio_get_pin,
2188c2ecf20Sopenharmony_ci	.write_sad_regs = dce6_afmt_write_sad_regs,
2198c2ecf20Sopenharmony_ci	.write_speaker_allocation = dce6_afmt_hdmi_write_speaker_allocation,
2208c2ecf20Sopenharmony_ci	.write_latency_fields = dce6_afmt_write_latency_fields,
2218c2ecf20Sopenharmony_ci	.set_dto = dce6_hdmi_audio_set_dto,
2228c2ecf20Sopenharmony_ci	.update_acr = evergreen_hdmi_update_acr,
2238c2ecf20Sopenharmony_ci	.set_vbi_packet = dce4_set_vbi_packet,
2248c2ecf20Sopenharmony_ci	.set_color_depth = dce4_hdmi_set_color_depth,
2258c2ecf20Sopenharmony_ci	.set_avi_packet = evergreen_set_avi_packet,
2268c2ecf20Sopenharmony_ci	.set_audio_packet = dce4_set_audio_packet,
2278c2ecf20Sopenharmony_ci	.set_mute = dce4_set_mute,
2288c2ecf20Sopenharmony_ci	.mode_set = radeon_audio_hdmi_mode_set,
2298c2ecf20Sopenharmony_ci	.dpms = evergreen_hdmi_enable,
2308c2ecf20Sopenharmony_ci};
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic struct radeon_audio_funcs dce6_dp_funcs = {
2338c2ecf20Sopenharmony_ci	.select_pin = dce6_afmt_select_pin,
2348c2ecf20Sopenharmony_ci	.get_pin = dce6_audio_get_pin,
2358c2ecf20Sopenharmony_ci	.write_sad_regs = dce6_afmt_write_sad_regs,
2368c2ecf20Sopenharmony_ci	.write_speaker_allocation = dce6_afmt_dp_write_speaker_allocation,
2378c2ecf20Sopenharmony_ci	.write_latency_fields = dce6_afmt_write_latency_fields,
2388c2ecf20Sopenharmony_ci	.set_dto = dce6_dp_audio_set_dto,
2398c2ecf20Sopenharmony_ci	.set_avi_packet = evergreen_set_avi_packet,
2408c2ecf20Sopenharmony_ci	.set_audio_packet = dce4_set_audio_packet,
2418c2ecf20Sopenharmony_ci	.mode_set = radeon_audio_dp_mode_set,
2428c2ecf20Sopenharmony_ci	.dpms = evergreen_dp_enable,
2438c2ecf20Sopenharmony_ci};
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic void radeon_audio_enable(struct radeon_device *rdev,
2468c2ecf20Sopenharmony_ci				struct r600_audio_pin *pin, u8 enable_mask)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	struct drm_encoder *encoder;
2498c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder;
2508c2ecf20Sopenharmony_ci	struct radeon_encoder_atom_dig *dig;
2518c2ecf20Sopenharmony_ci	int pin_count = 0;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	if (!pin)
2548c2ecf20Sopenharmony_ci		return;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	if (rdev->mode_info.mode_config_initialized) {
2578c2ecf20Sopenharmony_ci		list_for_each_entry(encoder, &rdev->ddev->mode_config.encoder_list, head) {
2588c2ecf20Sopenharmony_ci			if (radeon_encoder_is_digital(encoder)) {
2598c2ecf20Sopenharmony_ci				radeon_encoder = to_radeon_encoder(encoder);
2608c2ecf20Sopenharmony_ci				dig = radeon_encoder->enc_priv;
2618c2ecf20Sopenharmony_ci				if (dig->pin == pin)
2628c2ecf20Sopenharmony_ci					pin_count++;
2638c2ecf20Sopenharmony_ci			}
2648c2ecf20Sopenharmony_ci		}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci		if ((pin_count > 1) && (enable_mask == 0))
2678c2ecf20Sopenharmony_ci			return;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (rdev->audio.funcs->enable)
2718c2ecf20Sopenharmony_ci		rdev->audio.funcs->enable(rdev, pin, enable_mask);
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic void radeon_audio_interface_init(struct radeon_device *rdev)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	if (ASIC_IS_DCE6(rdev)) {
2778c2ecf20Sopenharmony_ci		rdev->audio.funcs = &dce6_funcs;
2788c2ecf20Sopenharmony_ci		rdev->audio.hdmi_funcs = &dce6_hdmi_funcs;
2798c2ecf20Sopenharmony_ci		rdev->audio.dp_funcs = &dce6_dp_funcs;
2808c2ecf20Sopenharmony_ci	} else if (ASIC_IS_DCE4(rdev)) {
2818c2ecf20Sopenharmony_ci		rdev->audio.funcs = &dce4_funcs;
2828c2ecf20Sopenharmony_ci		rdev->audio.hdmi_funcs = &dce4_hdmi_funcs;
2838c2ecf20Sopenharmony_ci		rdev->audio.dp_funcs = &dce4_dp_funcs;
2848c2ecf20Sopenharmony_ci	} else if (ASIC_IS_DCE32(rdev)) {
2858c2ecf20Sopenharmony_ci		rdev->audio.funcs = &dce32_funcs;
2868c2ecf20Sopenharmony_ci		rdev->audio.hdmi_funcs = &dce32_hdmi_funcs;
2878c2ecf20Sopenharmony_ci		rdev->audio.dp_funcs = &dce32_dp_funcs;
2888c2ecf20Sopenharmony_ci	} else {
2898c2ecf20Sopenharmony_ci		rdev->audio.funcs = &r600_funcs;
2908c2ecf20Sopenharmony_ci		rdev->audio.hdmi_funcs = &r600_hdmi_funcs;
2918c2ecf20Sopenharmony_ci		rdev->audio.dp_funcs = NULL;
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic int radeon_audio_chipset_supported(struct radeon_device *rdev)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ciint radeon_audio_init(struct radeon_device *rdev)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	int i;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (!radeon_audio || !radeon_audio_chipset_supported(rdev))
3058c2ecf20Sopenharmony_ci		return 0;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	rdev->audio.enabled = true;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	if (ASIC_IS_DCE83(rdev))		/* KB: 2 streams, 3 endpoints */
3108c2ecf20Sopenharmony_ci		rdev->audio.num_pins = 3;
3118c2ecf20Sopenharmony_ci	else if (ASIC_IS_DCE81(rdev))	/* KV: 4 streams, 7 endpoints */
3128c2ecf20Sopenharmony_ci		rdev->audio.num_pins = 7;
3138c2ecf20Sopenharmony_ci	else if (ASIC_IS_DCE8(rdev))	/* BN/HW: 6 streams, 7 endpoints */
3148c2ecf20Sopenharmony_ci		rdev->audio.num_pins = 7;
3158c2ecf20Sopenharmony_ci	else if (ASIC_IS_DCE64(rdev))	/* OL: 2 streams, 2 endpoints */
3168c2ecf20Sopenharmony_ci		rdev->audio.num_pins = 2;
3178c2ecf20Sopenharmony_ci	else if (ASIC_IS_DCE61(rdev))	/* TN: 4 streams, 6 endpoints */
3188c2ecf20Sopenharmony_ci		rdev->audio.num_pins = 6;
3198c2ecf20Sopenharmony_ci	else if (ASIC_IS_DCE6(rdev))	/* SI: 6 streams, 6 endpoints */
3208c2ecf20Sopenharmony_ci		rdev->audio.num_pins = 6;
3218c2ecf20Sopenharmony_ci	else
3228c2ecf20Sopenharmony_ci		rdev->audio.num_pins = 1;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->audio.num_pins; i++) {
3258c2ecf20Sopenharmony_ci		rdev->audio.pin[i].channels = -1;
3268c2ecf20Sopenharmony_ci		rdev->audio.pin[i].rate = -1;
3278c2ecf20Sopenharmony_ci		rdev->audio.pin[i].bits_per_sample = -1;
3288c2ecf20Sopenharmony_ci		rdev->audio.pin[i].status_bits = 0;
3298c2ecf20Sopenharmony_ci		rdev->audio.pin[i].category_code = 0;
3308c2ecf20Sopenharmony_ci		rdev->audio.pin[i].connected = false;
3318c2ecf20Sopenharmony_ci		rdev->audio.pin[i].offset = pin_offsets[i];
3328c2ecf20Sopenharmony_ci		rdev->audio.pin[i].id = i;
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	radeon_audio_interface_init(rdev);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	/* disable audio.  it will be set up later */
3388c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->audio.num_pins; i++)
3398c2ecf20Sopenharmony_ci		radeon_audio_enable(rdev, &rdev->audio.pin[i], 0);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	return 0;
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ciu32 radeon_audio_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	if (rdev->audio.funcs->endpoint_rreg)
3478c2ecf20Sopenharmony_ci		return rdev->audio.funcs->endpoint_rreg(rdev, offset, reg);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	return 0;
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_civoid radeon_audio_endpoint_wreg(struct radeon_device *rdev, u32 offset,
3538c2ecf20Sopenharmony_ci	u32 reg, u32 v)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	if (rdev->audio.funcs->endpoint_wreg)
3568c2ecf20Sopenharmony_ci		rdev->audio.funcs->endpoint_wreg(rdev, offset, reg, v);
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic void radeon_audio_write_sad_regs(struct drm_encoder *encoder)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
3628c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
3638c2ecf20Sopenharmony_ci	struct cea_sad *sads;
3648c2ecf20Sopenharmony_ci	int sad_count;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (!connector)
3678c2ecf20Sopenharmony_ci		return;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads);
3708c2ecf20Sopenharmony_ci	if (sad_count < 0)
3718c2ecf20Sopenharmony_ci		DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
3728c2ecf20Sopenharmony_ci	if (sad_count <= 0)
3738c2ecf20Sopenharmony_ci		return;
3748c2ecf20Sopenharmony_ci	BUG_ON(!sads);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->write_sad_regs)
3778c2ecf20Sopenharmony_ci		radeon_encoder->audio->write_sad_regs(encoder, sads, sad_count);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	kfree(sads);
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic void radeon_audio_write_speaker_allocation(struct drm_encoder *encoder)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
3858c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
3868c2ecf20Sopenharmony_ci	u8 *sadb = NULL;
3878c2ecf20Sopenharmony_ci	int sad_count;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (!connector)
3908c2ecf20Sopenharmony_ci		return;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector),
3938c2ecf20Sopenharmony_ci						   &sadb);
3948c2ecf20Sopenharmony_ci	if (sad_count < 0) {
3958c2ecf20Sopenharmony_ci		DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n",
3968c2ecf20Sopenharmony_ci			  sad_count);
3978c2ecf20Sopenharmony_ci		sad_count = 0;
3988c2ecf20Sopenharmony_ci	}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->write_speaker_allocation)
4018c2ecf20Sopenharmony_ci		radeon_encoder->audio->write_speaker_allocation(encoder, sadb, sad_count);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	kfree(sadb);
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_cistatic void radeon_audio_write_latency_fields(struct drm_encoder *encoder,
4078c2ecf20Sopenharmony_ci					      struct drm_display_mode *mode)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
4108c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if (!connector)
4138c2ecf20Sopenharmony_ci		return;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->write_latency_fields)
4168c2ecf20Sopenharmony_ci		radeon_encoder->audio->write_latency_fields(encoder, connector, mode);
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistruct r600_audio_pin* radeon_audio_get_pin(struct drm_encoder *encoder)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	struct radeon_device *rdev = encoder->dev->dev_private;
4228c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->get_pin)
4258c2ecf20Sopenharmony_ci		return radeon_encoder->audio->get_pin(rdev);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	return NULL;
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic void radeon_audio_select_pin(struct drm_encoder *encoder)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->select_pin)
4358c2ecf20Sopenharmony_ci		radeon_encoder->audio->select_pin(encoder);
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_civoid radeon_audio_detect(struct drm_connector *connector,
4398c2ecf20Sopenharmony_ci			 struct drm_encoder *encoder,
4408c2ecf20Sopenharmony_ci			 enum drm_connector_status status)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
4438c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
4448c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
4458c2ecf20Sopenharmony_ci	struct radeon_encoder_atom_dig *dig;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (!radeon_audio_chipset_supported(rdev))
4488c2ecf20Sopenharmony_ci		return;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	if (!radeon_encoder_is_digital(encoder))
4518c2ecf20Sopenharmony_ci		return;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	dig = radeon_encoder->enc_priv;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	if (status == connector_status_connected) {
4568c2ecf20Sopenharmony_ci		if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
4578c2ecf20Sopenharmony_ci			struct radeon_connector *radeon_connector = to_radeon_connector(connector);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci			if (radeon_dp_getsinktype(radeon_connector) ==
4608c2ecf20Sopenharmony_ci			    CONNECTOR_OBJECT_ID_DISPLAYPORT)
4618c2ecf20Sopenharmony_ci				radeon_encoder->audio = rdev->audio.dp_funcs;
4628c2ecf20Sopenharmony_ci			else
4638c2ecf20Sopenharmony_ci				radeon_encoder->audio = rdev->audio.hdmi_funcs;
4648c2ecf20Sopenharmony_ci		} else {
4658c2ecf20Sopenharmony_ci			radeon_encoder->audio = rdev->audio.hdmi_funcs;
4668c2ecf20Sopenharmony_ci		}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci		if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
4698c2ecf20Sopenharmony_ci			if (!dig->pin)
4708c2ecf20Sopenharmony_ci				dig->pin = radeon_audio_get_pin(encoder);
4718c2ecf20Sopenharmony_ci			radeon_audio_enable(rdev, dig->pin, 0xf);
4728c2ecf20Sopenharmony_ci		} else {
4738c2ecf20Sopenharmony_ci			radeon_audio_enable(rdev, dig->pin, 0);
4748c2ecf20Sopenharmony_ci			dig->pin = NULL;
4758c2ecf20Sopenharmony_ci		}
4768c2ecf20Sopenharmony_ci	} else {
4778c2ecf20Sopenharmony_ci		radeon_audio_enable(rdev, dig->pin, 0);
4788c2ecf20Sopenharmony_ci		dig->pin = NULL;
4798c2ecf20Sopenharmony_ci	}
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_civoid radeon_audio_fini(struct radeon_device *rdev)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	int i;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	if (!rdev->audio.enabled)
4878c2ecf20Sopenharmony_ci		return;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	for (i = 0; i < rdev->audio.num_pins; i++)
4908c2ecf20Sopenharmony_ci		radeon_audio_enable(rdev, &rdev->audio.pin[i], 0);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	rdev->audio.enabled = false;
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic void radeon_audio_set_dto(struct drm_encoder *encoder, unsigned int clock)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	struct radeon_device *rdev = encoder->dev->dev_private;
4988c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
4998c2ecf20Sopenharmony_ci	struct radeon_crtc *crtc = to_radeon_crtc(encoder->crtc);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->set_dto)
5028c2ecf20Sopenharmony_ci		radeon_encoder->audio->set_dto(rdev, crtc, clock);
5038c2ecf20Sopenharmony_ci}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_cistatic int radeon_audio_set_avi_packet(struct drm_encoder *encoder,
5068c2ecf20Sopenharmony_ci				       struct drm_display_mode *mode)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	struct radeon_device *rdev = encoder->dev->dev_private;
5098c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
5108c2ecf20Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
5118c2ecf20Sopenharmony_ci	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
5128c2ecf20Sopenharmony_ci	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
5138c2ecf20Sopenharmony_ci	struct hdmi_avi_infoframe frame;
5148c2ecf20Sopenharmony_ci	int err;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	if (!connector)
5178c2ecf20Sopenharmony_ci		return -EINVAL;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	err = drm_hdmi_avi_infoframe_from_display_mode(&frame, connector, mode);
5208c2ecf20Sopenharmony_ci	if (err < 0) {
5218c2ecf20Sopenharmony_ci		DRM_ERROR("failed to setup AVI infoframe: %d\n", err);
5228c2ecf20Sopenharmony_ci		return err;
5238c2ecf20Sopenharmony_ci	}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	if (radeon_encoder->output_csc != RADEON_OUTPUT_CSC_BYPASS) {
5268c2ecf20Sopenharmony_ci		drm_hdmi_avi_infoframe_quant_range(&frame, connector, mode,
5278c2ecf20Sopenharmony_ci						   radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB ?
5288c2ecf20Sopenharmony_ci						   HDMI_QUANTIZATION_RANGE_LIMITED :
5298c2ecf20Sopenharmony_ci						   HDMI_QUANTIZATION_RANGE_FULL);
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
5338c2ecf20Sopenharmony_ci	if (err < 0) {
5348c2ecf20Sopenharmony_ci		DRM_ERROR("failed to pack AVI infoframe: %d\n", err);
5358c2ecf20Sopenharmony_ci		return err;
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	if (dig && dig->afmt && radeon_encoder->audio &&
5398c2ecf20Sopenharmony_ci	    radeon_encoder->audio->set_avi_packet)
5408c2ecf20Sopenharmony_ci		radeon_encoder->audio->set_avi_packet(rdev, dig->afmt->offset,
5418c2ecf20Sopenharmony_ci			buffer, sizeof(buffer));
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	return 0;
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci/*
5478c2ecf20Sopenharmony_ci * calculate CTS and N values if they are not found in the table
5488c2ecf20Sopenharmony_ci */
5498c2ecf20Sopenharmony_cistatic void radeon_audio_calc_cts(unsigned int clock, int *CTS, int *N, int freq)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	int n, cts;
5528c2ecf20Sopenharmony_ci	unsigned long div, mul;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	/* Safe, but overly large values */
5558c2ecf20Sopenharmony_ci	n = 128 * freq;
5568c2ecf20Sopenharmony_ci	cts = clock * 1000;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	/* Smallest valid fraction */
5598c2ecf20Sopenharmony_ci	div = gcd(n, cts);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	n /= div;
5628c2ecf20Sopenharmony_ci	cts /= div;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	/*
5658c2ecf20Sopenharmony_ci	 * The optimal N is 128*freq/1000. Calculate the closest larger
5668c2ecf20Sopenharmony_ci	 * value that doesn't truncate any bits.
5678c2ecf20Sopenharmony_ci	 */
5688c2ecf20Sopenharmony_ci	mul = ((128*freq/1000) + (n-1))/n;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	n *= mul;
5718c2ecf20Sopenharmony_ci	cts *= mul;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	/* Check that we are in spec (not always possible) */
5748c2ecf20Sopenharmony_ci	if (n < (128*freq/1500))
5758c2ecf20Sopenharmony_ci		pr_warn("Calculated ACR N value is too small. You may experience audio problems.\n");
5768c2ecf20Sopenharmony_ci	if (n > (128*freq/300))
5778c2ecf20Sopenharmony_ci		pr_warn("Calculated ACR N value is too large. You may experience audio problems.\n");
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	*N = n;
5808c2ecf20Sopenharmony_ci	*CTS = cts;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n",
5838c2ecf20Sopenharmony_ci		*N, *CTS, freq);
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic const struct radeon_hdmi_acr* radeon_audio_acr(unsigned int clock)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	static struct radeon_hdmi_acr res;
5898c2ecf20Sopenharmony_ci	u8 i;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	static const struct radeon_hdmi_acr hdmi_predefined_acr[] = {
5928c2ecf20Sopenharmony_ci		/*       32kHz    44.1kHz   48kHz    */
5938c2ecf20Sopenharmony_ci		/* Clock      N     CTS      N     CTS      N     CTS */
5948c2ecf20Sopenharmony_ci		{  25175,  4096,  25175, 28224, 125875,  6144,  25175 }, /*  25,20/1.001 MHz */
5958c2ecf20Sopenharmony_ci		{  25200,  4096,  25200,  6272,  28000,  6144,  25200 }, /*  25.20       MHz */
5968c2ecf20Sopenharmony_ci		{  27000,  4096,  27000,  6272,  30000,  6144,  27000 }, /*  27.00       MHz */
5978c2ecf20Sopenharmony_ci		{  27027,  4096,  27027,  6272,  30030,  6144,  27027 }, /*  27.00*1.001 MHz */
5988c2ecf20Sopenharmony_ci		{  54000,  4096,  54000,  6272,  60000,  6144,  54000 }, /*  54.00       MHz */
5998c2ecf20Sopenharmony_ci		{  54054,  4096,  54054,  6272,  60060,  6144,  54054 }, /*  54.00*1.001 MHz */
6008c2ecf20Sopenharmony_ci		{  74176,  4096,  74176,  5733,  75335,  6144,  74176 }, /*  74.25/1.001 MHz */
6018c2ecf20Sopenharmony_ci		{  74250,  4096,  74250,  6272,  82500,  6144,  74250 }, /*  74.25       MHz */
6028c2ecf20Sopenharmony_ci		{ 148352,  4096, 148352,  5733, 150670,  6144, 148352 }, /* 148.50/1.001 MHz */
6038c2ecf20Sopenharmony_ci		{ 148500,  4096, 148500,  6272, 165000,  6144, 148500 }, /* 148.50       MHz */
6048c2ecf20Sopenharmony_ci	};
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	/* Precalculated values for common clocks */
6078c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(hdmi_predefined_acr); i++)
6088c2ecf20Sopenharmony_ci		if (hdmi_predefined_acr[i].clock == clock)
6098c2ecf20Sopenharmony_ci			return &hdmi_predefined_acr[i];
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	/* And odd clocks get manually calculated */
6128c2ecf20Sopenharmony_ci	radeon_audio_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000);
6138c2ecf20Sopenharmony_ci	radeon_audio_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100);
6148c2ecf20Sopenharmony_ci	radeon_audio_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	return &res;
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci/*
6208c2ecf20Sopenharmony_ci * update the N and CTS parameters for a given pixel clock rate
6218c2ecf20Sopenharmony_ci */
6228c2ecf20Sopenharmony_cistatic void radeon_audio_update_acr(struct drm_encoder *encoder, unsigned int clock)
6238c2ecf20Sopenharmony_ci{
6248c2ecf20Sopenharmony_ci	const struct radeon_hdmi_acr *acr = radeon_audio_acr(clock);
6258c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
6268c2ecf20Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	if (!dig || !dig->afmt)
6298c2ecf20Sopenharmony_ci		return;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->update_acr)
6328c2ecf20Sopenharmony_ci		radeon_encoder->audio->update_acr(encoder, dig->afmt->offset, acr);
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cistatic void radeon_audio_set_vbi_packet(struct drm_encoder *encoder)
6368c2ecf20Sopenharmony_ci{
6378c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
6388c2ecf20Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	if (!dig || !dig->afmt)
6418c2ecf20Sopenharmony_ci		return;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->set_vbi_packet)
6448c2ecf20Sopenharmony_ci		radeon_encoder->audio->set_vbi_packet(encoder, dig->afmt->offset);
6458c2ecf20Sopenharmony_ci}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_cistatic void radeon_hdmi_set_color_depth(struct drm_encoder *encoder)
6488c2ecf20Sopenharmony_ci{
6498c2ecf20Sopenharmony_ci	int bpc = 8;
6508c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
6518c2ecf20Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	if (!dig || !dig->afmt)
6548c2ecf20Sopenharmony_ci		return;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	if (encoder->crtc) {
6578c2ecf20Sopenharmony_ci		struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
6588c2ecf20Sopenharmony_ci		bpc = radeon_crtc->bpc;
6598c2ecf20Sopenharmony_ci	}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->set_color_depth)
6628c2ecf20Sopenharmony_ci		radeon_encoder->audio->set_color_depth(encoder, dig->afmt->offset, bpc);
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_cistatic void radeon_audio_set_audio_packet(struct drm_encoder *encoder)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
6688c2ecf20Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	if (!dig || !dig->afmt)
6718c2ecf20Sopenharmony_ci		return;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->set_audio_packet)
6748c2ecf20Sopenharmony_ci		radeon_encoder->audio->set_audio_packet(encoder, dig->afmt->offset);
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_cistatic void radeon_audio_set_mute(struct drm_encoder *encoder, bool mute)
6788c2ecf20Sopenharmony_ci{
6798c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
6808c2ecf20Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	if (!dig || !dig->afmt)
6838c2ecf20Sopenharmony_ci		return;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->set_mute)
6868c2ecf20Sopenharmony_ci		radeon_encoder->audio->set_mute(encoder, dig->afmt->offset, mute);
6878c2ecf20Sopenharmony_ci}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci/*
6908c2ecf20Sopenharmony_ci * update the info frames with the data from the current display mode
6918c2ecf20Sopenharmony_ci */
6928c2ecf20Sopenharmony_cistatic void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
6938c2ecf20Sopenharmony_ci				       struct drm_display_mode *mode)
6948c2ecf20Sopenharmony_ci{
6958c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
6968c2ecf20Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
6978c2ecf20Sopenharmony_ci	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	if (!dig || !dig->afmt)
7008c2ecf20Sopenharmony_ci		return;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	if (!connector)
7038c2ecf20Sopenharmony_ci		return;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
7068c2ecf20Sopenharmony_ci		radeon_audio_set_mute(encoder, true);
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci		radeon_audio_write_speaker_allocation(encoder);
7098c2ecf20Sopenharmony_ci		radeon_audio_write_sad_regs(encoder);
7108c2ecf20Sopenharmony_ci		radeon_audio_write_latency_fields(encoder, mode);
7118c2ecf20Sopenharmony_ci		radeon_audio_set_dto(encoder, mode->clock);
7128c2ecf20Sopenharmony_ci		radeon_audio_set_vbi_packet(encoder);
7138c2ecf20Sopenharmony_ci		radeon_hdmi_set_color_depth(encoder);
7148c2ecf20Sopenharmony_ci		radeon_audio_update_acr(encoder, mode->clock);
7158c2ecf20Sopenharmony_ci		radeon_audio_set_audio_packet(encoder);
7168c2ecf20Sopenharmony_ci		radeon_audio_select_pin(encoder);
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci		if (radeon_audio_set_avi_packet(encoder, mode) < 0)
7198c2ecf20Sopenharmony_ci			return;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci		radeon_audio_set_mute(encoder, false);
7228c2ecf20Sopenharmony_ci	} else {
7238c2ecf20Sopenharmony_ci		radeon_hdmi_set_color_depth(encoder);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci		if (radeon_audio_set_avi_packet(encoder, mode) < 0)
7268c2ecf20Sopenharmony_ci			return;
7278c2ecf20Sopenharmony_ci	}
7288c2ecf20Sopenharmony_ci}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_cistatic void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
7318c2ecf20Sopenharmony_ci				     struct drm_display_mode *mode)
7328c2ecf20Sopenharmony_ci{
7338c2ecf20Sopenharmony_ci	struct drm_device *dev = encoder->dev;
7348c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
7358c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
7368c2ecf20Sopenharmony_ci	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
7378c2ecf20Sopenharmony_ci	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	if (!dig || !dig->afmt)
7408c2ecf20Sopenharmony_ci		return;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	if (!connector)
7438c2ecf20Sopenharmony_ci		return;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	if (drm_detect_monitor_audio(radeon_connector_edid(connector))) {
7468c2ecf20Sopenharmony_ci		radeon_audio_write_speaker_allocation(encoder);
7478c2ecf20Sopenharmony_ci		radeon_audio_write_sad_regs(encoder);
7488c2ecf20Sopenharmony_ci		radeon_audio_write_latency_fields(encoder, mode);
7498c2ecf20Sopenharmony_ci		radeon_audio_set_dto(encoder, rdev->clock.vco_freq * 10);
7508c2ecf20Sopenharmony_ci		radeon_audio_set_audio_packet(encoder);
7518c2ecf20Sopenharmony_ci		radeon_audio_select_pin(encoder);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci		if (radeon_audio_set_avi_packet(encoder, mode) < 0)
7548c2ecf20Sopenharmony_ci			return;
7558c2ecf20Sopenharmony_ci	}
7568c2ecf20Sopenharmony_ci}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_civoid radeon_audio_mode_set(struct drm_encoder *encoder,
7598c2ecf20Sopenharmony_ci			   struct drm_display_mode *mode)
7608c2ecf20Sopenharmony_ci{
7618c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->mode_set)
7648c2ecf20Sopenharmony_ci		radeon_encoder->audio->mode_set(encoder, mode);
7658c2ecf20Sopenharmony_ci}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_civoid radeon_audio_dpms(struct drm_encoder *encoder, int mode)
7688c2ecf20Sopenharmony_ci{
7698c2ecf20Sopenharmony_ci	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	if (radeon_encoder->audio && radeon_encoder->audio->dpms)
7728c2ecf20Sopenharmony_ci		radeon_encoder->audio->dpms(encoder, mode == DRM_MODE_DPMS_ON);
7738c2ecf20Sopenharmony_ci}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ciunsigned int radeon_audio_decode_dfs_div(unsigned int div)
7768c2ecf20Sopenharmony_ci{
7778c2ecf20Sopenharmony_ci	if (div >= 8 && div < 64)
7788c2ecf20Sopenharmony_ci		return (div - 8) * 25 + 200;
7798c2ecf20Sopenharmony_ci	else if (div >= 64 && div < 96)
7808c2ecf20Sopenharmony_ci		return (div - 64) * 50 + 1600;
7818c2ecf20Sopenharmony_ci	else if (div >= 96 && div < 128)
7828c2ecf20Sopenharmony_ci		return (div - 96) * 100 + 3200;
7838c2ecf20Sopenharmony_ci	else
7848c2ecf20Sopenharmony_ci		return 0;
7858c2ecf20Sopenharmony_ci}
786