All of lore.kernel.org
 help / color / mirror / Atom feed
From: Fangzhi Zuo <jerry.zuo@amd.com>
To: <amd-gfx@lists.freedesktop.org>
Cc: Harry Wentland <harry.wentland@amd.com>,
	Leo Li <sunpeng.li@amd.com>,
	Aurabindo Pillai <aurabindo.pillai@amd.com>,
	Roman Li <roman.li@amd.com>, Wayne Lin <wayne.lin@amd.com>,
	Tom Chung <chiahsuan.chung@amd.com>,
	"Fangzhi Zuo" <jerry.zuo@amd.com>,
	Dan Wheeler <daniel.wheeler@amd.com>, Ray Wu <Ray.Wu@amd.com>,
	Ivan Lipski <ivan.lipski@amd.com>, Alex Hung <alex.hung@amd.com>,
	James Lin <PingLei.Lin@amd.com>,
	Chenyu Chen <Chen-Yu.Chen@amd.com>,
	Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Subject: [PATCH 33/49] drm/amd/display: Add KUnit tests for HDCP DDC link adapters
Date: Thu, 23 Jul 2026 16:13:41 -0400	[thread overview]
Message-ID: <20260723201908.373300-34-jerry.zuo@amd.com> (raw)
In-Reply-To: <20260723201908.373300-1-jerry.zuo@amd.com>

From: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>

Expose the mod_hdcp DDC adapter callbacks for KUnit and add tests:

lp_write_i2c / lp_read_i2c / lp_write_dpcd / lp_read_dpcd use recording
fake i2c and DP aux backends to assert the built payloads (write flag,
address, length, buffer, and the read offset-then-data sequence), plus
failure when the connector is missing.

lp_atomic_write_poll_read_i2c / lp_atomic_write_poll_read_aux cover the
hardware-free early returns (NULL link and a payload too large to convert);
the success path submits fused-IO to the DMCUB and is out of reach for a
unit test.

Reviewed-by: Alex Hung <alex.hung@amd.com>
Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com>
Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
---
 .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.c    |  50 +--
 .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.h    |  16 +
 .../amdgpu_dm/tests/amdgpu_dm_hdcp_test.c     | 378 ++++++++++++++++++
 3 files changed, 420 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
index 9ea0a120af6f..c887a70ae74d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
@@ -38,8 +38,7 @@
  */
 #define PSP_SRM_VERSION_MAX 0xFFFF
 
-static bool
-lp_write_i2c(void *handle, uint32_t address, const uint8_t *data, uint32_t size)
+STATIC_IFN_KUNIT bool lp_write_i2c(void *handle, uint32_t address, const uint8_t *data, uint32_t size)
 {
 	struct dc_link *link = handle;
 	struct i2c_payload i2c_payloads[] = {{true, address, size, (void *)data} };
@@ -48,9 +47,9 @@ lp_write_i2c(void *handle, uint32_t address, const uint8_t *data, uint32_t size)
 
 	return dm_helpers_submit_i2c(link->ctx, link, &cmd);
 }
+EXPORT_IF_KUNIT(lp_write_i2c);
 
-static bool
-lp_read_i2c(void *handle, uint32_t address, uint8_t offset, uint8_t *data, uint32_t size)
+STATIC_IFN_KUNIT bool lp_read_i2c(void *handle, uint32_t address, uint8_t offset, uint8_t *data, uint32_t size)
 {
 	struct dc_link *link = handle;
 
@@ -61,50 +60,53 @@ lp_read_i2c(void *handle, uint32_t address, uint8_t offset, uint8_t *data, uint3
 
 	return dm_helpers_submit_i2c(link->ctx, link, &cmd);
 }
+EXPORT_IF_KUNIT(lp_read_i2c);
 
-static bool
-lp_write_dpcd(void *handle, uint32_t address, const uint8_t *data, uint32_t size)
+STATIC_IFN_KUNIT bool lp_write_dpcd(void *handle, uint32_t address, const uint8_t *data, uint32_t size)
 {
 	struct dc_link *link = handle;
 
 	return dm_helpers_dp_write_dpcd(link->ctx, link, address, data, size);
 }
+EXPORT_IF_KUNIT(lp_write_dpcd);
 
-static bool
-lp_read_dpcd(void *handle, uint32_t address, uint8_t *data, uint32_t size)
+STATIC_IFN_KUNIT bool lp_read_dpcd(void *handle, uint32_t address, uint8_t *data, uint32_t size)
 {
 	struct dc_link *link = handle;
 
 	return dm_helpers_dp_read_dpcd(link->ctx, link, address, data, size);
 }
-
-static bool lp_atomic_write_poll_read_i2c(
-		void *handle,
-		const struct mod_hdcp_atomic_op_i2c *write,
-		const struct mod_hdcp_atomic_op_i2c *poll,
-		struct mod_hdcp_atomic_op_i2c *read,
-		uint32_t poll_timeout_us,
-		uint8_t poll_mask_msb
+EXPORT_IF_KUNIT(lp_read_dpcd);
+
+STATIC_IFN_KUNIT bool lp_atomic_write_poll_read_i2c(
+						void *handle,
+						const struct mod_hdcp_atomic_op_i2c *write,
+						const struct mod_hdcp_atomic_op_i2c *poll,
+						struct mod_hdcp_atomic_op_i2c *read,
+						uint32_t poll_timeout_us,
+						uint8_t poll_mask_msb
 )
 {
 	struct dc_link *link = handle;
 
 	return dm_atomic_write_poll_read_i2c(link, write, poll, read, poll_timeout_us, poll_mask_msb);
 }
-
-static bool lp_atomic_write_poll_read_aux(
-		void *handle,
-		const struct mod_hdcp_atomic_op_aux *write,
-		const struct mod_hdcp_atomic_op_aux *poll,
-		struct mod_hdcp_atomic_op_aux *read,
-		uint32_t poll_timeout_us,
-		uint8_t poll_mask_msb
+EXPORT_IF_KUNIT(lp_atomic_write_poll_read_i2c);
+
+STATIC_IFN_KUNIT bool lp_atomic_write_poll_read_aux(
+						void *handle,
+						const struct mod_hdcp_atomic_op_aux *write,
+						const struct mod_hdcp_atomic_op_aux *poll,
+						struct mod_hdcp_atomic_op_aux *read,
+						uint32_t poll_timeout_us,
+						uint8_t poll_mask_msb
 )
 {
 	struct dc_link *link = handle;
 
 	return dm_atomic_write_poll_read_aux(link, write, poll, read, poll_timeout_us, poll_mask_msb);
 }
+EXPORT_IF_KUNIT(lp_atomic_write_poll_read_aux);
 
 STATIC_IFN_KUNIT
 uint8_t *psp_get_srm(struct psp_context *psp, uint32_t *srm_version, uint32_t *srm_size)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
index e700d019f971..665fa4839a25 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
@@ -48,6 +48,8 @@ struct psp_context;
 struct file;
 struct kobject;
 struct bin_attribute;
+struct mod_hdcp_atomic_op_i2c;
+struct mod_hdcp_atomic_op_aux;
 
 struct hdcp_workqueue {
 	struct work_struct cpirq_work;
@@ -134,6 +136,20 @@ ssize_t srm_data_write(struct file *filp, struct kobject *kobj,
 ssize_t srm_data_read(struct file *filp, struct kobject *kobj,
 		      const struct bin_attribute *bin_attr, char *buffer,
 		      loff_t pos, size_t count);
+bool lp_write_i2c(void *handle, uint32_t address, const uint8_t *data, uint32_t size);
+bool lp_read_i2c(void *handle, uint32_t address, uint8_t offset, uint8_t *data, uint32_t size);
+bool lp_write_dpcd(void *handle, uint32_t address, const uint8_t *data, uint32_t size);
+bool lp_read_dpcd(void *handle, uint32_t address, uint8_t *data, uint32_t size);
+bool lp_atomic_write_poll_read_i2c(void *handle,
+				   const struct mod_hdcp_atomic_op_i2c *write,
+				   const struct mod_hdcp_atomic_op_i2c *poll,
+				   struct mod_hdcp_atomic_op_i2c *read,
+				   uint32_t poll_timeout_us, uint8_t poll_mask_msb);
+bool lp_atomic_write_poll_read_aux(void *handle,
+				   const struct mod_hdcp_atomic_op_aux *write,
+				   const struct mod_hdcp_atomic_op_aux *poll,
+				   struct mod_hdcp_atomic_op_aux *read,
+				   uint32_t poll_timeout_us, uint8_t poll_mask_msb);
 #endif
 
 #endif /* AMDGPU_DM_AMDGPU_DM_HDCP_H_ */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
index a8bca05f47a3..838826d274c2 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
@@ -10,6 +10,9 @@
 #include <linux/kobject.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
+#include <linux/i2c.h>
+
+#include <drm/display/drm_dp_helper.h>
 
 #include "amdgpu.h"
 #include "amdgpu_dm.h"
@@ -1461,6 +1464,369 @@ static void dm_test_srm_data_read_empty_srm_returns_zero(struct kunit *test)
 
 /* End of tests for srm_data_write() and srm_data_read() */
 
+/* Tests for lp_write_i2c() / lp_read_i2c() / lp_write_dpcd() / lp_read_dpcd() */
+
+/* Defined further below with the display helper tests. */
+static struct amdgpu_dm_connector *alloc_test_connector(struct kunit *test,
+						       unsigned int index);
+
+/*
+ * Recording fakes for the DDC layer. The lp_* wrappers build i2c/DPCD
+ * transactions and forward them through dm_helpers_*, which end up calling
+ * i2c_transfer() / drm_dp_dpcd_*(). These fakes capture the resulting
+ * messages so the tests can assert what the wrappers built, without touching
+ * real hardware. KUnit runs cases sequentially, so file-scope capture state
+ * is reset at the start of each test.
+ */
+#define FAKE_DDC_MAX_MSGS 4
+
+static struct fake_i2c_capture {
+	int num;
+	struct i2c_msg msgs[FAKE_DDC_MAX_MSGS];
+} fake_i2c_cap;
+
+static int fake_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+				int num)
+{
+	int i;
+
+	fake_i2c_cap.num = num;
+	for (i = 0; i < num && i < FAKE_DDC_MAX_MSGS; i++)
+		fake_i2c_cap.msgs[i] = msgs[i];
+
+	return num;
+}
+
+static u32 fake_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm fake_i2c_algo = {
+	.master_xfer = fake_i2c_master_xfer,
+	.functionality = fake_i2c_functionality,
+};
+
+static void fake_i2c_lock_bus(struct i2c_adapter *adap, unsigned int flags) {}
+static int fake_i2c_trylock_bus(struct i2c_adapter *adap, unsigned int flags)
+{
+	return 1;
+}
+static void fake_i2c_unlock_bus(struct i2c_adapter *adap, unsigned int flags) {}
+
+static const struct i2c_lock_operations fake_i2c_lock_ops = {
+	.lock_bus = fake_i2c_lock_bus,
+	.trylock_bus = fake_i2c_trylock_bus,
+	.unlock_bus = fake_i2c_unlock_bus,
+};
+
+static struct fake_aux_capture {
+	int calls;
+	u8 request;
+	unsigned int address;
+	size_t size;
+} fake_aux_cap;
+
+static ssize_t fake_aux_transfer(struct drm_dp_aux *aux,
+				 struct drm_dp_aux_msg *msg)
+{
+	fake_aux_cap.calls++;
+	fake_aux_cap.request = msg->request;
+	fake_aux_cap.address = msg->address;
+	fake_aux_cap.size = msg->size;
+	msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+
+	return msg->size;
+}
+
+/**
+ * alloc_test_ddc_link - connector/link wired to the recording i2c + aux fakes
+ * @test: KUnit test context for managed allocation
+ *
+ * Builds an amdgpu_dm_connector with a fake i2c adapter and a fake DP aux, and
+ * points link->priv at the connector so dm_helpers_* find it. Returns the
+ * dc_link that the lp_* wrappers take as their opaque handle.
+ */
+static struct dc_link *alloc_test_ddc_link(struct kunit *test)
+{
+	struct amdgpu_dm_connector *aconnector = alloc_test_connector(test, 0);
+	struct amdgpu_i2c_adapter *i2c;
+	struct dc_link *link;
+
+	KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+	i2c = kunit_kzalloc(test, sizeof(*i2c), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, i2c);
+	i2c->base.algo = &fake_i2c_algo;
+	i2c->base.lock_ops = &fake_i2c_lock_ops;
+	aconnector->i2c = i2c;
+
+	mutex_init(&aconnector->dm_dp_aux.aux.hw_mutex);
+	aconnector->dm_dp_aux.aux.transfer = fake_aux_transfer;
+	/* Skip the DPCD "throw away" probe read so we capture only our access. */
+	aconnector->dm_dp_aux.aux.dpcd_probe_disabled = true;
+
+	link = aconnector->dc_link;
+	link->priv = aconnector;
+
+	return link;
+}
+
+/**
+ * dm_test_lp_write_i2c_builds_single_write_payload - write builds one i2c msg
+ * @test: KUnit test context
+ *
+ * lp_write_i2c() must forward a single write payload carrying the address,
+ * length and data buffer unchanged.
+ */
+static void dm_test_lp_write_i2c_builds_single_write_payload(struct kunit *test)
+{
+	struct dc_link *link = alloc_test_ddc_link(test);
+	u8 data[3] = {0x11, 0x22, 0x33};
+	bool ok;
+
+	memset(&fake_i2c_cap, 0, sizeof(fake_i2c_cap));
+
+	ok = lp_write_i2c(link, 0x3a, data, sizeof(data));
+
+	KUNIT_EXPECT_TRUE(test, ok);
+	KUNIT_ASSERT_EQ(test, fake_i2c_cap.num, 1);
+	/* write => flags without I2C_M_RD */
+	KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[0].flags, 0);
+	KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[0].addr, 0x3a);
+	KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[0].len, (int)sizeof(data));
+	KUNIT_EXPECT_PTR_EQ(test, fake_i2c_cap.msgs[0].buf, (void *)data);
+}
+
+/**
+ * dm_test_lp_read_i2c_builds_offset_then_read - read builds offset + read msgs
+ * @test: KUnit test context
+ *
+ * lp_read_i2c() must build a 1-byte write of the offset followed by a
+ * size-byte read into the caller buffer, both at the same address.
+ */
+static void dm_test_lp_read_i2c_builds_offset_then_read(struct kunit *test)
+{
+	struct dc_link *link = alloc_test_ddc_link(test);
+	u8 data[4];
+	bool ok;
+
+	memset(&fake_i2c_cap, 0, sizeof(fake_i2c_cap));
+
+	ok = lp_read_i2c(link, 0x50, 0x07, data, sizeof(data));
+
+	KUNIT_EXPECT_TRUE(test, ok);
+	KUNIT_ASSERT_EQ(test, fake_i2c_cap.num, 2);
+	/* first: 1-byte write of the offset */
+	KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[0].flags, 0);
+	KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[0].addr, 0x50);
+	KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[0].len, 1);
+	/* second: size-byte read into the caller buffer */
+	KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[1].flags, I2C_M_RD);
+	KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[1].addr, 0x50);
+	KUNIT_EXPECT_EQ(test, (int)fake_i2c_cap.msgs[1].len, (int)sizeof(data));
+	KUNIT_EXPECT_PTR_EQ(test, fake_i2c_cap.msgs[1].buf, (void *)data);
+}
+
+/**
+ * dm_test_lp_write_dpcd_forwards_native_write - write forwards a native write
+ * @test: KUnit test context
+ *
+ * lp_write_dpcd() must issue a single DP_AUX_NATIVE_WRITE at the requested
+ * address for the requested size.
+ */
+static void dm_test_lp_write_dpcd_forwards_native_write(struct kunit *test)
+{
+	struct dc_link *link = alloc_test_ddc_link(test);
+	u8 data[2] = {0xDE, 0xAD};
+	bool ok;
+
+	memset(&fake_aux_cap, 0, sizeof(fake_aux_cap));
+
+	ok = lp_write_dpcd(link, 0x68000, data, sizeof(data));
+
+	KUNIT_EXPECT_TRUE(test, ok);
+	KUNIT_EXPECT_EQ(test, fake_aux_cap.calls, 1);
+	KUNIT_EXPECT_EQ(test, (int)fake_aux_cap.request, DP_AUX_NATIVE_WRITE);
+	KUNIT_EXPECT_EQ(test, fake_aux_cap.address, 0x68000u);
+	KUNIT_EXPECT_EQ(test, (int)fake_aux_cap.size, (int)sizeof(data));
+}
+
+/**
+ * dm_test_lp_read_dpcd_forwards_native_read - read forwards a native read
+ * @test: KUnit test context
+ *
+ * lp_read_dpcd() must issue a single DP_AUX_NATIVE_READ at the requested
+ * address for the requested size.
+ */
+static void dm_test_lp_read_dpcd_forwards_native_read(struct kunit *test)
+{
+	struct dc_link *link = alloc_test_ddc_link(test);
+	u8 data[4];
+	bool ok;
+
+	memset(&fake_aux_cap, 0, sizeof(fake_aux_cap));
+
+	ok = lp_read_dpcd(link, 0x00220, data, sizeof(data));
+
+	KUNIT_EXPECT_TRUE(test, ok);
+	KUNIT_EXPECT_EQ(test, fake_aux_cap.calls, 1);
+	KUNIT_EXPECT_EQ(test, (int)fake_aux_cap.request, DP_AUX_NATIVE_READ);
+	KUNIT_EXPECT_EQ(test, fake_aux_cap.address, 0x00220u);
+	KUNIT_EXPECT_EQ(test, (int)fake_aux_cap.size, (int)sizeof(data));
+}
+
+/**
+ * dm_test_lp_write_i2c_no_connector_returns_false - missing connector fails
+ * @test: KUnit test context
+ *
+ * When link->priv has no connector, dm_helpers_submit_i2c() cannot proceed,
+ * so lp_write_i2c() must report failure without invoking the adapter.
+ */
+static void dm_test_lp_write_i2c_no_connector_returns_false(struct kunit *test)
+{
+	struct dc_link *link = alloc_test_ddc_link(test);
+	u8 data[2] = {0x01, 0x02};
+	bool ok;
+
+	link->priv = NULL;
+	memset(&fake_i2c_cap, 0, sizeof(fake_i2c_cap));
+
+	ok = lp_write_i2c(link, 0x3a, data, sizeof(data));
+
+	KUNIT_EXPECT_FALSE(test, ok);
+	KUNIT_EXPECT_EQ(test, fake_i2c_cap.num, 0);
+}
+
+/**
+ * dm_test_lp_read_dpcd_no_connector_returns_false - missing connector fails
+ * @test: KUnit test context
+ *
+ * When link->priv has no connector, dm_helpers_dp_read_dpcd() cannot proceed,
+ * so lp_read_dpcd() must report failure without invoking the aux transfer.
+ */
+static void dm_test_lp_read_dpcd_no_connector_returns_false(struct kunit *test)
+{
+	struct dc_link *link = alloc_test_ddc_link(test);
+	u8 data[4];
+	bool ok;
+
+	link->priv = NULL;
+	memset(&fake_aux_cap, 0, sizeof(fake_aux_cap));
+
+	ok = lp_read_dpcd(link, 0x00220, data, sizeof(data));
+
+	KUNIT_EXPECT_FALSE(test, ok);
+	KUNIT_EXPECT_EQ(test, fake_aux_cap.calls, 0);
+}
+
+/* End of tests for lp_write_i2c() / lp_read_i2c() / lp_write_dpcd() / lp_read_dpcd() */
+
+/*
+ * Tests for lp_atomic_write_poll_read_i2c() / lp_atomic_write_poll_read_aux()
+ *
+ * These wrappers cast the opaque handle to a dc_link and forward to the
+ * dc_fused_io helpers. The success path submits a fused-IO command sequence to
+ * the DMCUB, which is out of reach for a unit test, so the coverage here is the
+ * hardware-free early returns: a NULL link and a payload that fails conversion
+ * (op size larger than the fused request buffer).
+ */
+
+/**
+ * dm_test_lp_atomic_i2c_null_handle_returns_false - NULL link fails cleanly
+ * @test: KUnit test context
+ *
+ * With a NULL handle the forwarded dc_link is NULL, so the helper must return
+ * false without dereferencing anything.
+ */
+static void dm_test_lp_atomic_i2c_null_handle_returns_false(struct kunit *test)
+{
+	struct mod_hdcp_atomic_op_i2c op = { 0 };
+
+	KUNIT_EXPECT_FALSE(test,
+			   lp_atomic_write_poll_read_i2c(NULL, &op, &op, &op, 0, 0));
+}
+
+/**
+ * dm_test_lp_atomic_i2c_oversized_op_returns_false - bad payload fails conversion
+ * @test: KUnit test context
+ *
+ * An op whose size exceeds the fused request buffer must fail conversion, so
+ * the helper returns false before any fused-IO submission. no_ddc_pin routes
+ * the DDC line through aux_hw_inst, avoiding the GPIO pin dereference.
+ */
+static void dm_test_lp_atomic_i2c_oversized_op_returns_false(struct kunit *test)
+{
+	struct amdgpu_dm_connector *aconnector = alloc_test_connector(test, 0);
+	struct mod_hdcp_atomic_op_i2c write = { .size = 0x100 };
+	struct mod_hdcp_atomic_op_i2c op = { 0 };
+	struct dc_link *link;
+
+	KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+	link = aconnector->dc_link;
+	link->no_ddc_pin = true;
+
+	KUNIT_EXPECT_FALSE(test,
+			   lp_atomic_write_poll_read_i2c(link, &write, &op, &op, 0, 0));
+}
+
+/**
+ * dm_test_lp_atomic_aux_null_handle_returns_false - NULL link fails cleanly
+ * @test: KUnit test context
+ *
+ * With a NULL handle the forwarded dc_link is NULL, so the helper must return
+ * false without dereferencing anything.
+ */
+static void dm_test_lp_atomic_aux_null_handle_returns_false(struct kunit *test)
+{
+	struct mod_hdcp_atomic_op_aux op = { 0 };
+
+	KUNIT_EXPECT_FALSE(test,
+			   lp_atomic_write_poll_read_aux(NULL, &op, &op, &op, 0, 0));
+}
+
+/**
+ * dm_test_lp_atomic_aux_oversized_op_returns_false - bad payload fails conversion
+ * @test: KUnit test context
+ *
+ * The aux helper reads the DDC line from link->ddc->ddc_pin->pin_data before
+ * converting, so a minimal pin chain is wired up. An op larger than the fused
+ * request buffer then fails conversion and the helper returns false without
+ * any fused-IO submission.
+ */
+static void dm_test_lp_atomic_aux_oversized_op_returns_false(struct kunit *test)
+{
+	struct amdgpu_dm_connector *aconnector = alloc_test_connector(test, 0);
+	struct mod_hdcp_atomic_op_aux write = { .size = 0x100 };
+	struct mod_hdcp_atomic_op_aux op = { 0 };
+	struct ddc_service *ddc;
+	struct ddc *ddc_pin;
+	struct dc_link *link;
+	void *pin_data;
+
+	KUNIT_ASSERT_NOT_NULL(test, aconnector);
+
+	ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ddc);
+	ddc_pin = kunit_kzalloc(test, sizeof(*ddc_pin), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, ddc_pin);
+	/* Only ->en is read; over-allocate so struct gpio stays opaque here. */
+	pin_data = kunit_kzalloc(test, 128, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, pin_data);
+
+	ddc_pin->pin_data = pin_data;
+	ddc->ddc_pin = ddc_pin;
+
+	link = aconnector->dc_link;
+	link->ddc = ddc;
+
+	KUNIT_EXPECT_FALSE(test,
+			   lp_atomic_write_poll_read_aux(link, &write, &op, &op, 0, 0));
+}
+
+/* End of tests for lp_atomic_write_poll_read_i2c() / lp_atomic_write_poll_read_aux() */
+
 /*
  * Tests for hdcp_update_display() / hdcp_remove_display() /
  * hdcp_reset_display().
@@ -1994,6 +2360,18 @@ static struct kunit_case dm_hdcp_test_cases[] = {
 	KUNIT_CASE(dm_test_srm_data_write_uninitialized_ta_keeps_srm),
 	KUNIT_CASE(dm_test_srm_data_read_uninitialized_ta_returns_einval),
 	KUNIT_CASE(dm_test_srm_data_read_empty_srm_returns_zero),
+	/* lp_write_i2c() / lp_read_i2c() / lp_write_dpcd() / lp_read_dpcd() */
+	KUNIT_CASE(dm_test_lp_write_i2c_builds_single_write_payload),
+	KUNIT_CASE(dm_test_lp_read_i2c_builds_offset_then_read),
+	KUNIT_CASE(dm_test_lp_write_dpcd_forwards_native_write),
+	KUNIT_CASE(dm_test_lp_read_dpcd_forwards_native_read),
+	KUNIT_CASE(dm_test_lp_write_i2c_no_connector_returns_false),
+	KUNIT_CASE(dm_test_lp_read_dpcd_no_connector_returns_false),
+	/* lp_atomic_write_poll_read_i2c() / lp_atomic_write_poll_read_aux() */
+	KUNIT_CASE(dm_test_lp_atomic_i2c_null_handle_returns_false),
+	KUNIT_CASE(dm_test_lp_atomic_i2c_oversized_op_returns_false),
+	KUNIT_CASE(dm_test_lp_atomic_aux_null_handle_returns_false),
+	KUNIT_CASE(dm_test_lp_atomic_aux_oversized_op_returns_false),
 	/* hdcp_update_display() / hdcp_remove_display() / hdcp_reset_display() */
 	KUNIT_CASE(dm_test_hdcp_update_display_enable_registers_connector),
 	KUNIT_CASE(dm_test_hdcp_update_display_disable_sets_status_off),
-- 
2.53.0


  parent reply	other threads:[~2026-07-23 20:19 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-23 20:13 [PATCH 00/49] DC Patches July 20th, 2026 Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 01/49] drm/amd/display: share common DM KUnit helpers Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 02/49] drm/amd/display: Port DCN4+ MCIF ARB programming to new format Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 03/49] drm/amd/display: Fix force FRL rate debug setting Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 04/49] drm/amd/display: Add KUnit tests for link_lock and psp SRM helpers Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 05/49] drm/amd/display: Add KUnit tests for HDCP display helpers Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 06/49] drm/amd/display: Add KUnit tests for event_callback Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 07/49] drm/amd/display: Add KUnit tests for event_property_validate Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 08/49] drm/amd/display: Add KUnit tests for watchdog and cpirq events Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 09/49] drm/amd/display: Add KUnit tests for hdcp_destroy Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 10/49] drm/amd/display: Add AV mute wait frames to dce110_set_avmute Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 11/49] drm/amd/display: revert "convert dcn42 GPIO translation to lookup tables" Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 12/49] drm/amd/display: move scaling helper to connector Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 13/49] drm/amd/display: move stutter quirk to quirks file Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 14/49] drm/amd/display: move watermarks table to pp_smu Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 15/49] drm/amd/display: move GPU mem helpers to services Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 16/49] drm/amd/display: add FreeSync/VRR module Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 17/49] drm/amd/display: add cursor module Fangzhi Zuo
2026-08-03 12:48   ` Timur Kristóf
2026-07-23 20:13 ` [PATCH 18/49] drm/amd/display: add KUnit tests for audio component get_eld Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 19/49] drm/amd/display: add KUnit tests for audio commit path Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 20/49] drm/amd/display: Use current mpc pipe in set output transfer func Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 21/49] drm/amd/display: Correct vblank_end calc for fams cmd packet Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 22/49] drm/amd/display: Add KUnit test for native backlight registration Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 23/49] drm/amd/display: Add color transfer-function tests Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 24/49] drm/amd/display: Add atomic " Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 25/49] drm/amd/display: Add CRTC and plane degamma tests Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 26/49] drm/amd/display: Add legacy plane LUT tests Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 27/49] drm/amd/display: Add truncated colorop tests Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 28/49] drm/amd/display: Add colorop LUT programming tests Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 29/49] drm/amd/display: Add KUnit tests for enable_assr Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 30/49] drm/amd/display: Add KUnit tests for update_config Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 31/49] drm/amd/display: Add KUnit tests for hdcp_create_workqueue Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 32/49] drm/amd/display: Add KUnit tests for srm_data_write and srm_data_read Fangzhi Zuo
2026-07-23 20:13 ` Fangzhi Zuo [this message]
2026-07-23 20:13 ` [PATCH 34/49] drm/amd/display: Add initialized-branch test for psp_set_srm Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 35/49] drm/amd/display: Add deeper event_property_update tests Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 36/49] drm/amd/display: adjust floating point format for gamut remap when needed Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 37/49] drm/amd/display: Reintroduce "convert dcn42 GPIO translation to lookup tables" Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 38/49] drm/amd/display: Prune per-tile Timing from Apple Studio Display Primary Tile Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 39/49] drm/amd/display: Add get replay residency function Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 40/49] drm/amd/display: Fix divide-by-zero in calculate_mcache_setting on zero viewport Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 41/49] drm/amd/display: check if dml21_add_phantom_plane() is successful Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 42/49] drm/amd/display: change dcc_rate from 1 to 2 for log use only Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 43/49] drm/amd/display: enforce UCLK pstate support in mode_support Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 44/49] drm/amd/display: add DalForceMaxDisplayClock debug option to DML2 Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 45/49] drm/amd/display: Fixes for dcn42b_soc_bb.h Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 46/49] drm/amd/display: Fix rounding errors in CalculatePrefetchSchedule Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 47/49] drm/amd/display: plumb PMO per-plane pstate methods into mode_support Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 48/49] drm/amd/display: dispatch compressed FRL cap check inside dml1_frl_cap_chk_inter Fangzhi Zuo
2026-07-23 20:13 ` [PATCH 49/49] drm/amd/display: Promote DC to 3.2.391 Fangzhi Zuo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260723201908.373300-34-jerry.zuo@amd.com \
    --to=jerry.zuo@amd.com \
    --cc=Chen-Yu.Chen@amd.com \
    --cc=PingLei.Lin@amd.com \
    --cc=Ray.Wu@amd.com \
    --cc=alex.hung@amd.com \
    --cc=amd-gfx@lists.freedesktop.org \
    --cc=aurabindo.pillai@amd.com \
    --cc=bhawanpreet.lakha@amd.com \
    --cc=chiahsuan.chung@amd.com \
    --cc=daniel.wheeler@amd.com \
    --cc=harry.wentland@amd.com \
    --cc=ivan.lipski@amd.com \
    --cc=roman.li@amd.com \
    --cc=sunpeng.li@amd.com \
    --cc=wayne.lin@amd.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.