drm/amd/display: Add more KUnit tests for amdgpu_dm_mst_types

The following existing functions are also exported for the test module:

- needs_dsc_aux_workaround: detect branches needing the DSC AUX workaround
- dm_mst_get_pbn_divider: compute the PBN divider from link bandwidth
- amdgpu_dm_mst_reset_mst_connector_setting: reset per-connector MST state
- retrieve_downstream_port_device: read downstream port presence from DPCD
- retrieve_branch_specific_data: read branch OUI from the upstream device

Several self-contained pieces of logic are extracted from larger functions
into small testable helpers.

- dm_dp_aux_transfer_result: AUX return-code to errno mapping
- dm_dp_aux_fill_payload_flags: AUX request bit decode
- dm_mst_msg_ready_mask: MST sideband ESI mask selection
- dm_mst_select_esi_dpcd: DPCD ESI address/length selection

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:
Alex Hung
2026-05-29 17:16:58 -06:00
committed by Alex Deucher
parent 652021e4be
commit 3576a045cd
3 changed files with 491 additions and 49 deletions

View File

@@ -34,6 +34,7 @@
#include "dm_services.h"
#include "amdgpu.h"
#include "amdgpu_dm.h"
#include "dmub_cmd.h"
#include "amdgpu_dm_mst_types.h"
#include "amdgpu_dm_hdcp.h"
@@ -44,7 +45,6 @@
#include "ddc_service_types.h"
#include "dpcd_defs.h"
#include "dmub_cmd.h"
#if defined(CONFIG_DEBUG_FS)
#include "amdgpu_dm_debugfs.h"
#endif
@@ -53,6 +53,49 @@
#define PEAK_FACTOR_X1000 1006
/*
* Translate a failed AUX transaction's operation result into an errno-style
* return value. @result is returned unchanged for AUX_RET_SUCCESS.
*/
STATIC_IFN_KUNIT ssize_t dm_dp_aux_transfer_result(ssize_t result,
enum aux_return_code_type operation_result)
{
switch (operation_result) {
case AUX_RET_SUCCESS:
break;
case AUX_RET_ERROR_HPD_DISCON:
case AUX_RET_ERROR_UNKNOWN:
case AUX_RET_ERROR_INVALID_OPERATION:
case AUX_RET_ERROR_PROTOCOL_ERROR:
result = -EIO;
break;
case AUX_RET_ERROR_INVALID_REPLY:
case AUX_RET_ERROR_ENGINE_ACQUIRE:
result = -EBUSY;
break;
case AUX_RET_ERROR_TIMEOUT:
result = -ETIMEDOUT;
break;
}
return result;
}
EXPORT_IF_KUNIT(dm_dp_aux_transfer_result);
/*
* Derive the AUX payload transaction flags from a DP AUX request field.
*/
STATIC_IFN_KUNIT void dm_dp_aux_fill_payload_flags(u8 request,
struct aux_payload *payload)
{
payload->i2c_over_aux = (request & DP_AUX_NATIVE_WRITE) == 0;
payload->write = (request & DP_AUX_I2C_READ) == 0;
payload->mot = (request & DP_AUX_I2C_MOT) != 0;
payload->write_status_update =
(request & DP_AUX_I2C_WRITE_STATUS_UPDATE) != 0;
}
EXPORT_IF_KUNIT(dm_dp_aux_fill_payload_flags);
/*
* This function handles both native AUX and I2C-Over-AUX transactions.
*/
@@ -73,11 +116,7 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
payload.data = msg->buffer;
payload.length = msg->size;
payload.reply = &msg->reply;
payload.i2c_over_aux = (msg->request & DP_AUX_NATIVE_WRITE) == 0;
payload.write = (msg->request & DP_AUX_I2C_READ) == 0;
payload.mot = (msg->request & DP_AUX_I2C_MOT) != 0;
payload.write_status_update =
(msg->request & DP_AUX_I2C_WRITE_STATUS_UPDATE) != 0;
dm_dp_aux_fill_payload_flags(msg->request, &payload);
payload.defer_delay = 0;
if (payload.write) {
@@ -117,23 +156,7 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
}
if (result < 0) {
switch (operation_result) {
case AUX_RET_SUCCESS:
break;
case AUX_RET_ERROR_HPD_DISCON:
case AUX_RET_ERROR_UNKNOWN:
case AUX_RET_ERROR_INVALID_OPERATION:
case AUX_RET_ERROR_PROTOCOL_ERROR:
result = -EIO;
break;
case AUX_RET_ERROR_INVALID_REPLY:
case AUX_RET_ERROR_ENGINE_ACQUIRE:
result = -EBUSY;
break;
case AUX_RET_ERROR_TIMEOUT:
result = -ETIMEDOUT;
break;
}
result = dm_dp_aux_transfer_result(result, operation_result);
drm_dbg_dp(adev_to_drm(adev), "DP AUX transfer fail:%d\n", operation_result);
}
@@ -184,7 +207,7 @@ amdgpu_dm_mst_connector_late_register(struct drm_connector *connector)
}
static inline void
STATIC_IFN_KUNIT void
amdgpu_dm_mst_reset_mst_connector_setting(struct amdgpu_dm_connector *aconnector)
{
aconnector->drm_edid = NULL;
@@ -193,6 +216,7 @@ amdgpu_dm_mst_reset_mst_connector_setting(struct amdgpu_dm_connector *aconnector
aconnector->mst_local_bw = 0;
aconnector->vc_full_pbn = 0;
}
EXPORT_IF_KUNIT(amdgpu_dm_mst_reset_mst_connector_setting);
static void
amdgpu_dm_mst_connector_early_unregister(struct drm_connector *connector)
@@ -313,7 +337,7 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto
}
#endif
static bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector)
STATIC_IFN_KUNIT bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector)
{
union dp_downstream_port_present ds_port_present;
@@ -331,8 +355,9 @@ static bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnect
return true;
}
EXPORT_IF_KUNIT(retrieve_downstream_port_device);
static bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector)
STATIC_IFN_KUNIT bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector)
{
struct drm_connector *connector = &aconnector->base;
struct drm_dp_mst_port *port = aconnector->mst_output_port;
@@ -359,6 +384,7 @@ static bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector
return true;
}
EXPORT_IF_KUNIT(retrieve_branch_specific_data);
static int dm_dp_mst_get_modes(struct drm_connector *connector)
{
@@ -708,6 +734,44 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
return connector;
}
/*
* Select the ESI[1] mask used to filter the MST sideband ready bits for a
* given message-ready event type.
*/
STATIC_IFN_KUNIT u8 dm_mst_msg_ready_mask(enum mst_msg_ready_type msg_rdy_type)
{
switch (msg_rdy_type) {
case DOWN_REP_MSG_RDY_EVENT:
/* Only handle DOWN_REP_MSG_RDY case*/
return DP_DOWN_REP_MSG_RDY;
case UP_REQ_MSG_RDY_EVENT:
/* Only handle UP_REQ_MSG_RDY case*/
return DP_UP_REQ_MSG_RDY;
default:
/* Handle both cases*/
return DP_DOWN_REP_MSG_RDY | DP_UP_REQ_MSG_RDY;
}
}
EXPORT_IF_KUNIT(dm_mst_msg_ready_mask);
/*
* Select the DPCD ESI address and read length based on the DPCD revision.
*/
STATIC_IFN_KUNIT void dm_mst_select_esi_dpcd(u8 dpcd_rev, int *dpcd_addr,
u8 *dpcd_bytes_to_read)
{
if (dpcd_rev < 0x12) {
*dpcd_bytes_to_read = DP_LANE0_1_STATUS - DP_SINK_COUNT;
/* DPCD 0x200 - 0x201 for downstream IRQ */
*dpcd_addr = DP_SINK_COUNT;
} else {
*dpcd_bytes_to_read = DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI;
/* DPCD 0x2002 - 0x2005 for downstream IRQ */
*dpcd_addr = DP_SINK_COUNT_ESI;
}
}
EXPORT_IF_KUNIT(dm_mst_select_esi_dpcd);
void dm_handle_mst_sideband_msg_ready_event(
struct drm_dp_mst_topology_mgr *mgr,
enum mst_msg_ready_type msg_rdy_type)
@@ -726,15 +790,8 @@ void dm_handle_mst_sideband_msg_ready_event(
const struct dc_link_status *link_status = dc_link_get_status(aconnector->dc_link);
if (link_status->dpcd_caps->dpcd_rev.raw < 0x12) {
dpcd_bytes_to_read = DP_LANE0_1_STATUS - DP_SINK_COUNT;
/* DPCD 0x200 - 0x201 for downstream IRQ */
dpcd_addr = DP_SINK_COUNT;
} else {
dpcd_bytes_to_read = DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI;
/* DPCD 0x2002 - 0x2005 for downstream IRQ */
dpcd_addr = DP_SINK_COUNT_ESI;
}
dm_mst_select_esi_dpcd(link_status->dpcd_caps->dpcd_rev.raw, &dpcd_addr,
&dpcd_bytes_to_read);
mutex_lock(&aconnector->handle_mst_msg_ready);
@@ -756,20 +813,7 @@ void dm_handle_mst_sideband_msg_ready_event(
DRM_DEBUG_DRIVER("ESI %02x %02x %02x\n", esi[0], esi[1], esi[2]);
switch (msg_rdy_type) {
case DOWN_REP_MSG_RDY_EVENT:
/* Only handle DOWN_REP_MSG_RDY case*/
esi[1] &= DP_DOWN_REP_MSG_RDY;
break;
case UP_REQ_MSG_RDY_EVENT:
/* Only handle UP_REQ_MSG_RDY case*/
esi[1] &= DP_UP_REQ_MSG_RDY;
break;
default:
/* Handle both cases*/
esi[1] &= (DP_DOWN_REP_MSG_RDY | DP_UP_REQ_MSG_RDY);
break;
}
esi[1] &= dm_mst_msg_ready_mask(msg_rdy_type);
if (!esi[1])
break;
@@ -866,6 +910,7 @@ uint32_t dm_mst_get_pbn_divider(struct dc_link *link)
return dfixed_const(pbn_div_x100) / 100;
}
EXPORT_IF_KUNIT(dm_mst_get_pbn_divider);
struct dsc_mst_fairness_params {
struct dc_crtc_timing *timing;

View File

@@ -60,6 +60,7 @@ enum mst_msg_ready_type {
struct amdgpu_device;
struct amdgpu_display_manager;
struct amdgpu_dm_connector;
struct aux_payload;
struct dc_state;
struct dc_stream_state;
struct dm_atomic_state;
@@ -100,4 +101,15 @@ enum dc_status dm_dp_mst_is_port_support_mode(
struct amdgpu_dm_connector *aconnector,
struct dc_stream_state *stream);
#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST)
void amdgpu_dm_mst_reset_mst_connector_setting(struct amdgpu_dm_connector *aconnector);
bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector);
bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector);
ssize_t dm_dp_aux_transfer_result(ssize_t result,
enum aux_return_code_type operation_result);
void dm_dp_aux_fill_payload_flags(u8 request, struct aux_payload *payload);
u8 dm_mst_msg_ready_mask(enum mst_msg_ready_type msg_rdy_type);
void dm_mst_select_esi_dpcd(u8 dpcd_rev, int *dpcd_addr, u8 *dpcd_bytes_to_read);
#endif
#endif

View File

@@ -7,10 +7,44 @@
#include <kunit/test.h>
#include <drm/display/drm_dp.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/display/drm_dp_mst_helper.h>
#include "dc.h"
#include "dpcd_defs.h"
#include "dmub_cmd.h"
#include "amdgpu.h"
#include "amdgpu_mode.h"
#include "amdgpu_dm.h"
#include "amdgpu_dm_mst_types.h"
/*
* Minimal mock DPCD backing store and AUX transfer callback used to exercise
* the DPCD read paths without real hardware.
*/
static u8 dm_mst_test_dpcd[0x10];
static ssize_t dm_mst_test_aux_transfer(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg)
{
size_t i;
switch (msg->request & ~DP_AUX_I2C_MOT) {
case DP_AUX_NATIVE_READ:
for (i = 0; i < msg->size; i++)
((u8 *)msg->buffer)[i] =
dm_mst_test_dpcd[(msg->address + i) & 0xf];
msg->reply = DP_AUX_NATIVE_REPLY_ACK;
return msg->size;
case DP_AUX_NATIVE_WRITE:
msg->reply = DP_AUX_NATIVE_REPLY_ACK;
return msg->size;
default:
return -EINVAL;
}
}
/* Tests for needs_dsc_aux_workaround */
/**
@@ -103,6 +137,332 @@ static void dm_mst_test_needs_dsc_aux_workaround_low_sink_count(struct kunit *te
KUNIT_EXPECT_FALSE(test, needs_dsc_aux_workaround(&link));
}
/**
* dm_mst_test_needs_dsc_aux_workaround_zero_sink_count - Test workaround skipped for zero sinks
* @test: KUnit test context
*
* Verify that needs_dsc_aux_workaround() returns false when the sink
* count is zero, even if device ID and DPCD rev match.
*/
static void dm_mst_test_needs_dsc_aux_workaround_zero_sink_count(struct kunit *test)
{
struct dc_link link = {0};
link.dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24;
link.dpcd_caps.dpcd_rev.raw = DPCD_REV_14;
link.dpcd_caps.sink_count.bits.SINK_COUNT = 0;
KUNIT_EXPECT_FALSE(test, needs_dsc_aux_workaround(&link));
}
/* Tests for dm_mst_get_pbn_divider */
/**
* dm_mst_test_pbn_divider_null_link - Test pbn_divider with NULL link
* @test: KUnit test context
*
* Verify that dm_mst_get_pbn_divider() returns 0 when passed a NULL
* link pointer without crashing.
*/
static void dm_mst_test_pbn_divider_null_link(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, dm_mst_get_pbn_divider(NULL), 0U);
}
/* Tests for amdgpu_dm_mst_reset_mst_connector_setting */
/**
* dm_mst_test_reset_connector_setting - Test MST connector setting reset
* @test: KUnit test context
*
* Verify that amdgpu_dm_mst_reset_mst_connector_setting() clears the cached
* EDID, DSC AUX, passthrough AUX, local bandwidth, and VC PBN state.
*/
static void dm_mst_test_reset_connector_setting(struct kunit *test)
{
struct amdgpu_dm_connector *aconnector;
struct drm_dp_mst_port *port;
aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
port = kunit_kzalloc(test, sizeof(*port), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, aconnector);
KUNIT_ASSERT_NOT_NULL(test, port);
aconnector->drm_edid = (const struct drm_edid *)test;
aconnector->dsc_aux = (struct drm_dp_aux *)test;
aconnector->mst_output_port = port;
aconnector->mst_output_port->passthrough_aux = (struct drm_dp_aux *)test;
aconnector->mst_local_bw = 12345;
aconnector->vc_full_pbn = 678;
amdgpu_dm_mst_reset_mst_connector_setting(aconnector);
KUNIT_EXPECT_TRUE(test, aconnector->drm_edid == NULL);
KUNIT_EXPECT_TRUE(test, aconnector->dsc_aux == NULL);
KUNIT_EXPECT_TRUE(test, aconnector->mst_output_port->passthrough_aux == NULL);
KUNIT_EXPECT_EQ(test, aconnector->mst_local_bw, 0U);
KUNIT_EXPECT_EQ(test, aconnector->vc_full_pbn, 0U);
}
/* Tests for retrieve_downstream_port_device */
/**
* dm_mst_test_retrieve_downstream_no_aux - Test retrieval bails out without AUX
* @test: KUnit test context
*
* Verify that retrieve_downstream_port_device() returns false when the
* connector has no DSC AUX channel and therefore cannot read DPCD.
*/
static void dm_mst_test_retrieve_downstream_no_aux(struct kunit *test)
{
struct amdgpu_dm_connector *aconnector;
aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, aconnector);
aconnector->dsc_aux = NULL;
KUNIT_EXPECT_FALSE(test, retrieve_downstream_port_device(aconnector));
}
/**
* dm_mst_test_retrieve_downstream_present - Test retrieval parses DPCD 0x05
* @test: KUnit test context
*
* Verify that retrieve_downstream_port_device() reads DP_DOWNSTREAMPORT_PRESENT
* over a mock AUX channel and caches the parsed downstream port fields.
*/
static void dm_mst_test_retrieve_downstream_present(struct kunit *test)
{
struct amdgpu_dm_connector *aconnector;
struct drm_dp_aux *aux;
aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
aux = kunit_kzalloc(test, sizeof(*aux), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, aconnector);
KUNIT_ASSERT_NOT_NULL(test, aux);
memset(dm_mst_test_dpcd, 0, sizeof(dm_mst_test_dpcd));
/* PORT_PRESENT = 1, PORT_TYPE = 2 (0b101) */
dm_mst_test_dpcd[DP_DOWNSTREAMPORT_PRESENT] = 0x05;
aux->name = "dm_mst_test_aux";
aux->transfer = dm_mst_test_aux_transfer;
drm_dp_aux_init(aux);
drm_dp_dpcd_set_probe(aux, false);
aconnector->dsc_aux = aux;
KUNIT_EXPECT_TRUE(test, retrieve_downstream_port_device(aconnector));
KUNIT_EXPECT_EQ(test,
(int)aconnector->mst_downstream_port_present.fields.PORT_PRESENT, 1);
KUNIT_EXPECT_EQ(test,
(int)aconnector->mst_downstream_port_present.fields.PORT_TYPE, 2);
}
/* Tests for retrieve_branch_specific_data */
/**
* dm_mst_test_retrieve_branch_no_parent - Test branch lookup needs a parent port
* @test: KUnit test context
*
* Verify that retrieve_branch_specific_data() returns false when the MST
* output port has no parent branch device to query.
*/
static void dm_mst_test_retrieve_branch_no_parent(struct kunit *test)
{
struct amdgpu_dm_connector *aconnector;
struct drm_dp_mst_port *port;
aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL);
port = kunit_kzalloc(test, sizeof(*port), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, aconnector);
KUNIT_ASSERT_NOT_NULL(test, port);
port->parent = NULL;
aconnector->mst_output_port = port;
KUNIT_EXPECT_FALSE(test, retrieve_branch_specific_data(aconnector));
}
/**
* dm_mst_test_aux_result_success - AUX_RET_SUCCESS preserves the input result.
* @test: KUnit test context.
*
* On success the original (negative) transfer result must be returned unchanged.
*/
static void dm_mst_test_aux_result_success(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-5, AUX_RET_SUCCESS), (ssize_t)-5);
KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(3, AUX_RET_SUCCESS), (ssize_t)3);
}
/**
* dm_mst_test_aux_result_eio - HPD/unknown/protocol errors map to -EIO.
* @test: KUnit test context.
*
* AUX_RET_ERROR_HPD_DISCON, AUX_RET_ERROR_UNKNOWN,
* AUX_RET_ERROR_INVALID_OPERATION and AUX_RET_ERROR_PROTOCOL_ERROR all map to -EIO.
*/
static void dm_mst_test_aux_result_eio(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-1, AUX_RET_ERROR_HPD_DISCON),
(ssize_t)-EIO);
KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-1, AUX_RET_ERROR_UNKNOWN),
(ssize_t)-EIO);
KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-1, AUX_RET_ERROR_INVALID_OPERATION),
(ssize_t)-EIO);
KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-1, AUX_RET_ERROR_PROTOCOL_ERROR),
(ssize_t)-EIO);
}
/**
* dm_mst_test_aux_result_ebusy - invalid reply / engine acquire map to -EBUSY.
* @test: KUnit test context.
*
* AUX_RET_ERROR_INVALID_REPLY and AUX_RET_ERROR_ENGINE_ACQUIRE map to -EBUSY.
*/
static void dm_mst_test_aux_result_ebusy(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-1, AUX_RET_ERROR_INVALID_REPLY),
(ssize_t)-EBUSY);
KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-1, AUX_RET_ERROR_ENGINE_ACQUIRE),
(ssize_t)-EBUSY);
}
/**
* dm_mst_test_aux_result_timeout - AUX_RET_ERROR_TIMEOUT maps to -ETIMEDOUT.
* @test: KUnit test context.
*/
static void dm_mst_test_aux_result_timeout(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-1, AUX_RET_ERROR_TIMEOUT),
(ssize_t)-ETIMEDOUT);
}
/**
* dm_mst_test_fill_payload_flags_native_write - native write request decode.
* @test: KUnit test context.
*
* DP_AUX_NATIVE_WRITE clears i2c_over_aux and sets write; no I2C bits set.
*/
static void dm_mst_test_fill_payload_flags_native_write(struct kunit *test)
{
struct aux_payload payload = { 0 };
dm_dp_aux_fill_payload_flags(DP_AUX_NATIVE_WRITE, &payload);
KUNIT_EXPECT_FALSE(test, payload.i2c_over_aux);
KUNIT_EXPECT_TRUE(test, payload.write);
KUNIT_EXPECT_FALSE(test, payload.mot);
KUNIT_EXPECT_FALSE(test, payload.write_status_update);
}
/**
* dm_mst_test_fill_payload_flags_native_read - native read request decode.
* @test: KUnit test context.
*
* DP_AUX_NATIVE_READ keeps i2c_over_aux clear; the I2C_READ bit clears write.
*/
static void dm_mst_test_fill_payload_flags_native_read(struct kunit *test)
{
struct aux_payload payload = { 0 };
dm_dp_aux_fill_payload_flags(DP_AUX_NATIVE_READ, &payload);
KUNIT_EXPECT_FALSE(test, payload.i2c_over_aux);
KUNIT_EXPECT_FALSE(test, payload.write);
KUNIT_EXPECT_FALSE(test, payload.mot);
}
/**
* dm_mst_test_fill_payload_flags_i2c_read_mot - I2C read with MOT request decode.
* @test: KUnit test context.
*
* DP_AUX_I2C_READ sets i2c_over_aux and clears write; DP_AUX_I2C_MOT sets mot.
*/
static void dm_mst_test_fill_payload_flags_i2c_read_mot(struct kunit *test)
{
struct aux_payload payload = { 0 };
dm_dp_aux_fill_payload_flags(DP_AUX_I2C_READ | DP_AUX_I2C_MOT, &payload);
KUNIT_EXPECT_TRUE(test, payload.i2c_over_aux);
KUNIT_EXPECT_FALSE(test, payload.write);
KUNIT_EXPECT_TRUE(test, payload.mot);
}
/**
* dm_mst_test_fill_payload_flags_write_status - write status update decode.
* @test: KUnit test context.
*
* DP_AUX_I2C_WRITE_STATUS_UPDATE sets write_status_update.
*/
static void dm_mst_test_fill_payload_flags_write_status(struct kunit *test)
{
struct aux_payload payload = { 0 };
dm_dp_aux_fill_payload_flags(DP_AUX_I2C_WRITE | DP_AUX_I2C_WRITE_STATUS_UPDATE,
&payload);
KUNIT_EXPECT_TRUE(test, payload.i2c_over_aux);
KUNIT_EXPECT_TRUE(test, payload.write_status_update);
}
/**
* dm_mst_test_msg_ready_mask - ESI mask selection per message-ready type.
* @test: KUnit test context.
*
* DOWN_REP and UP_REQ each select their single bit; other types select both.
*/
static void dm_mst_test_msg_ready_mask(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, dm_mst_msg_ready_mask(DOWN_REP_MSG_RDY_EVENT),
(u8)DP_DOWN_REP_MSG_RDY);
KUNIT_EXPECT_EQ(test, dm_mst_msg_ready_mask(UP_REQ_MSG_RDY_EVENT),
(u8)DP_UP_REQ_MSG_RDY);
KUNIT_EXPECT_EQ(test, dm_mst_msg_ready_mask(DOWN_OR_UP_MSG_RDY_EVENT),
(u8)(DP_DOWN_REP_MSG_RDY | DP_UP_REQ_MSG_RDY));
KUNIT_EXPECT_EQ(test, dm_mst_msg_ready_mask(NONE_MSG_RDY_EVENT),
(u8)(DP_DOWN_REP_MSG_RDY | DP_UP_REQ_MSG_RDY));
}
/**
* dm_mst_test_select_esi_dpcd_legacy - pre-1.2 DPCD ESI address/length.
* @test: KUnit test context.
*
* For DPCD rev < 0x12 the legacy DP_SINK_COUNT address/length pair is selected.
*/
static void dm_mst_test_select_esi_dpcd_legacy(struct kunit *test)
{
int dpcd_addr = -1;
u8 dpcd_bytes_to_read = 0;
dm_mst_select_esi_dpcd(0x11, &dpcd_addr, &dpcd_bytes_to_read);
KUNIT_EXPECT_EQ(test, dpcd_addr, DP_SINK_COUNT);
KUNIT_EXPECT_EQ(test, (int)dpcd_bytes_to_read,
(int)(DP_LANE0_1_STATUS - DP_SINK_COUNT));
}
/**
* dm_mst_test_select_esi_dpcd_esi - 1.2+ DPCD ESI address/length.
* @test: KUnit test context.
*
* For DPCD rev >= 0x12 the ESI DP_SINK_COUNT_ESI address/length pair is selected.
*/
static void dm_mst_test_select_esi_dpcd_esi(struct kunit *test)
{
int dpcd_addr = -1;
u8 dpcd_bytes_to_read = 0;
dm_mst_select_esi_dpcd(0x14, &dpcd_addr, &dpcd_bytes_to_read);
KUNIT_EXPECT_EQ(test, dpcd_addr, DP_SINK_COUNT_ESI);
KUNIT_EXPECT_EQ(test, (int)dpcd_bytes_to_read,
(int)(DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI));
}
static struct kunit_case dm_mst_types_test_cases[] = {
/* needs_dsc_aux_workaround tests */
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_match),
@@ -110,6 +470,31 @@ static struct kunit_case dm_mst_types_test_cases[] = {
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_wrong_dev_id),
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_wrong_rev),
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_low_sink_count),
KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_zero_sink_count),
/* dm_mst_get_pbn_divider tests */
KUNIT_CASE(dm_mst_test_pbn_divider_null_link),
/* amdgpu_dm_mst_reset_mst_connector_setting tests */
KUNIT_CASE(dm_mst_test_reset_connector_setting),
/* retrieve_downstream_port_device tests */
KUNIT_CASE(dm_mst_test_retrieve_downstream_no_aux),
KUNIT_CASE(dm_mst_test_retrieve_downstream_present),
/* retrieve_branch_specific_data tests */
KUNIT_CASE(dm_mst_test_retrieve_branch_no_parent),
/* dm_dp_aux_transfer_result tests */
KUNIT_CASE(dm_mst_test_aux_result_success),
KUNIT_CASE(dm_mst_test_aux_result_eio),
KUNIT_CASE(dm_mst_test_aux_result_ebusy),
KUNIT_CASE(dm_mst_test_aux_result_timeout),
/* dm_dp_aux_fill_payload_flags tests */
KUNIT_CASE(dm_mst_test_fill_payload_flags_native_write),
KUNIT_CASE(dm_mst_test_fill_payload_flags_native_read),
KUNIT_CASE(dm_mst_test_fill_payload_flags_i2c_read_mot),
KUNIT_CASE(dm_mst_test_fill_payload_flags_write_status),
/* dm_mst_msg_ready_mask tests */
KUNIT_CASE(dm_mst_test_msg_ready_mask),
/* dm_mst_select_esi_dpcd tests */
KUNIT_CASE(dm_mst_test_select_esi_dpcd_legacy),
KUNIT_CASE(dm_mst_test_select_esi_dpcd_esi),
{}
};