Leave only a scaled mode in connector->modes and put the larger native mode in the encoder, as a size-limited probe does. On eDP and LVDS, create_stream_for_sink() must build a stream with the native timing and the scaled mode as its source size. On HDMI it must keep the first mode in the list as the timing
Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Hugo Sales <[email protected]> --- .../tests/amdgpu_dm_connector_test.c | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c index 56fd133bc..55e2c3849 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c @@ -4547,6 +4547,115 @@ static void dm_test_create_stream_hdmi_vsif(struct kunit *test) dc_sink_release(sink); } +/* + * Build a stream after a probe with size limits below the native mode, such as + * fbdev emulation's. That probe leaves only a 1920x1200 scaled mode in the + * connector's mode list, while the encoder keeps the 3840x2400 native mode + */ +static struct dc_stream_state * +dm_test_native_mode_pruned_stream(struct kunit *test, int connector_type) +{ + static const u8 edid[EDID_LENGTH]; + struct dm_test_stream_ctx *ctx = dm_test_stream_ctx_alloc(test); + struct amdgpu_encoder *aenc; + struct dc_stream_state *stream; + struct drm_display_mode *native; + + ctx->aconnector->base.connector_type = connector_type; + + aenc = drmm_kzalloc(ctx->drm, sizeof(*aenc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aenc); + KUNIT_ASSERT_EQ(test, drmm_encoder_init(ctx->drm, &aenc->base, NULL, + DRM_MODE_ENCODER_TMDS, NULL), 0); + KUNIT_ASSERT_EQ(test, drm_connector_attach_encoder(&ctx->aconnector->base, &aenc->base), 0); + + native = &aenc->native_mode; + native->clock = 592500; + native->hdisplay = 3840; + native->hsync_start = 3888; + native->hsync_end = 3920; + native->htotal = 4000; + native->vdisplay = 2400; + native->vsync_start = 2403; + native->vsync_end = 2409; + native->vtotal = 2469; + /* Cached by the first, unlimited probe */ + drm_mode_copy(&ctx->aconnector->freesync_vid_base, native); + + drm_mode_copy(ctx->mode, native); + ctx->mode->hdisplay = 1920; + ctx->mode->vdisplay = 1200; + drm_mode_set_crtcinfo(ctx->mode, CRTC_INTERLACE_HALVE_V); + dm_test_stream_add_mode(test, ctx, 0); + ctx->dm_state->scaling = RMX_FULL; + + ctx->aconnector->drm_edid = drm_edid_alloc(edid, sizeof(edid)); + KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector->drm_edid); + + stream = create_stream_for_sink(&ctx->aconnector->base, ctx->mode, + ctx->dm_state, NULL, 8, + PIXEL_ENCODING_RGB, false); + + drm_edid_free(ctx->aconnector->drm_edid); + KUNIT_ASSERT_NOT_NULL(test, stream); + + return stream; +} + +/** + * dm_test_create_stream_native_mode_pruned_edp - Test eDP gets native timing + * @test: The KUnit test context + * + * The scaled mode must still be driven with the panel's native timing, kept in + * the encoder + */ +static void dm_test_create_stream_native_mode_pruned_edp(struct kunit *test) +{ + struct dc_stream_state *stream = + dm_test_native_mode_pruned_stream(test, DRM_MODE_CONNECTOR_eDP); + + KUNIT_EXPECT_EQ(test, (int)stream->timing.h_addressable, 3840); + KUNIT_EXPECT_EQ(test, (int)stream->timing.v_addressable, 2400); + KUNIT_EXPECT_EQ(test, (int)stream->src.width, 1920); + KUNIT_EXPECT_EQ(test, (int)stream->src.height, 1200); + dc_stream_release(stream); +} + +/** + * dm_test_create_stream_native_mode_pruned_lvds - Test LVDS gets native timing + * @test: The KUnit test context + */ +static void dm_test_create_stream_native_mode_pruned_lvds(struct kunit *test) +{ + struct dc_stream_state *stream = + dm_test_native_mode_pruned_stream(test, DRM_MODE_CONNECTOR_LVDS); + + KUNIT_EXPECT_EQ(test, (int)stream->timing.h_addressable, 3840); + KUNIT_EXPECT_EQ(test, (int)stream->timing.v_addressable, 2400); + KUNIT_EXPECT_EQ(test, (int)stream->src.width, 1920); + KUNIT_EXPECT_EQ(test, (int)stream->src.height, 1200); + dc_stream_release(stream); +} + +/** + * dm_test_create_stream_native_mode_pruned_hdmi - Test HDMI uses the first mode + * @test: The KUnit test context + * + * On a connector that is not a panel, mode_valid may have dropped the native + * mode, so the first mode left in the list must drive the timing + */ +static void dm_test_create_stream_native_mode_pruned_hdmi(struct kunit *test) +{ + struct dc_stream_state *stream = + dm_test_native_mode_pruned_stream(test, DRM_MODE_CONNECTOR_HDMIA); + + KUNIT_EXPECT_EQ(test, (int)stream->timing.h_addressable, 1920); + KUNIT_EXPECT_EQ(test, (int)stream->timing.v_addressable, 1200); + KUNIT_EXPECT_EQ(test, (int)stream->src.width, 1920); + KUNIT_EXPECT_EQ(test, (int)stream->src.height, 1200); + dc_stream_release(stream); +} + /* Tests for amdgpu_dm_connector_detect() */ /* @@ -10246,6 +10355,9 @@ static struct kunit_case amdgpu_dm_connector_tests[] = { KUNIT_CASE(dm_test_create_stream_dp_vsc_colorimetry), KUNIT_CASE(dm_test_create_stream_dp_colorimetry_quirk), KUNIT_CASE(dm_test_create_stream_hdmi_vsif), + KUNIT_CASE(dm_test_create_stream_native_mode_pruned_edp), + KUNIT_CASE(dm_test_create_stream_native_mode_pruned_lvds), + KUNIT_CASE(dm_test_create_stream_native_mode_pruned_hdmi), /* amdgpu_dm_connector_detect */ KUNIT_CASE(dm_test_detect_force_on), KUNIT_CASE(dm_test_detect_force_on_digital), -- 2.55.0
