mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-23 22:27:01 -04:00
drm/amd/display: Extract audio code to amdgpu_dm_audio
Move audio component, init/fini, ELD notification, fill_audio_info, and commit_audio functions from amdgpu_dm.c into a dedicated amdgpu_dm_audio.c file with its own header. No functional change intended. Assisted-by: Copilot:Claude-Opus-4.6 Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com> Signed-off-by: Alex Hung <alex.hung@amd.com> Signed-off-by: Chenyu Chen <chen-yu.chen@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
@@ -42,7 +42,8 @@ AMDGPUDM = \
|
||||
amdgpu_dm_wb.o \
|
||||
amdgpu_dm_colorop.o \
|
||||
amdgpu_dm_ism.o \
|
||||
amdgpu_dm_backlight.o
|
||||
amdgpu_dm_backlight.o \
|
||||
amdgpu_dm_audio.o
|
||||
|
||||
ifdef CONFIG_DRM_AMD_DC_FP
|
||||
AMDGPUDM += dc_fpu.o
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
#include "amdgpu_dm_psr.h"
|
||||
#include "amdgpu_dm_replay.h"
|
||||
#include "amdgpu_dm_backlight.h"
|
||||
#include "amdgpu_dm_audio.h"
|
||||
|
||||
#include "ivsrcid/ivsrcid_vislands30.h"
|
||||
|
||||
@@ -95,7 +96,6 @@
|
||||
#include <drm/drm_mode.h>
|
||||
#include <drm/drm_utils.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
#include <drm/drm_audio_component.h>
|
||||
#include <drm/drm_colorop.h>
|
||||
#include <drm/drm_gem_atomic_helper.h>
|
||||
|
||||
@@ -1110,144 +1110,6 @@ static void amdgpu_dm_fbc_init(struct drm_connector *connector)
|
||||
|
||||
}
|
||||
|
||||
static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port,
|
||||
int pipe, bool *enabled,
|
||||
unsigned char *buf, int max_bytes)
|
||||
{
|
||||
struct drm_device *dev = dev_get_drvdata(kdev);
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
int ret = 0;
|
||||
|
||||
*enabled = false;
|
||||
|
||||
mutex_lock(&adev->dm.audio_lock);
|
||||
|
||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||
drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
|
||||
continue;
|
||||
|
||||
aconnector = to_amdgpu_dm_connector(connector);
|
||||
if (aconnector->audio_inst != port)
|
||||
continue;
|
||||
|
||||
*enabled = true;
|
||||
mutex_lock(&connector->eld_mutex);
|
||||
ret = drm_eld_size(connector->eld);
|
||||
memcpy(buf, connector->eld, min(max_bytes, ret));
|
||||
mutex_unlock(&connector->eld_mutex);
|
||||
|
||||
break;
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
|
||||
mutex_unlock(&adev->dm.audio_lock);
|
||||
|
||||
drm_dbg_kms(adev_to_drm(adev), "Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_audio_component_ops amdgpu_dm_audio_component_ops = {
|
||||
.get_eld = amdgpu_dm_audio_component_get_eld,
|
||||
};
|
||||
|
||||
static int amdgpu_dm_audio_component_bind(struct device *kdev,
|
||||
struct device *hda_kdev, void *data)
|
||||
{
|
||||
struct drm_device *dev = dev_get_drvdata(kdev);
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct drm_audio_component *acomp = data;
|
||||
|
||||
acomp->ops = &amdgpu_dm_audio_component_ops;
|
||||
acomp->dev = kdev;
|
||||
adev->dm.audio_component = acomp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amdgpu_dm_audio_component_unbind(struct device *kdev,
|
||||
struct device *hda_kdev, void *data)
|
||||
{
|
||||
struct amdgpu_device *adev = drm_to_adev(dev_get_drvdata(kdev));
|
||||
struct drm_audio_component *acomp = data;
|
||||
|
||||
acomp->ops = NULL;
|
||||
acomp->dev = NULL;
|
||||
adev->dm.audio_component = NULL;
|
||||
}
|
||||
|
||||
static const struct component_ops amdgpu_dm_audio_component_bind_ops = {
|
||||
.bind = amdgpu_dm_audio_component_bind,
|
||||
.unbind = amdgpu_dm_audio_component_unbind,
|
||||
};
|
||||
|
||||
static int amdgpu_dm_audio_init(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
if (!amdgpu_audio)
|
||||
return 0;
|
||||
|
||||
adev->mode_info.audio.enabled = true;
|
||||
|
||||
adev->mode_info.audio.num_pins = adev->dm.dc->res_pool->audio_count;
|
||||
|
||||
for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
|
||||
adev->mode_info.audio.pin[i].channels = -1;
|
||||
adev->mode_info.audio.pin[i].rate = -1;
|
||||
adev->mode_info.audio.pin[i].bits_per_sample = -1;
|
||||
adev->mode_info.audio.pin[i].status_bits = 0;
|
||||
adev->mode_info.audio.pin[i].category_code = 0;
|
||||
adev->mode_info.audio.pin[i].connected = false;
|
||||
adev->mode_info.audio.pin[i].id =
|
||||
adev->dm.dc->res_pool->audios[i]->inst;
|
||||
adev->mode_info.audio.pin[i].offset = 0;
|
||||
}
|
||||
|
||||
ret = component_add(adev->dev, &amdgpu_dm_audio_component_bind_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
adev->dm.audio_registered = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amdgpu_dm_audio_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
if (!amdgpu_audio)
|
||||
return;
|
||||
|
||||
if (!adev->mode_info.audio.enabled)
|
||||
return;
|
||||
|
||||
if (adev->dm.audio_registered) {
|
||||
component_del(adev->dev, &amdgpu_dm_audio_component_bind_ops);
|
||||
adev->dm.audio_registered = false;
|
||||
}
|
||||
|
||||
/* TODO: Disable audio? */
|
||||
|
||||
adev->mode_info.audio.enabled = false;
|
||||
}
|
||||
|
||||
static void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin)
|
||||
{
|
||||
struct drm_audio_component *acomp = adev->dm.audio_component;
|
||||
|
||||
if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
|
||||
drm_dbg_kms(adev_to_drm(adev), "Notify ELD: %d\n", pin);
|
||||
|
||||
acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
|
||||
pin, -1);
|
||||
}
|
||||
}
|
||||
|
||||
static int dm_dmub_hw_init(struct amdgpu_device *adev)
|
||||
{
|
||||
const struct dmcub_firmware_header_v1_0 *hdr;
|
||||
@@ -6530,51 +6392,6 @@ static void fill_stream_properties_from_drm_display_mode(
|
||||
stream->content_type = get_output_content_type(connector_state);
|
||||
}
|
||||
|
||||
static void fill_audio_info(struct audio_info *audio_info,
|
||||
const struct drm_connector *drm_connector,
|
||||
const struct dc_sink *dc_sink)
|
||||
{
|
||||
int i = 0;
|
||||
int cea_revision = 0;
|
||||
const struct dc_edid_caps *edid_caps = &dc_sink->edid_caps;
|
||||
|
||||
audio_info->manufacture_id = edid_caps->manufacturer_id;
|
||||
audio_info->product_id = edid_caps->product_id;
|
||||
|
||||
cea_revision = drm_connector->display_info.cea_rev;
|
||||
|
||||
strscpy(audio_info->display_name,
|
||||
edid_caps->display_name,
|
||||
AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
|
||||
|
||||
if (cea_revision >= 3) {
|
||||
audio_info->mode_count = edid_caps->audio_mode_count;
|
||||
|
||||
for (i = 0; i < audio_info->mode_count; ++i) {
|
||||
audio_info->modes[i].format_code =
|
||||
(enum audio_format_code)
|
||||
(edid_caps->audio_modes[i].format_code);
|
||||
audio_info->modes[i].channel_count =
|
||||
edid_caps->audio_modes[i].channel_count;
|
||||
audio_info->modes[i].sample_rates.all =
|
||||
edid_caps->audio_modes[i].sample_rate;
|
||||
audio_info->modes[i].sample_size =
|
||||
edid_caps->audio_modes[i].sample_size;
|
||||
}
|
||||
}
|
||||
|
||||
audio_info->flags.all = edid_caps->speaker_flags;
|
||||
|
||||
/* TODO: We only check for the progressive mode, check for interlace mode too */
|
||||
if (drm_connector->latency_present[0]) {
|
||||
audio_info->video_latency = drm_connector->video_latency[0];
|
||||
audio_info->audio_latency = drm_connector->audio_latency[0];
|
||||
}
|
||||
|
||||
/* TODO: For DP, video and audio latency should be calculated from DPCD caps */
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
copy_crtc_timing_for_drm_display_mode(const struct drm_display_mode *src_mode,
|
||||
struct drm_display_mode *dst_mode)
|
||||
@@ -7176,7 +6993,7 @@ create_stream_for_sink(struct drm_connector *connector,
|
||||
|
||||
update_stream_scaling_settings(dev, &mode, dm_state, stream);
|
||||
|
||||
fill_audio_info(
|
||||
amdgpu_dm_fill_audio_info(
|
||||
&stream->audio_info,
|
||||
connector,
|
||||
sink);
|
||||
@@ -9984,87 +9801,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
|
||||
kfree(bundle);
|
||||
}
|
||||
|
||||
static void amdgpu_dm_commit_audio(struct drm_device *dev,
|
||||
struct drm_atomic_commit *state)
|
||||
{
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_state *old_con_state, *new_con_state;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
struct dm_crtc_state *new_dm_crtc_state;
|
||||
const struct dc_stream_status *status;
|
||||
int i, inst;
|
||||
|
||||
/* Notify device removals. */
|
||||
for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
|
||||
if (old_con_state->crtc != new_con_state->crtc) {
|
||||
/* CRTC changes require notification. */
|
||||
goto notify;
|
||||
}
|
||||
|
||||
if (!new_con_state->crtc)
|
||||
continue;
|
||||
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(
|
||||
state, new_con_state->crtc);
|
||||
|
||||
if (!new_crtc_state)
|
||||
continue;
|
||||
|
||||
if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
|
||||
continue;
|
||||
|
||||
notify:
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
|
||||
continue;
|
||||
|
||||
aconnector = to_amdgpu_dm_connector(connector);
|
||||
|
||||
mutex_lock(&adev->dm.audio_lock);
|
||||
inst = aconnector->audio_inst;
|
||||
aconnector->audio_inst = -1;
|
||||
mutex_unlock(&adev->dm.audio_lock);
|
||||
|
||||
amdgpu_dm_audio_eld_notify(adev, inst);
|
||||
}
|
||||
|
||||
/* Notify audio device additions. */
|
||||
for_each_new_connector_in_state(state, connector, new_con_state, i) {
|
||||
if (!new_con_state->crtc)
|
||||
continue;
|
||||
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(
|
||||
state, new_con_state->crtc);
|
||||
|
||||
if (!new_crtc_state)
|
||||
continue;
|
||||
|
||||
if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
|
||||
continue;
|
||||
|
||||
new_dm_crtc_state = to_dm_crtc_state(new_crtc_state);
|
||||
if (!new_dm_crtc_state->stream)
|
||||
continue;
|
||||
|
||||
status = dc_stream_get_status(new_dm_crtc_state->stream);
|
||||
if (!status)
|
||||
continue;
|
||||
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
|
||||
continue;
|
||||
|
||||
aconnector = to_amdgpu_dm_connector(connector);
|
||||
|
||||
mutex_lock(&adev->dm.audio_lock);
|
||||
inst = status->audio_inst;
|
||||
aconnector->audio_inst = inst;
|
||||
mutex_unlock(&adev->dm.audio_lock);
|
||||
|
||||
amdgpu_dm_audio_eld_notify(adev, inst);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* amdgpu_dm_crtc_copy_transient_flags - copy mirrored flags from DRM to DC
|
||||
* @crtc_state: the DRM CRTC state
|
||||
|
||||
302
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.c
Normal file
302
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.c
Normal file
@@ -0,0 +1,302 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright 2026 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: AMD
|
||||
*/
|
||||
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_dm.h"
|
||||
#include "amdgpu_dm_audio.h"
|
||||
#include "dc.h"
|
||||
|
||||
#include <linux/component.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_audio_component.h>
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_eld.h>
|
||||
|
||||
#include "dc/inc/core_types.h"
|
||||
|
||||
static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port,
|
||||
int pipe, bool *enabled,
|
||||
unsigned char *buf, int max_bytes)
|
||||
{
|
||||
struct drm_device *dev = dev_get_drvdata(kdev);
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
int ret = 0;
|
||||
|
||||
*enabled = false;
|
||||
|
||||
mutex_lock(&adev->dm.audio_lock);
|
||||
|
||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||
drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
|
||||
continue;
|
||||
|
||||
aconnector = to_amdgpu_dm_connector(connector);
|
||||
if (aconnector->audio_inst != port)
|
||||
continue;
|
||||
|
||||
*enabled = true;
|
||||
mutex_lock(&connector->eld_mutex);
|
||||
ret = drm_eld_size(connector->eld);
|
||||
memcpy(buf, connector->eld, min(max_bytes, ret));
|
||||
mutex_unlock(&connector->eld_mutex);
|
||||
|
||||
break;
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
|
||||
mutex_unlock(&adev->dm.audio_lock);
|
||||
|
||||
drm_dbg_kms(adev_to_drm(adev), "Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_audio_component_ops amdgpu_dm_audio_component_ops = {
|
||||
.get_eld = amdgpu_dm_audio_component_get_eld,
|
||||
};
|
||||
|
||||
static int amdgpu_dm_audio_component_bind(struct device *kdev,
|
||||
struct device *hda_kdev, void *data)
|
||||
{
|
||||
struct drm_device *dev = dev_get_drvdata(kdev);
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct drm_audio_component *acomp = data;
|
||||
|
||||
acomp->ops = &amdgpu_dm_audio_component_ops;
|
||||
acomp->dev = kdev;
|
||||
adev->dm.audio_component = acomp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amdgpu_dm_audio_component_unbind(struct device *kdev,
|
||||
struct device *hda_kdev, void *data)
|
||||
{
|
||||
struct amdgpu_device *adev = drm_to_adev(dev_get_drvdata(kdev));
|
||||
struct drm_audio_component *acomp = data;
|
||||
|
||||
acomp->ops = NULL;
|
||||
acomp->dev = NULL;
|
||||
adev->dm.audio_component = NULL;
|
||||
}
|
||||
|
||||
static const struct component_ops amdgpu_dm_audio_component_bind_ops = {
|
||||
.bind = amdgpu_dm_audio_component_bind,
|
||||
.unbind = amdgpu_dm_audio_component_unbind,
|
||||
};
|
||||
|
||||
int amdgpu_dm_audio_init(struct amdgpu_device *adev)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
if (!amdgpu_audio)
|
||||
return 0;
|
||||
|
||||
adev->mode_info.audio.enabled = true;
|
||||
|
||||
adev->mode_info.audio.num_pins = adev->dm.dc->res_pool->audio_count;
|
||||
|
||||
for (i = 0; i < adev->mode_info.audio.num_pins; i++) {
|
||||
adev->mode_info.audio.pin[i].channels = -1;
|
||||
adev->mode_info.audio.pin[i].rate = -1;
|
||||
adev->mode_info.audio.pin[i].bits_per_sample = -1;
|
||||
adev->mode_info.audio.pin[i].status_bits = 0;
|
||||
adev->mode_info.audio.pin[i].category_code = 0;
|
||||
adev->mode_info.audio.pin[i].connected = false;
|
||||
adev->mode_info.audio.pin[i].id =
|
||||
adev->dm.dc->res_pool->audios[i]->inst;
|
||||
adev->mode_info.audio.pin[i].offset = 0;
|
||||
}
|
||||
|
||||
ret = component_add(adev->dev, &amdgpu_dm_audio_component_bind_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
adev->dm.audio_registered = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void amdgpu_dm_audio_fini(struct amdgpu_device *adev)
|
||||
{
|
||||
if (!amdgpu_audio)
|
||||
return;
|
||||
|
||||
if (!adev->mode_info.audio.enabled)
|
||||
return;
|
||||
|
||||
if (adev->dm.audio_registered) {
|
||||
component_del(adev->dev, &amdgpu_dm_audio_component_bind_ops);
|
||||
adev->dm.audio_registered = false;
|
||||
}
|
||||
|
||||
/* TODO: Disable audio? */
|
||||
|
||||
adev->mode_info.audio.enabled = false;
|
||||
}
|
||||
|
||||
static void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin)
|
||||
{
|
||||
struct drm_audio_component *acomp = adev->dm.audio_component;
|
||||
|
||||
if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
|
||||
drm_dbg_kms(adev_to_drm(adev), "Notify ELD: %d\n", pin);
|
||||
|
||||
acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
|
||||
pin, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void amdgpu_dm_fill_audio_info(struct audio_info *audio_info,
|
||||
const struct drm_connector *drm_connector,
|
||||
const struct dc_sink *dc_sink)
|
||||
{
|
||||
int i = 0;
|
||||
int cea_revision = 0;
|
||||
const struct dc_edid_caps *edid_caps = &dc_sink->edid_caps;
|
||||
|
||||
audio_info->manufacture_id = edid_caps->manufacturer_id;
|
||||
audio_info->product_id = edid_caps->product_id;
|
||||
|
||||
cea_revision = drm_connector->display_info.cea_rev;
|
||||
|
||||
strscpy(audio_info->display_name,
|
||||
edid_caps->display_name,
|
||||
AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
|
||||
|
||||
if (cea_revision >= 3) {
|
||||
audio_info->mode_count = edid_caps->audio_mode_count;
|
||||
|
||||
for (i = 0; i < audio_info->mode_count; ++i) {
|
||||
audio_info->modes[i].format_code =
|
||||
(enum audio_format_code)
|
||||
(edid_caps->audio_modes[i].format_code);
|
||||
audio_info->modes[i].channel_count =
|
||||
edid_caps->audio_modes[i].channel_count;
|
||||
audio_info->modes[i].sample_rates.all =
|
||||
edid_caps->audio_modes[i].sample_rate;
|
||||
audio_info->modes[i].sample_size =
|
||||
edid_caps->audio_modes[i].sample_size;
|
||||
}
|
||||
}
|
||||
|
||||
audio_info->flags.all = edid_caps->speaker_flags;
|
||||
|
||||
/* TODO: We only check for the progressive mode, check for interlace mode too */
|
||||
if (drm_connector->latency_present[0]) {
|
||||
audio_info->video_latency = drm_connector->video_latency[0];
|
||||
audio_info->audio_latency = drm_connector->audio_latency[0];
|
||||
}
|
||||
|
||||
/* TODO: For DP, video and audio latency should be calculated from DPCD caps */
|
||||
|
||||
}
|
||||
|
||||
void amdgpu_dm_commit_audio(struct drm_device *dev,
|
||||
struct drm_atomic_commit *state)
|
||||
{
|
||||
struct amdgpu_device *adev = drm_to_adev(dev);
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_state *old_con_state, *new_con_state;
|
||||
struct drm_crtc_state *new_crtc_state;
|
||||
struct dm_crtc_state *new_dm_crtc_state;
|
||||
const struct dc_stream_status *status;
|
||||
int i, inst;
|
||||
|
||||
/* Notify device removals. */
|
||||
for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
|
||||
if (old_con_state->crtc != new_con_state->crtc) {
|
||||
/* CRTC changes require notification. */
|
||||
goto notify;
|
||||
}
|
||||
|
||||
if (!new_con_state->crtc)
|
||||
continue;
|
||||
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(
|
||||
state, new_con_state->crtc);
|
||||
|
||||
if (!new_crtc_state)
|
||||
continue;
|
||||
|
||||
if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
|
||||
continue;
|
||||
|
||||
notify:
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
|
||||
continue;
|
||||
|
||||
aconnector = to_amdgpu_dm_connector(connector);
|
||||
|
||||
mutex_lock(&adev->dm.audio_lock);
|
||||
inst = aconnector->audio_inst;
|
||||
aconnector->audio_inst = -1;
|
||||
mutex_unlock(&adev->dm.audio_lock);
|
||||
|
||||
amdgpu_dm_audio_eld_notify(adev, inst);
|
||||
}
|
||||
|
||||
/* Notify audio device additions. */
|
||||
for_each_new_connector_in_state(state, connector, new_con_state, i) {
|
||||
if (!new_con_state->crtc)
|
||||
continue;
|
||||
|
||||
new_crtc_state = drm_atomic_get_new_crtc_state(
|
||||
state, new_con_state->crtc);
|
||||
|
||||
if (!new_crtc_state)
|
||||
continue;
|
||||
|
||||
if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
|
||||
continue;
|
||||
|
||||
new_dm_crtc_state = to_dm_crtc_state(new_crtc_state);
|
||||
if (!new_dm_crtc_state->stream)
|
||||
continue;
|
||||
|
||||
status = dc_stream_get_status(new_dm_crtc_state->stream);
|
||||
if (!status)
|
||||
continue;
|
||||
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
|
||||
continue;
|
||||
|
||||
aconnector = to_amdgpu_dm_connector(connector);
|
||||
|
||||
mutex_lock(&adev->dm.audio_lock);
|
||||
inst = status->audio_inst;
|
||||
aconnector->audio_inst = inst;
|
||||
mutex_unlock(&adev->dm.audio_lock);
|
||||
|
||||
amdgpu_dm_audio_eld_notify(adev, inst);
|
||||
}
|
||||
}
|
||||
44
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.h
Normal file
44
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright 2026 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: AMD
|
||||
*/
|
||||
|
||||
#ifndef __AMDGPU_DM_AUDIO_H__
|
||||
#define __AMDGPU_DM_AUDIO_H__
|
||||
|
||||
struct amdgpu_device;
|
||||
struct drm_device;
|
||||
struct drm_atomic_state;
|
||||
struct drm_connector;
|
||||
struct audio_info;
|
||||
struct dc_sink;
|
||||
|
||||
int amdgpu_dm_audio_init(struct amdgpu_device *adev);
|
||||
void amdgpu_dm_audio_fini(struct amdgpu_device *adev);
|
||||
void amdgpu_dm_commit_audio(struct drm_device *dev,
|
||||
struct drm_atomic_commit *state);
|
||||
void amdgpu_dm_fill_audio_info(struct audio_info *audio_info,
|
||||
const struct drm_connector *drm_connector,
|
||||
const struct dc_sink *dc_sink);
|
||||
|
||||
#endif /* __AMDGPU_DM_AUDIO_H__ */
|
||||
Reference in New Issue
Block a user