diff options
Diffstat (limited to 'drivers/gpu/drm/vkms')
22 files changed, 2600 insertions, 132 deletions
diff --git a/drivers/gpu/drm/vkms/Kconfig b/drivers/gpu/drm/vkms/Kconfig index 3c02f928ffe6..3977bbb99f7d 100644 --- a/drivers/gpu/drm/vkms/Kconfig +++ b/drivers/gpu/drm/vkms/Kconfig @@ -7,6 +7,7 @@ config DRM_VKMS select DRM_KMS_HELPER select DRM_GEM_SHMEM_HELPER select CRC32 + select CONFIGFS_FS default n help Virtual Kernel Mode-Setting (VKMS) is used for testing or for diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile index d657865e573f..9bb264091c38 100644 --- a/drivers/gpu/drm/vkms/Makefile +++ b/drivers/gpu/drm/vkms/Makefile @@ -8,7 +8,10 @@ vkms-y := \ vkms_composer.o \ vkms_writeback.o \ vkms_connector.o \ - vkms_config.o + vkms_config.o \ + vkms_configfs.o \ + vkms_colorop.o \ + vkms_luts.o obj-$(CONFIG_DRM_VKMS) += vkms.o obj-$(CONFIG_DRM_VKMS_KUNIT_TEST) += tests/ diff --git a/drivers/gpu/drm/vkms/tests/Makefile b/drivers/gpu/drm/vkms/tests/Makefile index 5750f0bd9d40..d4d9ba8d4c54 100644 --- a/drivers/gpu/drm/vkms/tests/Makefile +++ b/drivers/gpu/drm/vkms/tests/Makefile @@ -2,6 +2,7 @@ vkms-kunit-tests-y := \ vkms_config_test.o \ - vkms_format_test.o + vkms_format_test.o \ + vkms_color_test.o obj-$(CONFIG_DRM_VKMS_KUNIT_TEST) += vkms-kunit-tests.o diff --git a/drivers/gpu/drm/vkms/tests/vkms_color_test.c b/drivers/gpu/drm/vkms/tests/vkms_color_test.c new file mode 100644 index 000000000000..1a1c7cac2f15 --- /dev/null +++ b/drivers/gpu/drm/vkms/tests/vkms_color_test.c @@ -0,0 +1,414 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <kunit/test.h> + +#include <drm/drm_fixed.h> +#include <drm/drm_mode.h> +#include "../vkms_composer.h" +#include "../vkms_drv.h" +#include "../vkms_luts.h" + +#define TEST_LUT_SIZE 16 + +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); + +static struct drm_color_lut test_linear_array[TEST_LUT_SIZE] = { + { 0x0, 0x0, 0x0, 0 }, + { 0x1111, 0x1111, 0x1111, 0 }, + { 0x2222, 0x2222, 0x2222, 0 }, + { 0x3333, 0x3333, 0x3333, 0 }, + { 0x4444, 0x4444, 0x4444, 0 }, + { 0x5555, 0x5555, 0x5555, 0 }, + { 0x6666, 0x6666, 0x6666, 0 }, + { 0x7777, 0x7777, 0x7777, 0 }, + { 0x8888, 0x8888, 0x8888, 0 }, + { 0x9999, 0x9999, 0x9999, 0 }, + { 0xaaaa, 0xaaaa, 0xaaaa, 0 }, + { 0xbbbb, 0xbbbb, 0xbbbb, 0 }, + { 0xcccc, 0xcccc, 0xcccc, 0 }, + { 0xdddd, 0xdddd, 0xdddd, 0 }, + { 0xeeee, 0xeeee, 0xeeee, 0 }, + { 0xffff, 0xffff, 0xffff, 0 }, +}; + +/* lerp test parameters */ +struct vkms_color_test_lerp_params { + s64 t; + __u16 a; + __u16 b; + __u16 expected; +}; + +/* lerp test cases */ +static const struct vkms_color_test_lerp_params color_test_lerp_cases[] = { + /* Half-way round down */ + { 0x80000000 - 1, 0x0, 0x10, 0x8 }, + { 0x80000000 - 1, 0x1, 0x10, 0x8 }, /* Odd a */ + { 0x80000000 - 1, 0x1, 0xf, 0x8 }, /* Odd b */ + { 0x80000000 - 1, 0x10, 0x10, 0x10 }, /* b = a */ + { 0x80000000 - 1, 0x10, 0x11, 0x10 }, /* b = a + 1*/ + /* Half-way round up */ + { 0x80000000, 0x0, 0x10, 0x8 }, + { 0x80000000, 0x1, 0x10, 0x9 }, /* Odd a */ + { 0x80000000, 0x1, 0xf, 0x8 }, /* Odd b */ + { 0x80000000, 0x10, 0x10, 0x10 }, /* b = a */ + { 0x80000000, 0x10, 0x11, 0x11 }, /* b = a + 1*/ + /* t = 0.0 */ + { 0x0, 0x0, 0x10, 0x0 }, + { 0x0, 0x1, 0x10, 0x1 }, /* Odd a */ + { 0x0, 0x1, 0xf, 0x1 }, /* Odd b */ + { 0x0, 0x10, 0x10, 0x10 }, /* b = a */ + { 0x0, 0x10, 0x11, 0x10 }, /* b = a + 1*/ + /* t = 1.0 */ + { 0x100000000, 0x0, 0x10, 0x10 }, + { 0x100000000, 0x1, 0x10, 0x10 }, /* Odd a */ + { 0x100000000, 0x1, 0xf, 0xf }, /* Odd b */ + { 0x100000000, 0x10, 0x10, 0x10 }, /* b = a */ + { 0x100000000, 0x10, 0x11, 0x11 }, /* b = a + 1*/ + /* t = 0.0 + 1 */ + { 0x0 + 1, 0x0, 0x10, 0x0 }, + { 0x0 + 1, 0x1, 0x10, 0x1 }, /* Odd a */ + { 0x0 + 1, 0x1, 0xf, 0x1 }, /* Odd b */ + { 0x0 + 1, 0x10, 0x10, 0x10 }, /* b = a */ + { 0x0 + 1, 0x10, 0x11, 0x10 }, /* b = a + 1*/ + /* t = 1.0 - 1 */ + { 0x100000000 - 1, 0x0, 0x10, 0x10 }, + { 0x100000000 - 1, 0x1, 0x10, 0x10 }, /* Odd a */ + { 0x100000000 - 1, 0x1, 0xf, 0xf }, /* Odd b */ + { 0x100000000 - 1, 0x10, 0x10, 0x10 }, /* b = a */ + { 0x100000000 - 1, 0x10, 0x11, 0x11 }, /* b = a + 1*/ + /* t chosen to verify the flipping point of result a (or b) to a+1 (or b-1) */ + { 0x80000000 - 1, 0x0, 0x1, 0x0 }, + { 0x80000000, 0x0, 0x1, 0x1 }, +}; + +static const struct vkms_color_lut test_linear_lut = { + .base = test_linear_array, + .lut_length = TEST_LUT_SIZE, + .channel_value2index_ratio = 0xf000fll +}; + +static void vkms_color_test_get_lut_index(struct kunit *test) +{ + s64 lut_index; + int i; + + lut_index = get_lut_index(&test_linear_lut, test_linear_array[0].red); + KUNIT_EXPECT_EQ(test, drm_fixp2int(lut_index), 0); + + for (i = 0; i < TEST_LUT_SIZE; i++) { + lut_index = get_lut_index(&test_linear_lut, test_linear_array[i].red); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(lut_index), i); + } + + KUNIT_EXPECT_EQ(test, drm_fixp2int(get_lut_index(&srgb_eotf, 0x0)), 0x0); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_eotf, 0x0)), 0x0); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_eotf, 0x101)), 0x1); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_eotf, 0x202)), 0x2); + + KUNIT_EXPECT_EQ(test, drm_fixp2int(get_lut_index(&srgb_inv_eotf, 0x0)), 0x0); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_inv_eotf, 0x0)), 0x0); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_inv_eotf, 0x101)), 0x1); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_inv_eotf, 0x202)), 0x2); + + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_eotf, 0xfefe)), 0xfe); + KUNIT_EXPECT_EQ(test, drm_fixp2int_ceil(get_lut_index(&srgb_eotf, 0xffff)), 0xff); +} + +static void vkms_color_test_lerp(struct kunit *test) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(color_test_lerp_cases); i++) { + const struct vkms_color_test_lerp_params *params = &color_test_lerp_cases[i]; + + KUNIT_EXPECT_EQ(test, lerp_u16(params->a, params->b, params->t), params->expected); + } +} + +static void vkms_color_test_linear(struct kunit *test) +{ + for (int i = 0; i < LUT_SIZE; i++) { + int linear = apply_lut_to_channel_value(&linear_eotf, i * 0x101, LUT_RED); + + KUNIT_EXPECT_EQ(test, DIV_ROUND_CLOSEST(linear, 0x101), i); + } +} + +static void vkms_color_srgb_inv_srgb(struct kunit *test) +{ + u16 srgb, final; + + for (int i = 0; i < LUT_SIZE; i++) { + srgb = apply_lut_to_channel_value(&srgb_eotf, i * 0x101, LUT_RED); + final = apply_lut_to_channel_value(&srgb_inv_eotf, srgb, LUT_RED); + + KUNIT_EXPECT_GE(test, final / 0x101, i - 1); + KUNIT_EXPECT_LE(test, final / 0x101, i + 1); + } +} + +#define FIXPT_HALF (DRM_FIXED_ONE >> 1) +#define FIXPT_QUARTER (DRM_FIXED_ONE >> 2) + +static const struct drm_color_ctm_3x4 test_matrix_3x4_50_desat = { { + FIXPT_HALF, FIXPT_QUARTER, FIXPT_QUARTER, 0, + FIXPT_QUARTER, FIXPT_HALF, FIXPT_QUARTER, 0, + FIXPT_QUARTER, FIXPT_QUARTER, FIXPT_HALF, 0 +} }; + +static void vkms_color_ctm_3x4_50_desat(struct kunit *test) +{ + struct pixel_argb_s32 ref, out; + + /* full white */ + ref.a = 0xffff; + ref.r = 0xffff; + ref.g = 0xffff; + ref.b = 0xffff; + + memcpy(&out, &ref, sizeof(out)); + apply_3x4_matrix(&out, &test_matrix_3x4_50_desat); + + KUNIT_EXPECT_MEMEQ(test, &ref, &out, sizeof(out)); + + /* full black */ + ref.a = 0xffff; + ref.r = 0x0; + ref.g = 0x0; + ref.b = 0x0; + + memcpy(&out, &ref, sizeof(out)); + apply_3x4_matrix(&out, &test_matrix_3x4_50_desat); + + KUNIT_EXPECT_MEMEQ(test, &ref, &out, sizeof(out)); + + /* 50% grey */ + ref.a = 0xffff; + ref.r = 0x8000; + ref.g = 0x8000; + ref.b = 0x8000; + + memcpy(&out, &ref, sizeof(out)); + apply_3x4_matrix(&out, &test_matrix_3x4_50_desat); + + KUNIT_EXPECT_MEMEQ(test, &ref, &out, sizeof(out)); + + /* full red to 50% desat */ + ref.a = 0xffff; + ref.r = 0x8000; + ref.g = 0x4000; + ref.b = 0x4000; + + out.a = 0xffff; + out.r = 0xffff; + out.g = 0x0; + out.b = 0x0; + + apply_3x4_matrix(&out, &test_matrix_3x4_50_desat); + + KUNIT_EXPECT_MEMEQ(test, &ref, &out, sizeof(out)); +} + +/* + * BT.709 encoding matrix + * + * Values printed from within IGT when converting + * igt_matrix_3x4_bt709_enc to the fixed-point format expected + * by DRM/KMS. + */ +static const struct drm_color_ctm_3x4 test_matrix_3x4_bt709_enc = { { + 0x00000000366cf400ull, 0x00000000b7175900ull, 0x0000000127bb300ull, 0, + 0x800000001993b3a0ull, 0x800000005609fe80ull, 0x000000006f9db200ull, 0, + 0x000000009d70a400ull, 0x800000008f011100ull, 0x800000000e6f9330ull, 0 +} }; + +static void vkms_color_ctm_3x4_bt709(struct kunit *test) +{ + struct pixel_argb_s32 out; + + /* full white to bt709 */ + out.a = 0xffff; + out.r = 0xffff; + out.g = 0xffff; + out.b = 0xffff; + + apply_3x4_matrix(&out, &test_matrix_3x4_bt709_enc); + + /* Y 255 */ + KUNIT_EXPECT_GT(test, out.r, 0xfe00); + KUNIT_EXPECT_LT(test, out.r, 0x10000); + + /* U 0 */ + KUNIT_EXPECT_LT(test, out.g, 0x0100); + + /* V 0 */ + KUNIT_EXPECT_LT(test, out.b, 0x0100); + + /* full black to bt709 */ + out.a = 0xffff; + out.r = 0x0; + out.g = 0x0; + out.b = 0x0; + + apply_3x4_matrix(&out, &test_matrix_3x4_bt709_enc); + + /* Y 0 */ + KUNIT_EXPECT_LT(test, out.r, 0x100); + + /* U 0 */ + KUNIT_EXPECT_LT(test, out.g, 0x0100); + + /* V 0 */ + KUNIT_EXPECT_LT(test, out.b, 0x0100); + + /* gray to bt709 */ + out.a = 0xffff; + out.r = 0x7fff; + out.g = 0x7fff; + out.b = 0x7fff; + + apply_3x4_matrix(&out, &test_matrix_3x4_bt709_enc); + + /* Y 127 */ + KUNIT_EXPECT_GT(test, out.r, 0x7e00); + KUNIT_EXPECT_LT(test, out.r, 0x8000); + + /* U 0 */ + KUNIT_EXPECT_LT(test, out.g, 0x0100); + + /* V 0 */ + KUNIT_EXPECT_LT(test, out.b, 0x0100); + + /* == red 255 - bt709 enc == */ + out.a = 0xffff; + out.r = 0xffff; + out.g = 0x0; + out.b = 0x0; + + apply_3x4_matrix(&out, &test_matrix_3x4_bt709_enc); + + /* Y 54 */ + KUNIT_EXPECT_GT(test, out.r, 0x3500); + KUNIT_EXPECT_LT(test, out.r, 0x3700); + + /* U 0 */ + KUNIT_EXPECT_LT(test, out.g, 0x0100); + + /* V 157 */ + KUNIT_EXPECT_GT(test, out.b, 0x9C00); + KUNIT_EXPECT_LT(test, out.b, 0x9E00); + + /* == green 255 - bt709 enc == */ + out.a = 0xffff; + out.r = 0x0; + out.g = 0xffff; + out.b = 0x0; + + apply_3x4_matrix(&out, &test_matrix_3x4_bt709_enc); + + /* Y 182 */ + KUNIT_EXPECT_GT(test, out.r, 0xB500); + KUNIT_EXPECT_LT(test, out.r, 0xB780); /* laxed by half*/ + + /* U 0 */ + KUNIT_EXPECT_LT(test, out.g, 0x0100); + + /* V 0 */ + KUNIT_EXPECT_LT(test, out.b, 0x0100); + + /* == blue 255 - bt709 enc == */ + out.a = 0xffff; + out.r = 0x0; + out.g = 0x0; + out.b = 0xffff; + + apply_3x4_matrix(&out, &test_matrix_3x4_bt709_enc); + + /* Y 18 */ + KUNIT_EXPECT_GT(test, out.r, 0x1100); + KUNIT_EXPECT_LT(test, out.r, 0x1300); + + /* U 111 */ + KUNIT_EXPECT_GT(test, out.g, 0x6E00); + KUNIT_EXPECT_LT(test, out.g, 0x7000); + + /* V 0 */ + KUNIT_EXPECT_LT(test, out.b, 0x0100); + + /* == red 140 - bt709 enc == */ + out.a = 0xffff; + out.r = 0x8c8c; + out.g = 0x0; + out.b = 0x0; + + apply_3x4_matrix(&out, &test_matrix_3x4_bt709_enc); + + /* Y 30 */ + KUNIT_EXPECT_GT(test, out.r, 0x1D00); + KUNIT_EXPECT_LT(test, out.r, 0x1F00); + + /* U 0 */ + KUNIT_EXPECT_LT(test, out.g, 0x100); + + /* V 87 */ + KUNIT_EXPECT_GT(test, out.b, 0x5600); + KUNIT_EXPECT_LT(test, out.b, 0x5800); + + /* == green 140 - bt709 enc == */ + out.a = 0xffff; + out.r = 0x0; + out.g = 0x8c8c; + out.b = 0x0; + + apply_3x4_matrix(&out, &test_matrix_3x4_bt709_enc); + + /* Y 30 */ + KUNIT_EXPECT_GT(test, out.r, 0x6400); + KUNIT_EXPECT_LT(test, out.r, 0x6600); + + /* U 0 */ + KUNIT_EXPECT_LT(test, out.g, 0x100); + + /* V 0 */ + KUNIT_EXPECT_LT(test, out.b, 0x100); + + /* == blue 140 - bt709 enc == */ + out.a = 0xffff; + out.r = 0x0; + out.g = 0x0; + out.b = 0x8c8c; + + apply_3x4_matrix(&out, &test_matrix_3x4_bt709_enc); + + /* Y 30 */ + KUNIT_EXPECT_GT(test, out.r, 0x900); + KUNIT_EXPECT_LT(test, out.r, 0xB00); + + /* U 61 */ + KUNIT_EXPECT_GT(test, out.g, 0x3C00); + KUNIT_EXPECT_LT(test, out.g, 0x3E00); + + /* V 0 */ + KUNIT_EXPECT_LT(test, out.b, 0x100); +} + +static struct kunit_case vkms_color_test_cases[] = { + KUNIT_CASE(vkms_color_test_get_lut_index), + KUNIT_CASE(vkms_color_test_lerp), + KUNIT_CASE(vkms_color_test_linear), + KUNIT_CASE(vkms_color_srgb_inv_srgb), + KUNIT_CASE(vkms_color_ctm_3x4_50_desat), + KUNIT_CASE(vkms_color_ctm_3x4_bt709), + {} +}; + +static struct kunit_suite vkms_color_test_suite = { + .name = "vkms-color", + .test_cases = vkms_color_test_cases, +}; + +kunit_test_suite(vkms_color_test_suite); + +MODULE_DESCRIPTION("Kunit test for VKMS LUT handling"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/vkms/tests/vkms_config_test.c b/drivers/gpu/drm/vkms/tests/vkms_config_test.c index b0d78a81d2df..1e4ea1863420 100644 --- a/drivers/gpu/drm/vkms/tests/vkms_config_test.c +++ b/drivers/gpu/drm/vkms/tests/vkms_config_test.c @@ -83,6 +83,7 @@ struct default_config_case { bool enable_cursor; bool enable_writeback; bool enable_overlay; + bool enable_plane_pipeline; }; static void vkms_config_test_empty_config(struct kunit *test) @@ -108,14 +109,22 @@ static void vkms_config_test_empty_config(struct kunit *test) } static struct default_config_case default_config_cases[] = { - { false, false, false }, - { true, false, false }, - { true, true, false }, - { true, false, true }, - { false, true, false }, - { false, true, true }, - { false, false, true }, - { true, true, true }, + { false, false, false, false }, + { true, false, false, false }, + { true, true, false, false }, + { true, false, true, false }, + { false, true, false, false }, + { false, true, true, false }, + { false, false, true, false }, + { true, true, true, false }, + { false, false, false, true }, + { true, false, false, true }, + { true, true, false, true }, + { true, false, true, true }, + { false, true, false, true }, + { false, true, true, true }, + { false, false, true, true }, + { true, true, true, true }, }; KUNIT_ARRAY_PARAM(default_config, default_config_cases, NULL); @@ -132,11 +141,15 @@ static void vkms_config_test_default_config(struct kunit *test) config = vkms_config_default_create(params->enable_cursor, params->enable_writeback, - params->enable_overlay); + params->enable_overlay, + params->enable_plane_pipeline); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); /* Planes */ vkms_config_for_each_plane(config, plane_cfg) { + KUNIT_EXPECT_EQ(test, + vkms_config_plane_get_default_pipeline(plane_cfg), + params->enable_plane_pipeline); switch (vkms_config_plane_get_type(plane_cfg)) { case DRM_PLANE_TYPE_PRIMARY: n_primaries++; @@ -368,7 +381,7 @@ static void vkms_config_test_invalid_plane_number(struct kunit *test) struct vkms_config_plane *plane_cfg; int n; - config = vkms_config_default_create(false, false, false); + config = vkms_config_default_create(false, false, false, false); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); /* Invalid: No planes */ @@ -393,7 +406,7 @@ static void vkms_config_test_valid_plane_type(struct kunit *test) struct vkms_config_encoder *encoder_cfg; int err; - config = vkms_config_default_create(false, false, false); + config = vkms_config_default_create(false, false, false, false); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); plane_cfg = get_first_plane(config); @@ -474,7 +487,7 @@ static void vkms_config_test_valid_plane_possible_crtcs(struct kunit *test) struct vkms_config_plane *plane_cfg; struct vkms_config_crtc *crtc_cfg; - config = vkms_config_default_create(false, false, false); + config = vkms_config_default_create(false, false, false, false); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); plane_cfg = get_first_plane(config); @@ -493,7 +506,7 @@ static void vkms_config_test_invalid_crtc_number(struct kunit *test) struct vkms_config_crtc *crtc_cfg; int n; - config = vkms_config_default_create(false, false, false); + config = vkms_config_default_create(false, false, false, false); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); /* Invalid: No CRTCs */ @@ -516,7 +529,7 @@ static void vkms_config_test_invalid_encoder_number(struct kunit *test) struct vkms_config_encoder *encoder_cfg; int n; - config = vkms_config_default_create(false, false, false); + config = vkms_config_default_create(false, false, false, false); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); /* Invalid: No encoders */ @@ -541,7 +554,7 @@ static void vkms_config_test_valid_encoder_possible_crtcs(struct kunit *test) struct vkms_config_encoder *encoder_cfg; int err; - config = vkms_config_default_create(false, false, false); + config = vkms_config_default_create(false, false, false, false); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); crtc_cfg1 = get_first_crtc(config); @@ -587,7 +600,7 @@ static void vkms_config_test_invalid_connector_number(struct kunit *test) struct vkms_config_connector *connector_cfg; int n; - config = vkms_config_default_create(false, false, false); + config = vkms_config_default_create(false, false, false, false); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); /* Invalid: No connectors */ @@ -610,7 +623,7 @@ static void vkms_config_test_valid_connector_possible_encoders(struct kunit *tes struct vkms_config_encoder *encoder_cfg; struct vkms_config_connector *connector_cfg; - config = vkms_config_default_create(false, false, false); + config = vkms_config_default_create(false, false, false, false); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); encoder_cfg = get_first_encoder(config); @@ -957,6 +970,29 @@ static void vkms_config_test_connector_get_possible_encoders(struct kunit *test) vkms_config_destroy(config); } +static void vkms_config_test_connector_status(struct kunit *test) +{ + struct vkms_config *config; + struct vkms_config_connector *connector_cfg; + enum drm_connector_status status; + + config = vkms_config_create("test"); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config); + + connector_cfg = vkms_config_create_connector(config); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg); + + status = vkms_config_connector_get_status(connector_cfg); + KUNIT_EXPECT_EQ(test, status, connector_status_connected); + + vkms_config_connector_set_status(connector_cfg, + connector_status_disconnected); + status = vkms_config_connector_get_status(connector_cfg); + KUNIT_EXPECT_EQ(test, status, connector_status_disconnected); + + vkms_config_destroy(config); +} + static struct kunit_case vkms_config_test_cases[] = { KUNIT_CASE(vkms_config_test_empty_config), KUNIT_CASE_PARAM(vkms_config_test_default_config, @@ -978,6 +1014,7 @@ static struct kunit_case vkms_config_test_cases[] = { KUNIT_CASE(vkms_config_test_plane_get_possible_crtcs), KUNIT_CASE(vkms_config_test_encoder_get_possible_crtcs), KUNIT_CASE(vkms_config_test_connector_get_possible_encoders), + KUNIT_CASE(vkms_config_test_connector_status), {} }; diff --git a/drivers/gpu/drm/vkms/vkms_colorop.c b/drivers/gpu/drm/vkms/vkms_colorop.c new file mode 100644 index 000000000000..5c3ffc78aea0 --- /dev/null +++ b/drivers/gpu/drm/vkms/vkms_colorop.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <linux/slab.h> +#include <drm/drm_colorop.h> +#include <drm/drm_print.h> +#include <drm/drm_property.h> +#include <drm/drm_plane.h> + +#include "vkms_drv.h" + +static const u64 supported_tfs = + BIT(DRM_COLOROP_1D_CURVE_SRGB_EOTF) | + BIT(DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF); + +#define MAX_COLOR_PIPELINE_OPS 4 + +static int vkms_initialize_color_pipeline(struct drm_plane *plane, struct drm_prop_enum_list *list) +{ + struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS]; + struct drm_device *dev = plane->dev; + int ret; + int i = 0, j = 0; + + memset(ops, 0, sizeof(ops)); + + /* 1st op: 1d curve */ + ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL); + if (!ops[i]) { + drm_err(dev, "KMS: Failed to allocate colorop\n"); + ret = -ENOMEM; + goto cleanup; + } + + ret = drm_plane_colorop_curve_1d_init(dev, ops[i], plane, supported_tfs, + DRM_COLOROP_FLAG_ALLOW_BYPASS); + if (ret) + goto cleanup; + + list->type = ops[i]->base.id; + list->name = kasprintf(GFP_KERNEL, "Color Pipeline %d", ops[i]->base.id); + + i++; + + /* 2nd op: 3x4 matrix */ + ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL); + if (!ops[i]) { + drm_err(dev, "KMS: Failed to allocate colorop\n"); + ret = -ENOMEM; + goto cleanup; + } + + ret = drm_plane_colorop_ctm_3x4_init(dev, ops[i], plane, DRM_COLOROP_FLAG_ALLOW_BYPASS); + if (ret) + goto cleanup; + + drm_colorop_set_next_property(ops[i - 1], ops[i]); + + i++; + + /* 3rd op: 3x4 matrix */ + ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL); + if (!ops[i]) { + drm_err(dev, "KMS: Failed to allocate colorop\n"); + ret = -ENOMEM; + goto cleanup; + } + + ret = drm_plane_colorop_ctm_3x4_init(dev, ops[i], plane, DRM_COLOROP_FLAG_ALLOW_BYPASS); + if (ret) + goto cleanup; + + drm_colorop_set_next_property(ops[i - 1], ops[i]); + + i++; + + /* 4th op: 1d curve */ + ops[i] = kzalloc(sizeof(*ops[i]), GFP_KERNEL); + if (!ops[i]) { + drm_err(dev, "KMS: Failed to allocate colorop\n"); + ret = -ENOMEM; + goto cleanup; + } + + ret = drm_plane_colorop_curve_1d_init(dev, ops[i], plane, supported_tfs, + DRM_COLOROP_FLAG_ALLOW_BYPASS); + if (ret) + goto cleanup; + + drm_colorop_set_next_property(ops[i - 1], ops[i]); + + return 0; + +cleanup: + for (j = 0; j < i; j++) { + if (ops[j]) { + drm_colorop_cleanup(ops[j]); + kfree(ops[j]); + } + } + + return ret; +} + +int vkms_initialize_colorops(struct drm_plane *plane) +{ + struct drm_prop_enum_list pipeline; + int ret; + + /* Add color pipeline */ + ret = vkms_initialize_color_pipeline(plane, &pipeline); + if (ret) + return ret; + + /* Create COLOR_PIPELINE property and attach */ + ret = drm_plane_create_color_pipeline_property(plane, &pipeline, 1); + if (ret) + return ret; + + return 0; +} diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index fa269d279e25..3cf3f26e0d8e 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -8,10 +8,13 @@ #include <drm/drm_fourcc.h> #include <drm/drm_fixed.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_print.h> #include <drm/drm_vblank.h> #include <linux/minmax.h> +#include <kunit/visibility.h> -#include "vkms_drv.h" +#include "vkms_composer.h" +#include "vkms_luts.h" static u16 pre_mul_blend_channel(u16 src, u16 dst, u16 alpha) { @@ -60,7 +63,7 @@ static void fill_background(const struct pixel_argb_u16 *background_color, } // lerp(a, b, t) = a + (b - a) * t -static u16 lerp_u16(u16 a, u16 b, s64 t) +VISIBLE_IF_KUNIT u16 lerp_u16(u16 a, u16 b, s64 t) { s64 a_fp = drm_int2fixp(a); s64 b_fp = drm_int2fixp(b); @@ -69,27 +72,18 @@ static u16 lerp_u16(u16 a, u16 b, s64 t) return drm_fixp2int_round(a_fp + delta); } +EXPORT_SYMBOL_IF_KUNIT(lerp_u16); -static s64 get_lut_index(const struct vkms_color_lut *lut, u16 channel_value) +VISIBLE_IF_KUNIT s64 get_lut_index(const struct vkms_color_lut *lut, u16 channel_value) { s64 color_channel_fp = drm_int2fixp(channel_value); return drm_fixp_mul(color_channel_fp, lut->channel_value2index_ratio); } +EXPORT_SYMBOL_IF_KUNIT(get_lut_index); -/* - * This enum is related to the positions of the variables inside - * `struct drm_color_lut`, so the order of both needs to be the same. - */ -enum lut_channel { - LUT_RED = 0, - LUT_GREEN, - LUT_BLUE, - LUT_RESERVED -}; - -static u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 channel_value, - enum lut_channel channel) +VISIBLE_IF_KUNIT u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 channel_value, + enum lut_channel channel) { s64 lut_index = get_lut_index(lut, channel_value); u16 *floor_lut_value, *ceil_lut_value; @@ -114,6 +108,8 @@ static u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 chan return lerp_u16(floor_channel_value, ceil_channel_value, lut_index & DRM_FIXED_DECIMAL_MASK); } +EXPORT_SYMBOL_IF_KUNIT(apply_lut_to_channel_value); + static void apply_lut(const struct vkms_crtc_state *crtc_state, struct line_buffer *output_buffer) { @@ -132,6 +128,112 @@ static void apply_lut(const struct vkms_crtc_state *crtc_state, struct line_buff } } +VISIBLE_IF_KUNIT void apply_3x4_matrix(struct pixel_argb_s32 *pixel, + const struct drm_color_ctm_3x4 *matrix) +{ + s64 rf, gf, bf; + s64 r, g, b; + + r = drm_int2fixp(pixel->r); + g = drm_int2fixp(pixel->g); + b = drm_int2fixp(pixel->b); + + rf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[0]), r) + + drm_fixp_mul(drm_sm2fixp(matrix->matrix[1]), g) + + drm_fixp_mul(drm_sm2fixp(matrix->matrix[2]), b) + + drm_sm2fixp(matrix->matrix[3]); + + gf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[4]), r) + + drm_fixp_mul(drm_sm2fixp(matrix->matrix[5]), g) + + drm_fixp_mul(drm_sm2fixp(matrix->matrix[6]), b) + + drm_sm2fixp(matrix->matrix[7]); + + bf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[8]), r) + + drm_fixp_mul(drm_sm2fixp(matrix->matrix[9]), g) + + drm_fixp_mul(drm_sm2fixp(matrix->matrix[10]), b) + + drm_sm2fixp(matrix->matrix[11]); + + pixel->r = drm_fixp2int_round(rf); + pixel->g = drm_fixp2int_round(gf); + pixel->b = drm_fixp2int_round(bf); +} +EXPORT_SYMBOL_IF_KUNIT(apply_3x4_matrix); + +static void apply_colorop(struct pixel_argb_s32 *pixel, struct drm_colorop *colorop) +{ + struct drm_colorop_state *colorop_state = colorop->state; + struct drm_device *dev = colorop->dev; + + if (colorop->type == DRM_COLOROP_1D_CURVE) { + switch (colorop_state->curve_1d_type) { + case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF: + pixel->r = apply_lut_to_channel_value(&srgb_inv_eotf, pixel->r, LUT_RED); + pixel->g = apply_lut_to_channel_value(&srgb_inv_eotf, pixel->g, LUT_GREEN); + pixel->b = apply_lut_to_channel_value(&srgb_inv_eotf, pixel->b, LUT_BLUE); + break; + case DRM_COLOROP_1D_CURVE_SRGB_EOTF: + pixel->r = apply_lut_to_channel_value(&srgb_eotf, pixel->r, LUT_RED); + pixel->g = apply_lut_to_channel_value(&srgb_eotf, pixel->g, LUT_GREEN); + pixel->b = apply_lut_to_channel_value(&srgb_eotf, pixel->b, LUT_BLUE); + break; + default: + drm_WARN_ONCE(dev, true, + "unknown colorop 1D curve type %d\n", + colorop_state->curve_1d_type); + break; + } + } else if (colorop->type == DRM_COLOROP_CTM_3X4) { + if (colorop_state->data) + apply_3x4_matrix(pixel, + (struct drm_color_ctm_3x4 *)colorop_state->data->data); + } +} + +static void pre_blend_color_transform(const struct vkms_plane_state *plane_state, + struct line_buffer *output_buffer) +{ + struct pixel_argb_s32 pixel; + + for (size_t x = 0; x < output_buffer->n_pixels; x++) { + struct drm_colorop *colorop = plane_state->base.base.color_pipeline; + + /* + * Some operations, such as applying a BT709 encoding matrix, + * followed by a decoding matrix, require that we preserve + * values above 1.0 and below 0.0 until the end of the pipeline. + * + * Pack the 16-bit UNORM values into s32 to give us head-room to + * avoid clipping until we're at the end of the pipeline. Clip + * intentionally at the end of the pipeline before packing + * UNORM values back into u16. + */ + pixel.a = output_buffer->pixels[x].a; + pixel.r = output_buffer->pixels[x].r; + pixel.g = output_buffer->pixels[x].g; + pixel.b = output_buffer->pixels[x].b; + + while (colorop) { + struct drm_colorop_state *colorop_state; + + colorop_state = colorop->state; + + if (!colorop_state) + return; + + if (!colorop_state->bypass) + apply_colorop(&pixel, colorop); + + colorop = colorop->next; + } + + /* clamp values */ + output_buffer->pixels[x].a = clamp_val(pixel.a, 0, 0xffff); + output_buffer->pixels[x].r = clamp_val(pixel.r, 0, 0xffff); + output_buffer->pixels[x].g = clamp_val(pixel.g, 0, 0xffff); + output_buffer->pixels[x].b = clamp_val(pixel.b, 0, 0xffff); + } +} + /** * direction_for_rotation() - Get the correct reading direction for a given rotation * @@ -347,7 +449,7 @@ static void blend_line(struct vkms_plane_state *current_plane, int y, */ current_plane->pixel_read_line(current_plane, src_x_start, src_y_start, direction, pixel_count, &stage_buffer->pixels[dst_x_start]); - + pre_blend_color_transform(current_plane, stage_buffer); pre_mul_alpha_blend(stage_buffer, output_buffer, dst_x_start, pixel_count); } diff --git a/drivers/gpu/drm/vkms/vkms_composer.h b/drivers/gpu/drm/vkms/vkms_composer.h new file mode 100644 index 000000000000..04dd5646f672 --- /dev/null +++ b/drivers/gpu/drm/vkms/vkms_composer.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef _VKMS_COMPOSER_H_ +#define _VKMS_COMPOSER_H_ + +#include <kunit/visibility.h> +#include "vkms_drv.h" + +/* + * This enum is related to the positions of the variables inside + * `struct drm_color_lut`, so the order of both needs to be the same. + */ +enum lut_channel { + LUT_RED = 0, + LUT_GREEN, + LUT_BLUE, + LUT_RESERVED +}; + +#if IS_ENABLED(CONFIG_KUNIT) +u16 lerp_u16(u16 a, u16 b, s64 t); +s64 get_lut_index(const struct vkms_color_lut *lut, u16 channel_value); +u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 channel_value, + enum lut_channel channel); +void apply_3x4_matrix(struct pixel_argb_s32 *pixel, const struct drm_color_ctm_3x4 *matrix); +#endif + +#endif /* _VKMS_COMPOSER_H_ */ diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c index a1df5659b0fb..8788df9edb7c 100644 --- a/drivers/gpu/drm/vkms/vkms_config.c +++ b/drivers/gpu/drm/vkms/vkms_config.c @@ -33,7 +33,8 @@ EXPORT_SYMBOL_IF_KUNIT(vkms_config_create); struct vkms_config *vkms_config_default_create(bool enable_cursor, bool enable_writeback, - bool enable_overlay) + bool enable_overlay, + bool enable_plane_pipeline) { struct vkms_config *config; struct vkms_config_plane *plane_cfg; @@ -58,6 +59,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor, if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg)) goto err_alloc; + vkms_config_plane_set_default_pipeline(plane_cfg, enable_plane_pipeline); if (enable_overlay) { for (n = 0; n < NUM_OVERLAY_PLANES; n++) { @@ -67,6 +69,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor, vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_OVERLAY); + vkms_config_plane_set_default_pipeline(plane_cfg, enable_plane_pipeline); if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg)) goto err_alloc; @@ -79,6 +82,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor, goto err_alloc; vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_CURSOR); + vkms_config_plane_set_default_pipeline(plane_cfg, enable_plane_pipeline); if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg)) goto err_alloc; @@ -361,8 +365,11 @@ static int vkms_config_show(struct seq_file *m, void *data) vkms_config_for_each_encoder(vkmsdev->config, encoder_cfg) seq_puts(m, "encoder\n"); - vkms_config_for_each_connector(vkmsdev->config, connector_cfg) - seq_puts(m, "connector\n"); + vkms_config_for_each_connector(vkmsdev->config, connector_cfg) { + seq_puts(m, "connector:\n"); + seq_printf(m, "\tstatus=%d\n", + vkms_config_connector_get_status(connector_cfg)); + } return 0; } @@ -386,6 +393,7 @@ struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *config) return ERR_PTR(-ENOMEM); plane_cfg->config = config; + plane_cfg->default_pipeline = false; vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_OVERLAY); xa_init_flags(&plane_cfg->possible_crtcs, XA_FLAGS_ALLOC); @@ -588,6 +596,7 @@ struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *c return ERR_PTR(-ENOMEM); connector_cfg->config = config; + connector_cfg->status = connector_status_connected; xa_init_flags(&connector_cfg->possible_encoders, XA_FLAGS_ALLOC); list_add_tail(&connector_cfg->link, &config->connectors); diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h index 0118e3f99706..8f7f286a4bdd 100644 --- a/drivers/gpu/drm/vkms/vkms_config.h +++ b/drivers/gpu/drm/vkms/vkms_config.h @@ -7,6 +7,8 @@ #include <linux/types.h> #include <linux/xarray.h> +#include <drm/drm_connector.h> + #include "vkms_drv.h" /** @@ -47,6 +49,7 @@ struct vkms_config_plane { enum drm_plane_type type; struct xarray possible_crtcs; + bool default_pipeline; /* Internal usage */ struct vkms_plane *plane; @@ -99,6 +102,7 @@ struct vkms_config_encoder { * * @link: Link to the others connector in vkms_config * @config: The vkms_config this connector belongs to + * @status: Status (connected, disconnected...) of the connector * @possible_encoders: Array of encoders that can be used with this connector * @connector: Internal usage. This pointer should never be considered as valid. * It can be used to store a temporary reference to a VKMS connector @@ -109,6 +113,7 @@ struct vkms_config_connector { struct list_head link; struct vkms_config *config; + enum drm_connector_status status; struct xarray possible_encoders; /* Internal usage */ @@ -199,7 +204,8 @@ struct vkms_config *vkms_config_create(const char *dev_name); */ struct vkms_config *vkms_config_default_create(bool enable_cursor, bool enable_writeback, - bool enable_overlay); + bool enable_overlay, + bool enable_plane_pipeline); /** * vkms_config_destroy() - Free a VKMS configuration @@ -285,6 +291,30 @@ vkms_config_plane_set_type(struct vkms_config_plane *plane_cfg, } /** + * vkms_config_plane_get_default_pipeline() - Return if the plane will + * be created with the default pipeline + * @plane_cfg: Plane to get the information from + */ +static inline bool +vkms_config_plane_get_default_pipeline(struct vkms_config_plane *plane_cfg) +{ + return plane_cfg->default_pipeline; +} + +/** + * vkms_config_plane_set_default_pipeline() - Set if the plane will + * be created with the default pipeline + * @plane_cfg: Plane to configure the pipeline + * @default_pipeline: New default pipeline value + */ +static inline void +vkms_config_plane_set_default_pipeline(struct vkms_config_plane *plane_cfg, + bool default_pipeline) +{ + plane_cfg->default_pipeline = default_pipeline; +} + +/** * vkms_config_plane_attach_crtc - Attach a plane to a CRTC * @plane_cfg: Plane to attach * @crtc_cfg: CRTC to attach @plane_cfg to @@ -434,4 +464,26 @@ int __must_check vkms_config_connector_attach_encoder(struct vkms_config_connect void vkms_config_connector_detach_encoder(struct vkms_config_connector *connector_cfg, struct vkms_config_encoder *encoder_cfg); +/** + * vkms_config_connector_get_status() - Return the status of the connector + * @connector_cfg: Connector to get the status from + */ +static inline enum drm_connector_status +vkms_config_connector_get_status(struct vkms_config_connector *connector_cfg) +{ + return connector_cfg->status; +} + +/** + * vkms_config_connector_set_status() - Set the status of the connector + * @connector_cfg: Connector to set the status to + * @status: New connector status + */ +static inline void +vkms_config_connector_set_status(struct vkms_config_connector *connector_cfg, + enum drm_connector_status status) +{ + connector_cfg->status = status; +} + #endif /* _VKMS_CONFIG_H_ */ diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c new file mode 100644 index 000000000000..506666e21c91 --- /dev/null +++ b/drivers/gpu/drm/vkms/vkms_configfs.c @@ -0,0 +1,843 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include <linux/cleanup.h> +#include <linux/configfs.h> +#include <linux/mutex.h> +#include <linux/slab.h> + +#include "vkms_drv.h" +#include "vkms_config.h" +#include "vkms_configfs.h" +#include "vkms_connector.h" + +/* To avoid registering configfs more than once or unregistering on error */ +static bool is_configfs_registered; + +/** + * struct vkms_configfs_device - Configfs representation of a VKMS device + * + * @group: Top level configuration group that represents a VKMS device. + * Initialized when a new directory is created under "/config/vkms/" + * @planes_group: Default subgroup of @group at "/config/vkms/planes" + * @crtcs_group: Default subgroup of @group at "/config/vkms/crtcs" + * @encoders_group: Default subgroup of @group at "/config/vkms/encoders" + * @connectors_group: Default subgroup of @group at "/config/vkms/connectors" + * @lock: Lock used to project concurrent access to the configuration attributes + * @config: Protected by @lock. Configuration of the VKMS device + * @enabled: Protected by @lock. The device is created or destroyed when this + * option changes + */ +struct vkms_configfs_device { + struct config_group group; + struct config_group planes_group; + struct config_group crtcs_group; + struct config_group encoders_group; + struct config_group connectors_group; + + struct mutex lock; + struct vkms_config *config; + bool enabled; +}; + +/** + * struct vkms_configfs_plane - Configfs representation of a plane + * + * @group: Top level configuration group that represents a plane. + * Initialized when a new directory is created under "/config/vkms/planes" + * @possible_crtcs_group: Default subgroup of @group at "plane/possible_crtcs" + * @dev: The vkms_configfs_device this plane belongs to + * @config: Configuration of the VKMS plane + */ +struct vkms_configfs_plane { + struct config_group group; + struct config_group possible_crtcs_group; + struct vkms_configfs_device *dev; + struct vkms_config_plane *config; +}; + +/** + * struct vkms_configfs_crtc - Configfs representation of a CRTC + * + * @group: Top level configuration group that represents a CRTC. + * Initialized when a new directory is created under "/config/vkms/crtcs" + * @dev: The vkms_configfs_device this CRTC belongs to + * @config: Configuration of the VKMS CRTC + */ +struct vkms_configfs_crtc { + struct config_group group; + struct vkms_configfs_device *dev; + struct vkms_config_crtc *config; +}; + +/** + * struct vkms_configfs_encoder - Configfs representation of a encoder + * + * @group: Top level configuration group that represents a encoder. + * Initialized when a new directory is created under "/config/vkms/encoders" + * @possible_crtcs_group: Default subgroup of @group at "encoder/possible_crtcs" + * @dev: The vkms_configfs_device this encoder belongs to + * @config: Configuration of the VKMS encoder + */ +struct vkms_configfs_encoder { + struct config_group group; + struct config_group possible_crtcs_group; + struct vkms_configfs_device *dev; + struct vkms_config_encoder *config; +}; + +/** + * struct vkms_configfs_connector - Configfs representation of a connector + * + * @group: Top level configuration group that represents a connector. + * Initialized when a new directory is created under "/config/vkms/connectors" + * @possible_encoders_group: Default subgroup of @group at + * "connector/possible_encoders" + * @dev: The vkms_configfs_device this connector belongs to + * @config: Configuration of the VKMS connector + */ +struct vkms_configfs_connector { + struct config_group group; + struct config_group possible_encoders_group; + struct vkms_configfs_device *dev; + struct vkms_config_connector *config; +}; + +#define device_item_to_vkms_configfs_device(item) \ + container_of(to_config_group((item)), struct vkms_configfs_device, \ + group) + +#define child_group_to_vkms_configfs_device(group) \ + device_item_to_vkms_configfs_device((&(group)->cg_item)->ci_parent) + +#define plane_item_to_vkms_configfs_plane(item) \ + container_of(to_config_group((item)), struct vkms_configfs_plane, group) + +#define plane_possible_crtcs_item_to_vkms_configfs_plane(item) \ + container_of(to_config_group((item)), struct vkms_configfs_plane, \ + possible_crtcs_group) + +#define crtc_item_to_vkms_configfs_crtc(item) \ + container_of(to_config_group((item)), struct vkms_configfs_crtc, group) + +#define encoder_item_to_vkms_configfs_encoder(item) \ + container_of(to_config_group((item)), struct vkms_configfs_encoder, \ + group) + +#define encoder_possible_crtcs_item_to_vkms_configfs_encoder(item) \ + container_of(to_config_group((item)), struct vkms_configfs_encoder, \ + possible_crtcs_group) + +#define connector_item_to_vkms_configfs_connector(item) \ + container_of(to_config_group((item)), struct vkms_configfs_connector, \ + group) + +#define connector_possible_encoders_item_to_vkms_configfs_connector(item) \ + container_of(to_config_group((item)), struct vkms_configfs_connector, \ + possible_encoders_group) + +static ssize_t crtc_writeback_show(struct config_item *item, char *page) +{ + struct vkms_configfs_crtc *crtc; + bool writeback; + + crtc = crtc_item_to_vkms_configfs_crtc(item); + + scoped_guard(mutex, &crtc->dev->lock) + writeback = vkms_config_crtc_get_writeback(crtc->config); + + return sprintf(page, "%d\n", writeback); +} + +static ssize_t crtc_writeback_store(struct config_item *item, const char *page, + size_t count) +{ + struct vkms_configfs_crtc *crtc; + bool writeback; + + crtc = crtc_item_to_vkms_configfs_crtc(item); + + if (kstrtobool(page, &writeback)) + return -EINVAL; + + scoped_guard(mutex, &crtc->dev->lock) { + if (crtc->dev->enabled) + return -EBUSY; + + vkms_config_crtc_set_writeback(crtc->config, writeback); + } + + return (ssize_t)count; +} + +CONFIGFS_ATTR(crtc_, writeback); + +static struct configfs_attribute *crtc_item_attrs[] = { + &crtc_attr_writeback, + NULL, +}; + +static void crtc_release(struct config_item *item) +{ + struct vkms_configfs_crtc *crtc; + struct mutex *lock; + + crtc = crtc_item_to_vkms_configfs_crtc(item); + lock = &crtc->dev->lock; + + scoped_guard(mutex, lock) { + vkms_config_destroy_crtc(crtc->dev->config, crtc->config); + kfree(crtc); + } +} + +static struct configfs_item_operations crtc_item_operations = { + .release = &crtc_release, +}; + +static const struct config_item_type crtc_item_type = { + .ct_attrs = crtc_item_attrs, + .ct_item_ops = &crtc_item_operations, + .ct_owner = THIS_MODULE, +}; + +static struct config_group *make_crtc_group(struct config_group *group, + const char *name) +{ + struct vkms_configfs_device *dev; + struct vkms_configfs_crtc *crtc; + int ret; + + dev = child_group_to_vkms_configfs_device(group); + + scoped_guard(mutex, &dev->lock) { + if (dev->enabled) + return ERR_PTR(-EBUSY); + + crtc = kzalloc(sizeof(*crtc), GFP_KERNEL); + if (!crtc) + return ERR_PTR(-ENOMEM); + + crtc->dev = dev; + + crtc->config = vkms_config_create_crtc(dev->config); + if (IS_ERR(crtc->config)) { + ret = PTR_ERR(crtc->config); + kfree(crtc); + return ERR_PTR(ret); + } + + config_group_init_type_name(&crtc->group, name, &crtc_item_type); + } + + return &crtc->group; +} + +static struct configfs_group_operations crtcs_group_operations = { + .make_group = &make_crtc_group, +}; + +static const struct config_item_type crtc_group_type = { + .ct_group_ops = &crtcs_group_operations, + .ct_owner = THIS_MODULE, +}; + +static int plane_possible_crtcs_allow_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_configfs_plane *plane; + struct vkms_configfs_crtc *crtc; + int ret; + + if (target->ci_type != &crtc_item_type) + return -EINVAL; + + plane = plane_possible_crtcs_item_to_vkms_configfs_plane(src); + crtc = crtc_item_to_vkms_configfs_crtc(target); + + scoped_guard(mutex, &plane->dev->lock) { + if (plane->dev->enabled) + return -EBUSY; + + ret = vkms_config_plane_attach_crtc(plane->config, crtc->config); + } + + return ret; +} + +static void plane_possible_crtcs_drop_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_configfs_plane *plane; + struct vkms_configfs_crtc *crtc; + + plane = plane_possible_crtcs_item_to_vkms_configfs_plane(src); + crtc = crtc_item_to_vkms_configfs_crtc(target); + + scoped_guard(mutex, &plane->dev->lock) + vkms_config_plane_detach_crtc(plane->config, crtc->config); +} + +static struct configfs_item_operations plane_possible_crtcs_item_operations = { + .allow_link = plane_possible_crtcs_allow_link, + .drop_link = plane_possible_crtcs_drop_link, +}; + +static const struct config_item_type plane_possible_crtcs_group_type = { + .ct_item_ops = &plane_possible_crtcs_item_operations, + .ct_owner = THIS_MODULE, +}; + +static ssize_t plane_type_show(struct config_item *item, char *page) +{ + struct vkms_configfs_plane *plane; + enum drm_plane_type type; + + plane = plane_item_to_vkms_configfs_plane(item); + + scoped_guard(mutex, &plane->dev->lock) + type = vkms_config_plane_get_type(plane->config); + + return sprintf(page, "%u", type); +} + +static ssize_t plane_type_store(struct config_item *item, const char *page, + size_t count) +{ + struct vkms_configfs_plane *plane; + enum drm_plane_type type; + + plane = plane_item_to_vkms_configfs_plane(item); + + if (kstrtouint(page, 10, &type)) + return -EINVAL; + + if (type != DRM_PLANE_TYPE_OVERLAY && type != DRM_PLANE_TYPE_PRIMARY && + type != DRM_PLANE_TYPE_CURSOR) + return -EINVAL; + + scoped_guard(mutex, &plane->dev->lock) { + if (plane->dev->enabled) + return -EBUSY; + + vkms_config_plane_set_type(plane->config, type); + } + + return (ssize_t)count; +} + +CONFIGFS_ATTR(plane_, type); + +static struct configfs_attribute *plane_item_attrs[] = { + &plane_attr_type, + NULL, +}; + +static void plane_release(struct config_item *item) +{ + struct vkms_configfs_plane *plane; + struct mutex *lock; + + plane = plane_item_to_vkms_configfs_plane(item); + lock = &plane->dev->lock; + + scoped_guard(mutex, lock) { + vkms_config_destroy_plane(plane->config); + kfree(plane); + } +} + +static struct configfs_item_operations plane_item_operations = { + .release = &plane_release, +}; + +static const struct config_item_type plane_item_type = { + .ct_attrs = plane_item_attrs, + .ct_item_ops = &plane_item_operations, + .ct_owner = THIS_MODULE, +}; + +static struct config_group *make_plane_group(struct config_group *group, + const char *name) +{ + struct vkms_configfs_device *dev; + struct vkms_configfs_plane *plane; + int ret; + + dev = child_group_to_vkms_configfs_device(group); + + scoped_guard(mutex, &dev->lock) { + if (dev->enabled) + return ERR_PTR(-EBUSY); + + plane = kzalloc(sizeof(*plane), GFP_KERNEL); + if (!plane) + return ERR_PTR(-ENOMEM); + + plane->dev = dev; + + plane->config = vkms_config_create_plane(dev->config); + if (IS_ERR(plane->config)) { + ret = PTR_ERR(plane->config); + kfree(plane); + return ERR_PTR(ret); + } + + config_group_init_type_name(&plane->group, name, &plane_item_type); + + config_group_init_type_name(&plane->possible_crtcs_group, + "possible_crtcs", + &plane_possible_crtcs_group_type); + configfs_add_default_group(&plane->possible_crtcs_group, + &plane->group); + } + + return &plane->group; +} + +static struct configfs_group_operations planes_group_operations = { + .make_group = &make_plane_group, +}; + +static const struct config_item_type plane_group_type = { + .ct_group_ops = &planes_group_operations, + .ct_owner = THIS_MODULE, +}; + +static int encoder_possible_crtcs_allow_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_configfs_encoder *encoder; + struct vkms_configfs_crtc *crtc; + int ret; + + if (target->ci_type != &crtc_item_type) + return -EINVAL; + + encoder = encoder_possible_crtcs_item_to_vkms_configfs_encoder(src); + crtc = crtc_item_to_vkms_configfs_crtc(target); + + scoped_guard(mutex, &encoder->dev->lock) { + if (encoder->dev->enabled) + return -EBUSY; + + ret = vkms_config_encoder_attach_crtc(encoder->config, crtc->config); + } + + return ret; +} + +static void encoder_possible_crtcs_drop_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_configfs_encoder *encoder; + struct vkms_configfs_crtc *crtc; + + encoder = encoder_possible_crtcs_item_to_vkms_configfs_encoder(src); + crtc = crtc_item_to_vkms_configfs_crtc(target); + + scoped_guard(mutex, &encoder->dev->lock) + vkms_config_encoder_detach_crtc(encoder->config, crtc->config); +} + +static struct configfs_item_operations encoder_possible_crtcs_item_operations = { + .allow_link = encoder_possible_crtcs_allow_link, + .drop_link = encoder_possible_crtcs_drop_link, +}; + +static const struct config_item_type encoder_possible_crtcs_group_type = { + .ct_item_ops = &encoder_possible_crtcs_item_operations, + .ct_owner = THIS_MODULE, +}; + +static void encoder_release(struct config_item *item) +{ + struct vkms_configfs_encoder *encoder; + struct mutex *lock; + + encoder = encoder_item_to_vkms_configfs_encoder(item); + lock = &encoder->dev->lock; + + scoped_guard(mutex, lock) { + vkms_config_destroy_encoder(encoder->dev->config, encoder->config); + kfree(encoder); + } +} + +static struct configfs_item_operations encoder_item_operations = { + .release = &encoder_release, +}; + +static const struct config_item_type encoder_item_type = { + .ct_item_ops = &encoder_item_operations, + .ct_owner = THIS_MODULE, +}; + +static struct config_group *make_encoder_group(struct config_group *group, + const char *name) +{ + struct vkms_configfs_device *dev; + struct vkms_configfs_encoder *encoder; + int ret; + + dev = child_group_to_vkms_configfs_device(group); + + scoped_guard(mutex, &dev->lock) { + if (dev->enabled) + return ERR_PTR(-EBUSY); + + encoder = kzalloc(sizeof(*encoder), GFP_KERNEL); + if (!encoder) + return ERR_PTR(-ENOMEM); + + encoder->dev = dev; + + encoder->config = vkms_config_create_encoder(dev->config); + if (IS_ERR(encoder->config)) { + ret = PTR_ERR(encoder->config); + kfree(encoder); + return ERR_PTR(ret); + } + + config_group_init_type_name(&encoder->group, name, + &encoder_item_type); + + config_group_init_type_name(&encoder->possible_crtcs_group, + "possible_crtcs", + &encoder_possible_crtcs_group_type); + configfs_add_default_group(&encoder->possible_crtcs_group, + &encoder->group); + } + + return &encoder->group; +} + +static struct configfs_group_operations encoders_group_operations = { + .make_group = &make_encoder_group, +}; + +static const struct config_item_type encoder_group_type = { + .ct_group_ops = &encoders_group_operations, + .ct_owner = THIS_MODULE, +}; + +static ssize_t connector_status_show(struct config_item *item, char *page) +{ + struct vkms_configfs_connector *connector; + enum drm_connector_status status; + + connector = connector_item_to_vkms_configfs_connector(item); + + scoped_guard(mutex, &connector->dev->lock) + status = vkms_config_connector_get_status(connector->config); + + return sprintf(page, "%u", status); +} + +static ssize_t connector_status_store(struct config_item *item, + const char *page, size_t count) +{ + struct vkms_configfs_connector *connector; + enum drm_connector_status status; + + connector = connector_item_to_vkms_configfs_connector(item); + + if (kstrtouint(page, 10, &status)) + return -EINVAL; + + if (status != connector_status_connected && + status != connector_status_disconnected && + status != connector_status_unknown) + return -EINVAL; + + scoped_guard(mutex, &connector->dev->lock) { + vkms_config_connector_set_status(connector->config, status); + + if (connector->dev->enabled) + vkms_trigger_connector_hotplug(connector->dev->config->dev); + } + + return (ssize_t)count; +} + +CONFIGFS_ATTR(connector_, status); + +static struct configfs_attribute *connector_item_attrs[] = { + &connector_attr_status, + NULL, +}; + +static void connector_release(struct config_item *item) +{ + struct vkms_configfs_connector *connector; + struct mutex *lock; + + connector = connector_item_to_vkms_configfs_connector(item); + lock = &connector->dev->lock; + + scoped_guard(mutex, lock) { + vkms_config_destroy_connector(connector->config); + kfree(connector); + } +} + +static struct configfs_item_operations connector_item_operations = { + .release = &connector_release, +}; + +static const struct config_item_type connector_item_type = { + .ct_attrs = connector_item_attrs, + .ct_item_ops = &connector_item_operations, + .ct_owner = THIS_MODULE, +}; + +static int connector_possible_encoders_allow_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_configfs_connector *connector; + struct vkms_configfs_encoder *encoder; + int ret; + + if (target->ci_type != &encoder_item_type) + return -EINVAL; + + connector = connector_possible_encoders_item_to_vkms_configfs_connector(src); + encoder = encoder_item_to_vkms_configfs_encoder(target); + + scoped_guard(mutex, &connector->dev->lock) { + if (connector->dev->enabled) + return -EBUSY; + + ret = vkms_config_connector_attach_encoder(connector->config, + encoder->config); + } + + return ret; +} + +static void connector_possible_encoders_drop_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_configfs_connector *connector; + struct vkms_configfs_encoder *encoder; + + connector = connector_possible_encoders_item_to_vkms_configfs_connector(src); + encoder = encoder_item_to_vkms_configfs_encoder(target); + + scoped_guard(mutex, &connector->dev->lock) { + vkms_config_connector_detach_encoder(connector->config, + encoder->config); + } +} + +static struct configfs_item_operations connector_possible_encoders_item_operations = { + .allow_link = connector_possible_encoders_allow_link, + .drop_link = connector_possible_encoders_drop_link, +}; + +static const struct config_item_type connector_possible_encoders_group_type = { + .ct_item_ops = &connector_possible_encoders_item_operations, + .ct_owner = THIS_MODULE, +}; + +static struct config_group *make_connector_group(struct config_group *group, + const char *name) +{ + struct vkms_configfs_device *dev; + struct vkms_configfs_connector *connector; + int ret; + + dev = child_group_to_vkms_configfs_device(group); + + scoped_guard(mutex, &dev->lock) { + if (dev->enabled) + return ERR_PTR(-EBUSY); + + connector = kzalloc(sizeof(*connector), GFP_KERNEL); + if (!connector) + return ERR_PTR(-ENOMEM); + + connector->dev = dev; + + connector->config = vkms_config_create_connector(dev->config); + if (IS_ERR(connector->config)) { + ret = PTR_ERR(connector->config); + kfree(connector); + return ERR_PTR(ret); + } + + config_group_init_type_name(&connector->group, name, + &connector_item_type); + + config_group_init_type_name(&connector->possible_encoders_group, + "possible_encoders", + &connector_possible_encoders_group_type); + configfs_add_default_group(&connector->possible_encoders_group, + &connector->group); + } + + return &connector->group; +} + +static struct configfs_group_operations connectors_group_operations = { + .make_group = &make_connector_group, +}; + +static const struct config_item_type connector_group_type = { + .ct_group_ops = &connectors_group_operations, + .ct_owner = THIS_MODULE, +}; + +static ssize_t device_enabled_show(struct config_item *item, char *page) +{ + struct vkms_configfs_device *dev; + bool enabled; + + dev = device_item_to_vkms_configfs_device(item); + + scoped_guard(mutex, &dev->lock) + enabled = dev->enabled; + + return sprintf(page, "%d\n", enabled); +} + +static ssize_t device_enabled_store(struct config_item *item, const char *page, + size_t count) +{ + struct vkms_configfs_device *dev; + bool enabled; + int ret = 0; + + dev = device_item_to_vkms_configfs_device(item); + + if (kstrtobool(page, &enabled)) + return -EINVAL; + + scoped_guard(mutex, &dev->lock) { + if (!dev->enabled && enabled) { + if (!vkms_config_is_valid(dev->config)) + return -EINVAL; + + ret = vkms_create(dev->config); + if (ret) + return ret; + } else if (dev->enabled && !enabled) { + vkms_destroy(dev->config); + } + + dev->enabled = enabled; + } + + return (ssize_t)count; +} + +CONFIGFS_ATTR(device_, enabled); + +static struct configfs_attribute *device_item_attrs[] = { + &device_attr_enabled, + NULL, +}; + +static void device_release(struct config_item *item) +{ + struct vkms_configfs_device *dev; + + dev = device_item_to_vkms_configfs_device(item); + + if (dev->enabled) + vkms_destroy(dev->config); + + mutex_destroy(&dev->lock); + vkms_config_destroy(dev->config); + kfree(dev); +} + +static struct configfs_item_operations device_item_operations = { + .release = &device_release, +}; + +static const struct config_item_type device_item_type = { + .ct_attrs = device_item_attrs, + .ct_item_ops = &device_item_operations, + .ct_owner = THIS_MODULE, +}; + +static struct config_group *make_device_group(struct config_group *group, + const char *name) +{ + struct vkms_configfs_device *dev; + int ret; + + if (strcmp(name, DEFAULT_DEVICE_NAME) == 0) + return ERR_PTR(-EINVAL); + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return ERR_PTR(-ENOMEM); + + dev->config = vkms_config_create(name); + if (IS_ERR(dev->config)) { + ret = PTR_ERR(dev->config); + kfree(dev); + return ERR_PTR(ret); + } + + config_group_init_type_name(&dev->group, name, &device_item_type); + mutex_init(&dev->lock); + + config_group_init_type_name(&dev->planes_group, "planes", + &plane_group_type); + configfs_add_default_group(&dev->planes_group, &dev->group); + + config_group_init_type_name(&dev->crtcs_group, "crtcs", + &crtc_group_type); + configfs_add_default_group(&dev->crtcs_group, &dev->group); + + config_group_init_type_name(&dev->encoders_group, "encoders", + &encoder_group_type); + configfs_add_default_group(&dev->encoders_group, &dev->group); + + config_group_init_type_name(&dev->connectors_group, "connectors", + &connector_group_type); + configfs_add_default_group(&dev->connectors_group, &dev->group); + + return &dev->group; +} + +static struct configfs_group_operations device_group_ops = { + .make_group = &make_device_group, +}; + +static const struct config_item_type device_group_type = { + .ct_group_ops = &device_group_ops, + .ct_owner = THIS_MODULE, +}; + +static struct configfs_subsystem vkms_subsys = { + .su_group = { + .cg_item = { + .ci_name = "vkms", + .ci_type = &device_group_type, + }, + }, + .su_mutex = __MUTEX_INITIALIZER(vkms_subsys.su_mutex), +}; + +int vkms_configfs_register(void) +{ + int ret; + + if (is_configfs_registered) + return 0; + + config_group_init(&vkms_subsys.su_group); + ret = configfs_register_subsystem(&vkms_subsys); + + is_configfs_registered = ret == 0; + + return ret; +} + +void vkms_configfs_unregister(void) +{ + if (is_configfs_registered) + configfs_unregister_subsystem(&vkms_subsys); +} diff --git a/drivers/gpu/drm/vkms/vkms_configfs.h b/drivers/gpu/drm/vkms/vkms_configfs.h new file mode 100644 index 000000000000..e9020b0043db --- /dev/null +++ b/drivers/gpu/drm/vkms/vkms_configfs.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +#ifndef _VKMS_CONFIGFS_H_ +#define _VKMS_CONFIGFS_H_ + +int vkms_configfs_register(void); +void vkms_configfs_unregister(void); + +#endif /* _VKMS_CONFIGFS_H_ */ diff --git a/drivers/gpu/drm/vkms/vkms_connector.c b/drivers/gpu/drm/vkms/vkms_connector.c index 48b10cba322a..b0a6b212d3f4 100644 --- a/drivers/gpu/drm/vkms/vkms_connector.c +++ b/drivers/gpu/drm/vkms/vkms_connector.c @@ -5,9 +5,37 @@ #include <drm/drm_managed.h> #include <drm/drm_probe_helper.h> +#include "vkms_config.h" #include "vkms_connector.h" +static enum drm_connector_status vkms_connector_detect(struct drm_connector *connector, + bool force) +{ + struct drm_device *dev = connector->dev; + struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev); + struct vkms_connector *vkms_connector; + enum drm_connector_status status; + struct vkms_config_connector *connector_cfg; + + vkms_connector = drm_connector_to_vkms_connector(connector); + + /* + * The connector configuration might not exist if its configfs directory + * was deleted. Therefore, use the configuration if present or keep the + * current status if we can not access it anymore. + */ + status = connector->status; + + vkms_config_for_each_connector(vkmsdev->config, connector_cfg) { + if (connector_cfg->connector == vkms_connector) + status = vkms_config_connector_get_status(connector_cfg); + } + + return status; +} + static const struct drm_connector_funcs vkms_connector_funcs = { + .detect = vkms_connector_detect, .fill_modes = drm_helper_probe_single_connector_modes, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, @@ -59,3 +87,10 @@ struct vkms_connector *vkms_connector_init(struct vkms_device *vkmsdev) return connector; } + +void vkms_trigger_connector_hotplug(struct vkms_device *vkmsdev) +{ + struct drm_device *dev = &vkmsdev->drm; + + drm_kms_helper_hotplug_event(dev); +} diff --git a/drivers/gpu/drm/vkms/vkms_connector.h b/drivers/gpu/drm/vkms/vkms_connector.h index c9149c1b7af0..ed312f4eff3a 100644 --- a/drivers/gpu/drm/vkms/vkms_connector.h +++ b/drivers/gpu/drm/vkms/vkms_connector.h @@ -5,6 +5,9 @@ #include "vkms_drv.h" +#define drm_connector_to_vkms_connector(target) \ + container_of(target, struct vkms_connector, base) + /** * struct vkms_connector - VKMS custom type wrapping around the DRM connector * @@ -23,4 +26,10 @@ struct vkms_connector { */ struct vkms_connector *vkms_connector_init(struct vkms_device *vkmsdev); +/** + * vkms_trigger_connector_hotplug() - Update the device's connectors status + * @vkmsdev: VKMS device to update + */ +void vkms_trigger_connector_hotplug(struct vkms_device *vkmsdev); + #endif /* _VKMS_CONNECTOR_H_ */ diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index e60573e0f3e9..9a7db1d51022 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -5,27 +5,21 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_managed.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_vblank.h> +#include <drm/drm_vblank_helper.h> #include "vkms_drv.h" -static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) +static bool vkms_crtc_handle_vblank_timeout(struct drm_crtc *crtc) { - struct vkms_output *output = container_of(timer, struct vkms_output, - vblank_hrtimer); - struct drm_crtc *crtc = &output->crtc; + struct vkms_output *output = drm_crtc_to_vkms_output(crtc); struct vkms_crtc_state *state; - u64 ret_overrun; bool ret, fence_cookie; fence_cookie = dma_fence_begin_signalling(); - ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer, - output->period_ns); - if (ret_overrun != 1) - pr_warn("%s: vblank timer overrun\n", __func__); - spin_lock(&output->lock); ret = drm_crtc_handle_vblank(crtc); if (!ret) @@ -57,55 +51,6 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) dma_fence_end_signalling(fence_cookie); - return HRTIMER_RESTART; -} - -static int vkms_enable_vblank(struct drm_crtc *crtc) -{ - struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); - struct vkms_output *out = drm_crtc_to_vkms_output(crtc); - - hrtimer_setup(&out->vblank_hrtimer, &vkms_vblank_simulate, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - out->period_ns = ktime_set(0, vblank->framedur_ns); - hrtimer_start(&out->vblank_hrtimer, out->period_ns, HRTIMER_MODE_REL); - - return 0; -} - -static void vkms_disable_vblank(struct drm_crtc *crtc) -{ - struct vkms_output *out = drm_crtc_to_vkms_output(crtc); - - hrtimer_cancel(&out->vblank_hrtimer); -} - -static bool vkms_get_vblank_timestamp(struct drm_crtc *crtc, - int *max_error, ktime_t *vblank_time, - bool in_vblank_irq) -{ - struct vkms_output *output = drm_crtc_to_vkms_output(crtc); - struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); - - if (!READ_ONCE(vblank->enabled)) { - *vblank_time = ktime_get(); - return true; - } - - *vblank_time = READ_ONCE(output->vblank_hrtimer.node.expires); - - if (WARN_ON(*vblank_time == vblank->time)) - return true; - - /* - * To prevent races we roll the hrtimer forward before we do any - * interrupt processing - this is how real hw works (the interrupt is - * only generated after all the vblank registers are updated) and what - * the vblank core expects. Therefore we need to always correct the - * timestampe by one frame. - */ - *vblank_time -= output->period_ns; - return true; } @@ -159,9 +104,7 @@ static const struct drm_crtc_funcs vkms_crtc_funcs = { .reset = vkms_atomic_crtc_reset, .atomic_duplicate_state = vkms_atomic_crtc_duplicate_state, .atomic_destroy_state = vkms_atomic_crtc_destroy_state, - .enable_vblank = vkms_enable_vblank, - .disable_vblank = vkms_disable_vblank, - .get_vblank_timestamp = vkms_get_vblank_timestamp, + DRM_CRTC_VBLANK_TIMER_FUNCS, .get_crc_sources = vkms_get_crc_sources, .set_crc_source = vkms_set_crc_source, .verify_crc_source = vkms_verify_crc_source, @@ -185,7 +128,7 @@ static int vkms_crtc_atomic_check(struct drm_crtc *crtc, return ret; drm_for_each_plane_mask(plane, crtc->dev, crtc_state->plane_mask) { - plane_state = drm_atomic_get_existing_plane_state(crtc_state->state, plane); + plane_state = drm_atomic_get_new_plane_state(crtc_state->state, plane); WARN_ON(!plane_state); if (!plane_state->visible) @@ -201,7 +144,7 @@ static int vkms_crtc_atomic_check(struct drm_crtc *crtc, i = 0; drm_for_each_plane_mask(plane, crtc->dev, crtc_state->plane_mask) { - plane_state = drm_atomic_get_existing_plane_state(crtc_state->state, plane); + plane_state = drm_atomic_get_new_plane_state(crtc_state->state, plane); if (!plane_state->visible) continue; @@ -213,18 +156,6 @@ static int vkms_crtc_atomic_check(struct drm_crtc *crtc, return 0; } -static void vkms_crtc_atomic_enable(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - drm_crtc_vblank_on(crtc); -} - -static void vkms_crtc_atomic_disable(struct drm_crtc *crtc, - struct drm_atomic_state *state) -{ - drm_crtc_vblank_off(crtc); -} - static void vkms_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state) __acquires(&vkms_output->lock) @@ -265,8 +196,9 @@ static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = { .atomic_check = vkms_crtc_atomic_check, .atomic_begin = vkms_crtc_atomic_begin, .atomic_flush = vkms_crtc_atomic_flush, - .atomic_enable = vkms_crtc_atomic_enable, - .atomic_disable = vkms_crtc_atomic_disable, + .atomic_enable = drm_crtc_vblank_atomic_enable, + .atomic_disable = drm_crtc_vblank_atomic_disable, + .handle_vblank_timeout = vkms_crtc_handle_vblank_timeout, }; struct vkms_output *vkms_crtc_init(struct drm_device *dev, struct drm_plane *primary, diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c index e8472d9b6e3b..dd1402f43773 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -23,11 +23,13 @@ #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_ioctl.h> #include <drm/drm_managed.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_gem_shmem_helper.h> #include <drm/drm_vblank.h> #include "vkms_config.h" +#include "vkms_configfs.h" #include "vkms_drv.h" #define DRIVER_NAME "vkms" @@ -49,6 +51,14 @@ static bool enable_overlay; module_param_named(enable_overlay, enable_overlay, bool, 0444); MODULE_PARM_DESC(enable_overlay, "Enable/Disable overlay support"); +static bool enable_plane_pipeline; +module_param_named(enable_plane_pipeline, enable_plane_pipeline, bool, 0444); +MODULE_PARM_DESC(enable_plane_pipeline, "Enable/Disable plane pipeline support"); + +static bool create_default_dev = true; +module_param_named(create_default_dev, create_default_dev, bool, 0444); +MODULE_PARM_DESC(create_default_dev, "Create or not the default VKMS device"); + DEFINE_DRM_GEM_FOPS(vkms_driver_fops); static void vkms_atomic_commit_tail(struct drm_atomic_state *old_state) @@ -146,7 +156,7 @@ static int vkms_modeset_init(struct vkms_device *vkmsdev) return vkms_output_init(vkmsdev); } -static int vkms_create(struct vkms_config *config) +int vkms_create(struct vkms_config *config) { int ret; struct faux_device *fdev; @@ -214,7 +224,15 @@ static int __init vkms_init(void) int ret; struct vkms_config *config; - config = vkms_config_default_create(enable_cursor, enable_writeback, enable_overlay); + ret = vkms_configfs_register(); + if (ret) + return ret; + + if (!create_default_dev) + return 0; + + config = vkms_config_default_create(enable_cursor, enable_writeback, + enable_overlay, enable_plane_pipeline); if (IS_ERR(config)) return PTR_ERR(config); @@ -229,7 +247,7 @@ static int __init vkms_init(void) return 0; } -static void vkms_destroy(struct vkms_config *config) +void vkms_destroy(struct vkms_config *config) { struct faux_device *fdev; @@ -240,6 +258,7 @@ static void vkms_destroy(struct vkms_config *config) fdev = config->dev->faux_dev; + drm_colorop_pipeline_destroy(&config->dev->drm); drm_dev_unregister(&config->dev->drm); drm_atomic_helper_shutdown(&config->dev->drm); devres_release_group(&fdev->dev, NULL); @@ -250,6 +269,8 @@ static void vkms_destroy(struct vkms_config *config) static void __exit vkms_exit(void) { + vkms_configfs_unregister(); + if (!default_config) return; diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index 8013c31efe3b..0933e4ce0ff0 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -45,6 +45,10 @@ struct vkms_frame_info { unsigned int rotation; }; +struct pixel_argb_s32 { + s32 a, r, g, b; +}; + /** * struct pixel_argb_u16 - Internal representation of a pixel color. * @a: Alpha component value, stored in 16 bits, without padding, using @@ -215,8 +219,6 @@ struct vkms_output { struct drm_crtc crtc; struct drm_writeback_connector wb_connector; struct drm_encoder wb_encoder; - struct hrtimer vblank_hrtimer; - ktime_t period_ns; struct workqueue_struct *composer_workq; spinlock_t lock; @@ -227,6 +229,7 @@ struct vkms_output { }; struct vkms_config; +struct vkms_config_plane; /** * struct vkms_device - Description of a VKMS device @@ -259,6 +262,26 @@ struct vkms_device { container_of(target, struct vkms_plane_state, base.base) /** + * vkms_create() - Create a device from a configuration + * @config: Config used to configure the new device + * + * A pointer to the created vkms_device is stored in @config + * + * Returns: + * 0 on success or an error. + */ +int vkms_create(struct vkms_config *config); + +/** + * vkms_destroy() - Destroy a device + * @config: Config from which the device was created + * + * The device is completely removed, but the @config is not freed. It can be + * reused or destroyed with vkms_config_destroy(). + */ +void vkms_destroy(struct vkms_config *config); + +/** * vkms_crtc_init() - Initialize a CRTC for VKMS * @dev: DRM device associated with the VKMS buffer * @crtc: uninitialized CRTC device @@ -280,10 +303,10 @@ int vkms_output_init(struct vkms_device *vkmsdev); * vkms_plane_init() - Initialize a plane * * @vkmsdev: VKMS device containing the plane - * @type: type of plane to initialize + * @plane_cfg: plane configuration */ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, - enum drm_plane_type type); + struct vkms_config_plane *plane_cfg); /* CRC Support */ const char *const *vkms_get_crc_sources(struct drm_crtc *crtc, @@ -300,4 +323,7 @@ void vkms_writeback_row(struct vkms_writeback_job *wb, const struct line_buffer /* Writeback */ int vkms_enable_writeback_connector(struct vkms_device *vkmsdev, struct vkms_output *vkms_out); +/* Colorops */ +int vkms_initialize_colorops(struct drm_plane *plane); + #endif /* _VKMS_DRV_H_ */ diff --git a/drivers/gpu/drm/vkms/vkms_luts.c b/drivers/gpu/drm/vkms/vkms_luts.c new file mode 100644 index 000000000000..82cb792f10d8 --- /dev/null +++ b/drivers/gpu/drm/vkms/vkms_luts.c @@ -0,0 +1,811 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <drm/drm_mode.h> + +#include "vkms_drv.h" +#include "vkms_luts.h" + +/* + * These luts were generated with a LUT generated based on + * skia's transfer function code. The LUT generator can be + * found at + * https://gitlab.freedesktop.org/hwentland/lutgen + */ + +static struct drm_color_lut linear_array[LUT_SIZE] = { + { 0x0, 0x0, 0x0, 0 }, + { 0x101, 0x101, 0x101, 0 }, + { 0x202, 0x202, 0x202, 0 }, + { 0x303, 0x303, 0x303, 0 }, + { 0x404, 0x404, 0x404, 0 }, + { 0x505, 0x505, 0x505, 0 }, + { 0x606, 0x606, 0x606, 0 }, + { 0x707, 0x707, 0x707, 0 }, + { 0x808, 0x808, 0x808, 0 }, + { 0x909, 0x909, 0x909, 0 }, + { 0xa0a, 0xa0a, 0xa0a, 0 }, + { 0xb0b, 0xb0b, 0xb0b, 0 }, + { 0xc0c, 0xc0c, 0xc0c, 0 }, + { 0xd0d, 0xd0d, 0xd0d, 0 }, + { 0xe0e, 0xe0e, 0xe0e, 0 }, + { 0xf0f, 0xf0f, 0xf0f, 0 }, + { 0x1010, 0x1010, 0x1010, 0 }, + { 0x1111, 0x1111, 0x1111, 0 }, + { 0x1212, 0x1212, 0x1212, 0 }, + { 0x1313, 0x1313, 0x1313, 0 }, + { 0x1414, 0x1414, 0x1414, 0 }, + { 0x1515, 0x1515, 0x1515, 0 }, + { 0x1616, 0x1616, 0x1616, 0 }, + { 0x1717, 0x1717, 0x1717, 0 }, + { 0x1818, 0x1818, 0x1818, 0 }, + { 0x1919, 0x1919, 0x1919, 0 }, + { 0x1a1a, 0x1a1a, 0x1a1a, 0 }, + { 0x1b1b, 0x1b1b, 0x1b1b, 0 }, + { 0x1c1c, 0x1c1c, 0x1c1c, 0 }, + { 0x1d1d, 0x1d1d, 0x1d1d, 0 }, + { 0x1e1e, 0x1e1e, 0x1e1e, 0 }, + { 0x1f1f, 0x1f1f, 0x1f1f, 0 }, + { 0x2020, 0x2020, 0x2020, 0 }, + { 0x2121, 0x2121, 0x2121, 0 }, + { 0x2222, 0x2222, 0x2222, 0 }, + { 0x2323, 0x2323, 0x2323, 0 }, + { 0x2424, 0x2424, 0x2424, 0 }, + { 0x2525, 0x2525, 0x2525, 0 }, + { 0x2626, 0x2626, 0x2626, 0 }, + { 0x2727, 0x2727, 0x2727, 0 }, + { 0x2828, 0x2828, 0x2828, 0 }, + { 0x2929, 0x2929, 0x2929, 0 }, + { 0x2a2a, 0x2a2a, 0x2a2a, 0 }, + { 0x2b2b, 0x2b2b, 0x2b2b, 0 }, + { 0x2c2c, 0x2c2c, 0x2c2c, 0 }, + { 0x2d2d, 0x2d2d, 0x2d2d, 0 }, + { 0x2e2e, 0x2e2e, 0x2e2e, 0 }, + { 0x2f2f, 0x2f2f, 0x2f2f, 0 }, + { 0x3030, 0x3030, 0x3030, 0 }, + { 0x3131, 0x3131, 0x3131, 0 }, + { 0x3232, 0x3232, 0x3232, 0 }, + { 0x3333, 0x3333, 0x3333, 0 }, + { 0x3434, 0x3434, 0x3434, 0 }, + { 0x3535, 0x3535, 0x3535, 0 }, + { 0x3636, 0x3636, 0x3636, 0 }, + { 0x3737, 0x3737, 0x3737, 0 }, + { 0x3838, 0x3838, 0x3838, 0 }, + { 0x3939, 0x3939, 0x3939, 0 }, + { 0x3a3a, 0x3a3a, 0x3a3a, 0 }, + { 0x3b3b, 0x3b3b, 0x3b3b, 0 }, + { 0x3c3c, 0x3c3c, 0x3c3c, 0 }, + { 0x3d3d, 0x3d3d, 0x3d3d, 0 }, + { 0x3e3e, 0x3e3e, 0x3e3e, 0 }, + { 0x3f3f, 0x3f3f, 0x3f3f, 0 }, + { 0x4040, 0x4040, 0x4040, 0 }, + { 0x4141, 0x4141, 0x4141, 0 }, + { 0x4242, 0x4242, 0x4242, 0 }, + { 0x4343, 0x4343, 0x4343, 0 }, + { 0x4444, 0x4444, 0x4444, 0 }, + { 0x4545, 0x4545, 0x4545, 0 }, + { 0x4646, 0x4646, 0x4646, 0 }, + { 0x4747, 0x4747, 0x4747, 0 }, + { 0x4848, 0x4848, 0x4848, 0 }, + { 0x4949, 0x4949, 0x4949, 0 }, + { 0x4a4a, 0x4a4a, 0x4a4a, 0 }, + { 0x4b4b, 0x4b4b, 0x4b4b, 0 }, + { 0x4c4c, 0x4c4c, 0x4c4c, 0 }, + { 0x4d4d, 0x4d4d, 0x4d4d, 0 }, + { 0x4e4e, 0x4e4e, 0x4e4e, 0 }, + { 0x4f4f, 0x4f4f, 0x4f4f, 0 }, + { 0x5050, 0x5050, 0x5050, 0 }, + { 0x5151, 0x5151, 0x5151, 0 }, + { 0x5252, 0x5252, 0x5252, 0 }, + { 0x5353, 0x5353, 0x5353, 0 }, + { 0x5454, 0x5454, 0x5454, 0 }, + { 0x5555, 0x5555, 0x5555, 0 }, + { 0x5656, 0x5656, 0x5656, 0 }, + { 0x5757, 0x5757, 0x5757, 0 }, + { 0x5858, 0x5858, 0x5858, 0 }, + { 0x5959, 0x5959, 0x5959, 0 }, + { 0x5a5a, 0x5a5a, 0x5a5a, 0 }, + { 0x5b5b, 0x5b5b, 0x5b5b, 0 }, + { 0x5c5c, 0x5c5c, 0x5c5c, 0 }, + { 0x5d5d, 0x5d5d, 0x5d5d, 0 }, + { 0x5e5e, 0x5e5e, 0x5e5e, 0 }, + { 0x5f5f, 0x5f5f, 0x5f5f, 0 }, + { 0x6060, 0x6060, 0x6060, 0 }, + { 0x6161, 0x6161, 0x6161, 0 }, + { 0x6262, 0x6262, 0x6262, 0 }, + { 0x6363, 0x6363, 0x6363, 0 }, + { 0x6464, 0x6464, 0x6464, 0 }, + { 0x6565, 0x6565, 0x6565, 0 }, + { 0x6666, 0x6666, 0x6666, 0 }, + { 0x6767, 0x6767, 0x6767, 0 }, + { 0x6868, 0x6868, 0x6868, 0 }, + { 0x6969, 0x6969, 0x6969, 0 }, + { 0x6a6a, 0x6a6a, 0x6a6a, 0 }, + { 0x6b6b, 0x6b6b, 0x6b6b, 0 }, + { 0x6c6c, 0x6c6c, 0x6c6c, 0 }, + { 0x6d6d, 0x6d6d, 0x6d6d, 0 }, + { 0x6e6e, 0x6e6e, 0x6e6e, 0 }, + { 0x6f6f, 0x6f6f, 0x6f6f, 0 }, + { 0x7070, 0x7070, 0x7070, 0 }, + { 0x7171, 0x7171, 0x7171, 0 }, + { 0x7272, 0x7272, 0x7272, 0 }, + { 0x7373, 0x7373, 0x7373, 0 }, + { 0x7474, 0x7474, 0x7474, 0 }, + { 0x7575, 0x7575, 0x7575, 0 }, + { 0x7676, 0x7676, 0x7676, 0 }, + { 0x7777, 0x7777, 0x7777, 0 }, + { 0x7878, 0x7878, 0x7878, 0 }, + { 0x7979, 0x7979, 0x7979, 0 }, + { 0x7a7a, 0x7a7a, 0x7a7a, 0 }, + { 0x7b7b, 0x7b7b, 0x7b7b, 0 }, + { 0x7c7c, 0x7c7c, 0x7c7c, 0 }, + { 0x7d7d, 0x7d7d, 0x7d7d, 0 }, + { 0x7e7e, 0x7e7e, 0x7e7e, 0 }, + { 0x7f7f, 0x7f7f, 0x7f7f, 0 }, + { 0x8080, 0x8080, 0x8080, 0 }, + { 0x8181, 0x8181, 0x8181, 0 }, + { 0x8282, 0x8282, 0x8282, 0 }, + { 0x8383, 0x8383, 0x8383, 0 }, + { 0x8484, 0x8484, 0x8484, 0 }, + { 0x8585, 0x8585, 0x8585, 0 }, + { 0x8686, 0x8686, 0x8686, 0 }, + { 0x8787, 0x8787, 0x8787, 0 }, + { 0x8888, 0x8888, 0x8888, 0 }, + { 0x8989, 0x8989, 0x8989, 0 }, + { 0x8a8a, 0x8a8a, 0x8a8a, 0 }, + { 0x8b8b, 0x8b8b, 0x8b8b, 0 }, + { 0x8c8c, 0x8c8c, 0x8c8c, 0 }, + { 0x8d8d, 0x8d8d, 0x8d8d, 0 }, + { 0x8e8e, 0x8e8e, 0x8e8e, 0 }, + { 0x8f8f, 0x8f8f, 0x8f8f, 0 }, + { 0x9090, 0x9090, 0x9090, 0 }, + { 0x9191, 0x9191, 0x9191, 0 }, + { 0x9292, 0x9292, 0x9292, 0 }, + { 0x9393, 0x9393, 0x9393, 0 }, + { 0x9494, 0x9494, 0x9494, 0 }, + { 0x9595, 0x9595, 0x9595, 0 }, + { 0x9696, 0x9696, 0x9696, 0 }, + { 0x9797, 0x9797, 0x9797, 0 }, + { 0x9898, 0x9898, 0x9898, 0 }, + { 0x9999, 0x9999, 0x9999, 0 }, + { 0x9a9a, 0x9a9a, 0x9a9a, 0 }, + { 0x9b9b, 0x9b9b, 0x9b9b, 0 }, + { 0x9c9c, 0x9c9c, 0x9c9c, 0 }, + { 0x9d9d, 0x9d9d, 0x9d9d, 0 }, + { 0x9e9e, 0x9e9e, 0x9e9e, 0 }, + { 0x9f9f, 0x9f9f, 0x9f9f, 0 }, + { 0xa0a0, 0xa0a0, 0xa0a0, 0 }, + { 0xa1a1, 0xa1a1, 0xa1a1, 0 }, + { 0xa2a2, 0xa2a2, 0xa2a2, 0 }, + { 0xa3a3, 0xa3a3, 0xa3a3, 0 }, + { 0xa4a4, 0xa4a4, 0xa4a4, 0 }, + { 0xa5a5, 0xa5a5, 0xa5a5, 0 }, + { 0xa6a6, 0xa6a6, 0xa6a6, 0 }, + { 0xa7a7, 0xa7a7, 0xa7a7, 0 }, + { 0xa8a8, 0xa8a8, 0xa8a8, 0 }, + { 0xa9a9, 0xa9a9, 0xa9a9, 0 }, + { 0xaaaa, 0xaaaa, 0xaaaa, 0 }, + { 0xabab, 0xabab, 0xabab, 0 }, + { 0xacac, 0xacac, 0xacac, 0 }, + { 0xadad, 0xadad, 0xadad, 0 }, + { 0xaeae, 0xaeae, 0xaeae, 0 }, + { 0xafaf, 0xafaf, 0xafaf, 0 }, + { 0xb0b0, 0xb0b0, 0xb0b0, 0 }, + { 0xb1b1, 0xb1b1, 0xb1b1, 0 }, + { 0xb2b2, 0xb2b2, 0xb2b2, 0 }, + { 0xb3b3, 0xb3b3, 0xb3b3, 0 }, + { 0xb4b4, 0xb4b4, 0xb4b4, 0 }, + { 0xb5b5, 0xb5b5, 0xb5b5, 0 }, + { 0xb6b6, 0xb6b6, 0xb6b6, 0 }, + { 0xb7b7, 0xb7b7, 0xb7b7, 0 }, + { 0xb8b8, 0xb8b8, 0xb8b8, 0 }, + { 0xb9b9, 0xb9b9, 0xb9b9, 0 }, + { 0xbaba, 0xbaba, 0xbaba, 0 }, + { 0xbbbb, 0xbbbb, 0xbbbb, 0 }, + { 0xbcbc, 0xbcbc, 0xbcbc, 0 }, + { 0xbdbd, 0xbdbd, 0xbdbd, 0 }, + { 0xbebe, 0xbebe, 0xbebe, 0 }, + { 0xbfbf, 0xbfbf, 0xbfbf, 0 }, + { 0xc0c0, 0xc0c0, 0xc0c0, 0 }, + { 0xc1c1, 0xc1c1, 0xc1c1, 0 }, + { 0xc2c2, 0xc2c2, 0xc2c2, 0 }, + { 0xc3c3, 0xc3c3, 0xc3c3, 0 }, + { 0xc4c4, 0xc4c4, 0xc4c4, 0 }, + { 0xc5c5, 0xc5c5, 0xc5c5, 0 }, + { 0xc6c6, 0xc6c6, 0xc6c6, 0 }, + { 0xc7c7, 0xc7c7, 0xc7c7, 0 }, + { 0xc8c8, 0xc8c8, 0xc8c8, 0 }, + { 0xc9c9, 0xc9c9, 0xc9c9, 0 }, + { 0xcaca, 0xcaca, 0xcaca, 0 }, + { 0xcbcb, 0xcbcb, 0xcbcb, 0 }, + { 0xcccc, 0xcccc, 0xcccc, 0 }, + { 0xcdcd, 0xcdcd, 0xcdcd, 0 }, + { 0xcece, 0xcece, 0xcece, 0 }, + { 0xcfcf, 0xcfcf, 0xcfcf, 0 }, + { 0xd0d0, 0xd0d0, 0xd0d0, 0 }, + { 0xd1d1, 0xd1d1, 0xd1d1, 0 }, + { 0xd2d2, 0xd2d2, 0xd2d2, 0 }, + { 0xd3d3, 0xd3d3, 0xd3d3, 0 }, + { 0xd4d4, 0xd4d4, 0xd4d4, 0 }, + { 0xd5d5, 0xd5d5, 0xd5d5, 0 }, + { 0xd6d6, 0xd6d6, 0xd6d6, 0 }, + { 0xd7d7, 0xd7d7, 0xd7d7, 0 }, + { 0xd8d8, 0xd8d8, 0xd8d8, 0 }, + { 0xd9d9, 0xd9d9, 0xd9d9, 0 }, + { 0xdada, 0xdada, 0xdada, 0 }, + { 0xdbdb, 0xdbdb, 0xdbdb, 0 }, + { 0xdcdc, 0xdcdc, 0xdcdc, 0 }, + { 0xdddd, 0xdddd, 0xdddd, 0 }, + { 0xdede, 0xdede, 0xdede, 0 }, + { 0xdfdf, 0xdfdf, 0xdfdf, 0 }, + { 0xe0e0, 0xe0e0, 0xe0e0, 0 }, + { 0xe1e1, 0xe1e1, 0xe1e1, 0 }, + { 0xe2e2, 0xe2e2, 0xe2e2, 0 }, + { 0xe3e3, 0xe3e3, 0xe3e3, 0 }, + { 0xe4e4, 0xe4e4, 0xe4e4, 0 }, + { 0xe5e5, 0xe5e5, 0xe5e5, 0 }, + { 0xe6e6, 0xe6e6, 0xe6e6, 0 }, + { 0xe7e7, 0xe7e7, 0xe7e7, 0 }, + { 0xe8e8, 0xe8e8, 0xe8e8, 0 }, + { 0xe9e9, 0xe9e9, 0xe9e9, 0 }, + { 0xeaea, 0xeaea, 0xeaea, 0 }, + { 0xebeb, 0xebeb, 0xebeb, 0 }, + { 0xecec, 0xecec, 0xecec, 0 }, + { 0xeded, 0xeded, 0xeded, 0 }, + { 0xeeee, 0xeeee, 0xeeee, 0 }, + { 0xefef, 0xefef, 0xefef, 0 }, + { 0xf0f0, 0xf0f0, 0xf0f0, 0 }, + { 0xf1f1, 0xf1f1, 0xf1f1, 0 }, + { 0xf2f2, 0xf2f2, 0xf2f2, 0 }, + { 0xf3f3, 0xf3f3, 0xf3f3, 0 }, + { 0xf4f4, 0xf4f4, 0xf4f4, 0 }, + { 0xf5f5, 0xf5f5, 0xf5f5, 0 }, + { 0xf6f6, 0xf6f6, 0xf6f6, 0 }, + { 0xf7f7, 0xf7f7, 0xf7f7, 0 }, + { 0xf8f8, 0xf8f8, 0xf8f8, 0 }, + { 0xf9f9, 0xf9f9, 0xf9f9, 0 }, + { 0xfafa, 0xfafa, 0xfafa, 0 }, + { 0xfbfb, 0xfbfb, 0xfbfb, 0 }, + { 0xfcfc, 0xfcfc, 0xfcfc, 0 }, + { 0xfdfd, 0xfdfd, 0xfdfd, 0 }, + { 0xfefe, 0xfefe, 0xfefe, 0 }, + { 0xffff, 0xffff, 0xffff, 0 }, +}; + +const struct vkms_color_lut linear_eotf = { + .base = linear_array, + .lut_length = LUT_SIZE, + .channel_value2index_ratio = 0xff00ffll +}; +EXPORT_SYMBOL(linear_eotf); + +static struct drm_color_lut srgb_array[LUT_SIZE] = { + { 0x0, 0x0, 0x0, 0 }, + { 0x13, 0x13, 0x13, 0 }, + { 0x27, 0x27, 0x27, 0 }, + { 0x3b, 0x3b, 0x3b, 0 }, + { 0x4f, 0x4f, 0x4f, 0 }, + { 0x63, 0x63, 0x63, 0 }, + { 0x77, 0x77, 0x77, 0 }, + { 0x8b, 0x8b, 0x8b, 0 }, + { 0x9f, 0x9f, 0x9f, 0 }, + { 0xb3, 0xb3, 0xb3, 0 }, + { 0xc6, 0xc6, 0xc6, 0 }, + { 0xdb, 0xdb, 0xdb, 0 }, + { 0xf0, 0xf0, 0xf0, 0 }, + { 0x107, 0x107, 0x107, 0 }, + { 0x11f, 0x11f, 0x11f, 0 }, + { 0x139, 0x139, 0x139, 0 }, + { 0x153, 0x153, 0x153, 0 }, + { 0x16f, 0x16f, 0x16f, 0 }, + { 0x18c, 0x18c, 0x18c, 0 }, + { 0x1aa, 0x1aa, 0x1aa, 0 }, + { 0x1ca, 0x1ca, 0x1ca, 0 }, + { 0x1eb, 0x1eb, 0x1eb, 0 }, + { 0x20d, 0x20d, 0x20d, 0 }, + { 0x231, 0x231, 0x231, 0 }, + { 0x256, 0x256, 0x256, 0 }, + { 0x27d, 0x27d, 0x27d, 0 }, + { 0x2a4, 0x2a4, 0x2a4, 0 }, + { 0x2ce, 0x2ce, 0x2ce, 0 }, + { 0x2f9, 0x2f9, 0x2f9, 0 }, + { 0x325, 0x325, 0x325, 0 }, + { 0x352, 0x352, 0x352, 0 }, + { 0x381, 0x381, 0x381, 0 }, + { 0x3b2, 0x3b2, 0x3b2, 0 }, + { 0x3e4, 0x3e4, 0x3e4, 0 }, + { 0x418, 0x418, 0x418, 0 }, + { 0x44d, 0x44d, 0x44d, 0 }, + { 0x484, 0x484, 0x484, 0 }, + { 0x4bc, 0x4bc, 0x4bc, 0 }, + { 0x4f6, 0x4f6, 0x4f6, 0 }, + { 0x531, 0x531, 0x531, 0 }, + { 0x56e, 0x56e, 0x56e, 0 }, + { 0x5ad, 0x5ad, 0x5ad, 0 }, + { 0x5ed, 0x5ed, 0x5ed, 0 }, + { 0x62f, 0x62f, 0x62f, 0 }, + { 0x672, 0x672, 0x672, 0 }, + { 0x6b7, 0x6b7, 0x6b7, 0 }, + { 0x6fe, 0x6fe, 0x6fe, 0 }, + { 0x746, 0x746, 0x746, 0 }, + { 0x791, 0x791, 0x791, 0 }, + { 0x7dc, 0x7dc, 0x7dc, 0 }, + { 0x82a, 0x82a, 0x82a, 0 }, + { 0x879, 0x879, 0x879, 0 }, + { 0x8ca, 0x8ca, 0x8ca, 0 }, + { 0x91d, 0x91d, 0x91d, 0 }, + { 0x971, 0x971, 0x971, 0 }, + { 0x9c7, 0x9c7, 0x9c7, 0 }, + { 0xa1f, 0xa1f, 0xa1f, 0 }, + { 0xa79, 0xa79, 0xa79, 0 }, + { 0xad4, 0xad4, 0xad4, 0 }, + { 0xb32, 0xb32, 0xb32, 0 }, + { 0xb91, 0xb91, 0xb91, 0 }, + { 0xbf2, 0xbf2, 0xbf2, 0 }, + { 0xc54, 0xc54, 0xc54, 0 }, + { 0xcb9, 0xcb9, 0xcb9, 0 }, + { 0xd1f, 0xd1f, 0xd1f, 0 }, + { 0xd88, 0xd88, 0xd88, 0 }, + { 0xdf2, 0xdf2, 0xdf2, 0 }, + { 0xe5e, 0xe5e, 0xe5e, 0 }, + { 0xecc, 0xecc, 0xecc, 0 }, + { 0xf3c, 0xf3c, 0xf3c, 0 }, + { 0xfad, 0xfad, 0xfad, 0 }, + { 0x1021, 0x1021, 0x1021, 0 }, + { 0x1096, 0x1096, 0x1096, 0 }, + { 0x110e, 0x110e, 0x110e, 0 }, + { 0x1187, 0x1187, 0x1187, 0 }, + { 0x1203, 0x1203, 0x1203, 0 }, + { 0x1280, 0x1280, 0x1280, 0 }, + { 0x12ff, 0x12ff, 0x12ff, 0 }, + { 0x1380, 0x1380, 0x1380, 0 }, + { 0x1404, 0x1404, 0x1404, 0 }, + { 0x1489, 0x1489, 0x1489, 0 }, + { 0x1510, 0x1510, 0x1510, 0 }, + { 0x1599, 0x1599, 0x1599, 0 }, + { 0x1624, 0x1624, 0x1624, 0 }, + { 0x16b2, 0x16b2, 0x16b2, 0 }, + { 0x1741, 0x1741, 0x1741, 0 }, + { 0x17d2, 0x17d2, 0x17d2, 0 }, + { 0x1865, 0x1865, 0x1865, 0 }, + { 0x18fb, 0x18fb, 0x18fb, 0 }, + { 0x1992, 0x1992, 0x1992, 0 }, + { 0x1a2c, 0x1a2c, 0x1a2c, 0 }, + { 0x1ac8, 0x1ac8, 0x1ac8, 0 }, + { 0x1b65, 0x1b65, 0x1b65, 0 }, + { 0x1c05, 0x1c05, 0x1c05, 0 }, + { 0x1ca7, 0x1ca7, 0x1ca7, 0 }, + { 0x1d4b, 0x1d4b, 0x1d4b, 0 }, + { 0x1df1, 0x1df1, 0x1df1, 0 }, + { 0x1e99, 0x1e99, 0x1e99, 0 }, + { 0x1f44, 0x1f44, 0x1f44, 0 }, + { 0x1ff0, 0x1ff0, 0x1ff0, 0 }, + { 0x209f, 0x209f, 0x209f, 0 }, + { 0x2150, 0x2150, 0x2150, 0 }, + { 0x2203, 0x2203, 0x2203, 0 }, + { 0x22b8, 0x22b8, 0x22b8, 0 }, + { 0x2370, 0x2370, 0x2370, 0 }, + { 0x2429, 0x2429, 0x2429, 0 }, + { 0x24e5, 0x24e5, 0x24e5, 0 }, + { 0x25a3, 0x25a3, 0x25a3, 0 }, + { 0x2663, 0x2663, 0x2663, 0 }, + { 0x2726, 0x2726, 0x2726, 0 }, + { 0x27ea, 0x27ea, 0x27ea, 0 }, + { 0x28b1, 0x28b1, 0x28b1, 0 }, + { 0x297a, 0x297a, 0x297a, 0 }, + { 0x2a45, 0x2a45, 0x2a45, 0 }, + { 0x2b13, 0x2b13, 0x2b13, 0 }, + { 0x2be3, 0x2be3, 0x2be3, 0 }, + { 0x2cb5, 0x2cb5, 0x2cb5, 0 }, + { 0x2d89, 0x2d89, 0x2d89, 0 }, + { 0x2e60, 0x2e60, 0x2e60, 0 }, + { 0x2f39, 0x2f39, 0x2f39, 0 }, + { 0x3014, 0x3014, 0x3014, 0 }, + { 0x30f2, 0x30f2, 0x30f2, 0 }, + { 0x31d2, 0x31d2, 0x31d2, 0 }, + { 0x32b4, 0x32b4, 0x32b4, 0 }, + { 0x3398, 0x3398, 0x3398, 0 }, + { 0x347f, 0x347f, 0x347f, 0 }, + { 0x3569, 0x3569, 0x3569, 0 }, + { 0x3654, 0x3654, 0x3654, 0 }, + { 0x3742, 0x3742, 0x3742, 0 }, + { 0x3832, 0x3832, 0x3832, 0 }, + { 0x3925, 0x3925, 0x3925, 0 }, + { 0x3a1a, 0x3a1a, 0x3a1a, 0 }, + { 0x3b11, 0x3b11, 0x3b11, 0 }, + { 0x3c0b, 0x3c0b, 0x3c0b, 0 }, + { 0x3d07, 0x3d07, 0x3d07, 0 }, + { 0x3e05, 0x3e05, 0x3e05, 0 }, + { 0x3f06, 0x3f06, 0x3f06, 0 }, + { 0x400a, 0x400a, 0x400a, 0 }, + { 0x410f, 0x410f, 0x410f, 0 }, + { 0x4218, 0x4218, 0x4218, 0 }, + { 0x4322, 0x4322, 0x4322, 0 }, + { 0x442f, 0x442f, 0x442f, 0 }, + { 0x453f, 0x453f, 0x453f, 0 }, + { 0x4650, 0x4650, 0x4650, 0 }, + { 0x4765, 0x4765, 0x4765, 0 }, + { 0x487c, 0x487c, 0x487c, 0 }, + { 0x4995, 0x4995, 0x4995, 0 }, + { 0x4ab1, 0x4ab1, 0x4ab1, 0 }, + { 0x4bcf, 0x4bcf, 0x4bcf, 0 }, + { 0x4cf0, 0x4cf0, 0x4cf0, 0 }, + { 0x4e13, 0x4e13, 0x4e13, 0 }, + { 0x4f39, 0x4f39, 0x4f39, 0 }, + { 0x5061, 0x5061, 0x5061, 0 }, + { 0x518b, 0x518b, 0x518b, 0 }, + { 0x52b9, 0x52b9, 0x52b9, 0 }, + { 0x53e8, 0x53e8, 0x53e8, 0 }, + { 0x551b, 0x551b, 0x551b, 0 }, + { 0x5650, 0x5650, 0x5650, 0 }, + { 0x5787, 0x5787, 0x5787, 0 }, + { 0x58c1, 0x58c1, 0x58c1, 0 }, + { 0x59fd, 0x59fd, 0x59fd, 0 }, + { 0x5b3c, 0x5b3c, 0x5b3c, 0 }, + { 0x5c7e, 0x5c7e, 0x5c7e, 0 }, + { 0x5dc2, 0x5dc2, 0x5dc2, 0 }, + { 0x5f09, 0x5f09, 0x5f09, 0 }, + { 0x6052, 0x6052, 0x6052, 0 }, + { 0x619e, 0x619e, 0x619e, 0 }, + { 0x62ec, 0x62ec, 0x62ec, 0 }, + { 0x643d, 0x643d, 0x643d, 0 }, + { 0x6591, 0x6591, 0x6591, 0 }, + { 0x66e7, 0x66e7, 0x66e7, 0 }, + { 0x6840, 0x6840, 0x6840, 0 }, + { 0x699b, 0x699b, 0x699b, 0 }, + { 0x6afa, 0x6afa, 0x6afa, 0 }, + { 0x6c5a, 0x6c5a, 0x6c5a, 0 }, + { 0x6dbe, 0x6dbe, 0x6dbe, 0 }, + { 0x6f24, 0x6f24, 0x6f24, 0 }, + { 0x708c, 0x708c, 0x708c, 0 }, + { 0x71f8, 0x71f8, 0x71f8, 0 }, + { 0x7366, 0x7366, 0x7366, 0 }, + { 0x74d6, 0x74d6, 0x74d6, 0 }, + { 0x764a, 0x764a, 0x764a, 0 }, + { 0x77c0, 0x77c0, 0x77c0, 0 }, + { 0x7938, 0x7938, 0x7938, 0 }, + { 0x7ab4, 0x7ab4, 0x7ab4, 0 }, + { 0x7c32, 0x7c32, 0x7c32, 0 }, + { 0x7db3, 0x7db3, 0x7db3, 0 }, + { 0x7f36, 0x7f36, 0x7f36, 0 }, + { 0x80bc, 0x80bc, 0x80bc, 0 }, + { 0x8245, 0x8245, 0x8245, 0 }, + { 0x83d1, 0x83d1, 0x83d1, 0 }, + { 0x855f, 0x855f, 0x855f, 0 }, + { 0x86f0, 0x86f0, 0x86f0, 0 }, + { 0x8884, 0x8884, 0x8884, 0 }, + { 0x8a1a, 0x8a1a, 0x8a1a, 0 }, + { 0x8bb4, 0x8bb4, 0x8bb4, 0 }, + { 0x8d50, 0x8d50, 0x8d50, 0 }, + { 0x8eee, 0x8eee, 0x8eee, 0 }, + { 0x9090, 0x9090, 0x9090, 0 }, + { 0x9234, 0x9234, 0x9234, 0 }, + { 0x93db, 0x93db, 0x93db, 0 }, + { 0x9585, 0x9585, 0x9585, 0 }, + { 0x9732, 0x9732, 0x9732, 0 }, + { 0x98e1, 0x98e1, 0x98e1, 0 }, + { 0x9a93, 0x9a93, 0x9a93, 0 }, + { 0x9c48, 0x9c48, 0x9c48, 0 }, + { 0x9e00, 0x9e00, 0x9e00, 0 }, + { 0x9fbb, 0x9fbb, 0x9fbb, 0 }, + { 0xa178, 0xa178, 0xa178, 0 }, + { 0xa338, 0xa338, 0xa338, 0 }, + { 0xa4fb, 0xa4fb, 0xa4fb, 0 }, + { 0xa6c1, 0xa6c1, 0xa6c1, 0 }, + { 0xa88a, 0xa88a, 0xa88a, 0 }, + { 0xaa56, 0xaa56, 0xaa56, 0 }, + { 0xac24, 0xac24, 0xac24, 0 }, + { 0xadf5, 0xadf5, 0xadf5, 0 }, + { 0xafc9, 0xafc9, 0xafc9, 0 }, + { 0xb1a0, 0xb1a0, 0xb1a0, 0 }, + { 0xb37a, 0xb37a, 0xb37a, 0 }, + { 0xb557, 0xb557, 0xb557, 0 }, + { 0xb736, 0xb736, 0xb736, 0 }, + { 0xb919, 0xb919, 0xb919, 0 }, + { 0xbafe, 0xbafe, 0xbafe, 0 }, + { 0xbce6, 0xbce6, 0xbce6, 0 }, + { 0xbed2, 0xbed2, 0xbed2, 0 }, + { 0xc0c0, 0xc0c0, 0xc0c0, 0 }, + { 0xc2b0, 0xc2b0, 0xc2b0, 0 }, + { 0xc4a4, 0xc4a4, 0xc4a4, 0 }, + { 0xc69b, 0xc69b, 0xc69b, 0 }, + { 0xc895, 0xc895, 0xc895, 0 }, + { 0xca91, 0xca91, 0xca91, 0 }, + { 0xcc91, 0xcc91, 0xcc91, 0 }, + { 0xce93, 0xce93, 0xce93, 0 }, + { 0xd098, 0xd098, 0xd098, 0 }, + { 0xd2a1, 0xd2a1, 0xd2a1, 0 }, + { 0xd4ac, 0xd4ac, 0xd4ac, 0 }, + { 0xd6ba, 0xd6ba, 0xd6ba, 0 }, + { 0xd8cb, 0xd8cb, 0xd8cb, 0 }, + { 0xdadf, 0xdadf, 0xdadf, 0 }, + { 0xdcf7, 0xdcf7, 0xdcf7, 0 }, + { 0xdf11, 0xdf11, 0xdf11, 0 }, + { 0xe12e, 0xe12e, 0xe12e, 0 }, + { 0xe34e, 0xe34e, 0xe34e, 0 }, + { 0xe571, 0xe571, 0xe571, 0 }, + { 0xe796, 0xe796, 0xe796, 0 }, + { 0xe9bf, 0xe9bf, 0xe9bf, 0 }, + { 0xebeb, 0xebeb, 0xebeb, 0 }, + { 0xee1a, 0xee1a, 0xee1a, 0 }, + { 0xf04c, 0xf04c, 0xf04c, 0 }, + { 0xf281, 0xf281, 0xf281, 0 }, + { 0xf4b9, 0xf4b9, 0xf4b9, 0 }, + { 0xf6f4, 0xf6f4, 0xf6f4, 0 }, + { 0xf932, 0xf932, 0xf932, 0 }, + { 0xfb73, 0xfb73, 0xfb73, 0 }, + { 0xfdb7, 0xfdb7, 0xfdb7, 0 }, + { 0xffff, 0xffff, 0xffff, 0 }, +}; + +const struct vkms_color_lut srgb_eotf = { + .base = srgb_array, + .lut_length = LUT_SIZE, + .channel_value2index_ratio = 0xff00ffll +}; +EXPORT_SYMBOL(srgb_eotf); + +static struct drm_color_lut srgb_inv_array[LUT_SIZE] = { + { 0x0, 0x0, 0x0, 0 }, + { 0xcc2, 0xcc2, 0xcc2, 0 }, + { 0x15be, 0x15be, 0x15be, 0 }, + { 0x1c56, 0x1c56, 0x1c56, 0 }, + { 0x21bd, 0x21bd, 0x21bd, 0 }, + { 0x2666, 0x2666, 0x2666, 0 }, + { 0x2a8a, 0x2a8a, 0x2a8a, 0 }, + { 0x2e4c, 0x2e4c, 0x2e4c, 0 }, + { 0x31c0, 0x31c0, 0x31c0, 0 }, + { 0x34f6, 0x34f6, 0x34f6, 0 }, + { 0x37f9, 0x37f9, 0x37f9, 0 }, + { 0x3acf, 0x3acf, 0x3acf, 0 }, + { 0x3d80, 0x3d80, 0x3d80, 0 }, + { 0x4010, 0x4010, 0x4010, 0 }, + { 0x4284, 0x4284, 0x4284, 0 }, + { 0x44dd, 0x44dd, 0x44dd, 0 }, + { 0x4720, 0x4720, 0x4720, 0 }, + { 0x494e, 0x494e, 0x494e, 0 }, + { 0x4b69, 0x4b69, 0x4b69, 0 }, + { 0x4d73, 0x4d73, 0x4d73, 0 }, + { 0x4f6e, 0x4f6e, 0x4f6e, 0 }, + { 0x5159, 0x5159, 0x5159, 0 }, + { 0x5337, 0x5337, 0x5337, 0 }, + { 0x5509, 0x5509, 0x5509, 0 }, + { 0x56cf, 0x56cf, 0x56cf, 0 }, + { 0x588a, 0x588a, 0x588a, 0 }, + { 0x5a3b, 0x5a3b, 0x5a3b, 0 }, + { 0x5be2, 0x5be2, 0x5be2, 0 }, + { 0x5d80, 0x5d80, 0x5d80, 0 }, + { 0x5f16, 0x5f16, 0x5f16, 0 }, + { 0x60a4, 0x60a4, 0x60a4, 0 }, + { 0x6229, 0x6229, 0x6229, 0 }, + { 0x63a8, 0x63a8, 0x63a8, 0 }, + { 0x6520, 0x6520, 0x6520, 0 }, + { 0x6691, 0x6691, 0x6691, 0 }, + { 0x67fc, 0x67fc, 0x67fc, 0 }, + { 0x6961, 0x6961, 0x6961, 0 }, + { 0x6ac0, 0x6ac0, 0x6ac0, 0 }, + { 0x6c19, 0x6c19, 0x6c19, 0 }, + { 0x6d6e, 0x6d6e, 0x6d6e, 0 }, + { 0x6ebd, 0x6ebd, 0x6ebd, 0 }, + { 0x7008, 0x7008, 0x7008, 0 }, + { 0x714d, 0x714d, 0x714d, 0 }, + { 0x728f, 0x728f, 0x728f, 0 }, + { 0x73cc, 0x73cc, 0x73cc, 0 }, + { 0x7504, 0x7504, 0x7504, 0 }, + { 0x7639, 0x7639, 0x7639, 0 }, + { 0x776a, 0x776a, 0x776a, 0 }, + { 0x7897, 0x7897, 0x7897, 0 }, + { 0x79c1, 0x79c1, 0x79c1, 0 }, + { 0x7ae7, 0x7ae7, 0x7ae7, 0 }, + { 0x7c09, 0x7c09, 0x7c09, 0 }, + { 0x7d28, 0x7d28, 0x7d28, 0 }, + { 0x7e44, 0x7e44, 0x7e44, 0 }, + { 0x7f5d, 0x7f5d, 0x7f5d, 0 }, + { 0x8073, 0x8073, 0x8073, 0 }, + { 0x8186, 0x8186, 0x8186, 0 }, + { 0x8296, 0x8296, 0x8296, 0 }, + { 0x83a4, 0x83a4, 0x83a4, 0 }, + { 0x84ae, 0x84ae, 0x84ae, 0 }, + { 0x85b6, 0x85b6, 0x85b6, 0 }, + { 0x86bc, 0x86bc, 0x86bc, 0 }, + { 0x87bf, 0x87bf, 0x87bf, 0 }, + { 0x88bf, 0x88bf, 0x88bf, 0 }, + { 0x89be, 0x89be, 0x89be, 0 }, + { 0x8ab9, 0x8ab9, 0x8ab9, 0 }, + { 0x8bb3, 0x8bb3, 0x8bb3, 0 }, + { 0x8cab, 0x8cab, 0x8cab, 0 }, + { 0x8da0, 0x8da0, 0x8da0, 0 }, + { 0x8e93, 0x8e93, 0x8e93, 0 }, + { 0x8f84, 0x8f84, 0x8f84, 0 }, + { 0x9073, 0x9073, 0x9073, 0 }, + { 0x9161, 0x9161, 0x9161, 0 }, + { 0x924c, 0x924c, 0x924c, 0 }, + { 0x9335, 0x9335, 0x9335, 0 }, + { 0x941d, 0x941d, 0x941d, 0 }, + { 0x9503, 0x9503, 0x9503, 0 }, + { 0x95e7, 0x95e7, 0x95e7, 0 }, + { 0x96c9, 0x96c9, 0x96c9, 0 }, + { 0x97aa, 0x97aa, 0x97aa, 0 }, + { 0x9889, 0x9889, 0x9889, 0 }, + { 0x9966, 0x9966, 0x9966, 0 }, + { 0x9a42, 0x9a42, 0x9a42, 0 }, + { 0x9b1c, 0x9b1c, 0x9b1c, 0 }, + { 0x9bf5, 0x9bf5, 0x9bf5, 0 }, + { 0x9ccc, 0x9ccc, 0x9ccc, 0 }, + { 0x9da1, 0x9da1, 0x9da1, 0 }, + { 0x9e76, 0x9e76, 0x9e76, 0 }, + { 0x9f49, 0x9f49, 0x9f49, 0 }, + { 0xa01a, 0xa01a, 0xa01a, 0 }, + { 0xa0ea, 0xa0ea, 0xa0ea, 0 }, + { 0xa1b9, 0xa1b9, 0xa1b9, 0 }, + { 0xa286, 0xa286, 0xa286, 0 }, + { 0xa352, 0xa352, 0xa352, 0 }, + { 0xa41d, 0xa41d, 0xa41d, 0 }, + { 0xa4e7, 0xa4e7, 0xa4e7, 0 }, + { 0xa5af, 0xa5af, 0xa5af, 0 }, + { 0xa676, 0xa676, 0xa676, 0 }, + { 0xa73c, 0xa73c, 0xa73c, 0 }, + { 0xa801, 0xa801, 0xa801, 0 }, + { 0xa8c5, 0xa8c5, 0xa8c5, 0 }, + { 0xa987, 0xa987, 0xa987, 0 }, + { 0xaa48, 0xaa48, 0xaa48, 0 }, + { 0xab09, 0xab09, 0xab09, 0 }, + { 0xabc8, 0xabc8, 0xabc8, 0 }, + { 0xac86, 0xac86, 0xac86, 0 }, + { 0xad43, 0xad43, 0xad43, 0 }, + { 0xadff, 0xadff, 0xadff, 0 }, + { 0xaeba, 0xaeba, 0xaeba, 0 }, + { 0xaf74, 0xaf74, 0xaf74, 0 }, + { 0xb02d, 0xb02d, 0xb02d, 0 }, + { 0xb0e5, 0xb0e5, 0xb0e5, 0 }, + { 0xb19c, 0xb19c, 0xb19c, 0 }, + { 0xb252, 0xb252, 0xb252, 0 }, + { 0xb307, 0xb307, 0xb307, 0 }, + { 0xb3bb, 0xb3bb, 0xb3bb, 0 }, + { 0xb46f, 0xb46f, 0xb46f, 0 }, + { 0xb521, 0xb521, 0xb521, 0 }, + { 0xb5d3, 0xb5d3, 0xb5d3, 0 }, + { 0xb683, 0xb683, 0xb683, 0 }, + { 0xb733, 0xb733, 0xb733, 0 }, + { 0xb7e2, 0xb7e2, 0xb7e2, 0 }, + { 0xb890, 0xb890, 0xb890, 0 }, + { 0xb93d, 0xb93d, 0xb93d, 0 }, + { 0xb9ea, 0xb9ea, 0xb9ea, 0 }, + { 0xba96, 0xba96, 0xba96, 0 }, + { 0xbb40, 0xbb40, 0xbb40, 0 }, + { 0xbbea, 0xbbea, 0xbbea, 0 }, + { 0xbc94, 0xbc94, 0xbc94, 0 }, + { 0xbd3c, 0xbd3c, 0xbd3c, 0 }, + { 0xbde4, 0xbde4, 0xbde4, 0 }, + { 0xbe8b, 0xbe8b, 0xbe8b, 0 }, + { 0xbf31, 0xbf31, 0xbf31, 0 }, + { 0xbfd7, 0xbfd7, 0xbfd7, 0 }, + { 0xc07b, 0xc07b, 0xc07b, 0 }, + { 0xc120, 0xc120, 0xc120, 0 }, + { 0xc1c3, 0xc1c3, 0xc1c3, 0 }, + { 0xc266, 0xc266, 0xc266, 0 }, + { 0xc308, 0xc308, 0xc308, 0 }, + { 0xc3a9, 0xc3a9, 0xc3a9, 0 }, + { 0xc449, 0xc449, 0xc449, 0 }, + { 0xc4e9, 0xc4e9, 0xc4e9, 0 }, + { 0xc589, 0xc589, 0xc589, 0 }, + { 0xc627, 0xc627, 0xc627, 0 }, + { 0xc6c5, 0xc6c5, 0xc6c5, 0 }, + { 0xc763, 0xc763, 0xc763, 0 }, + { 0xc7ff, 0xc7ff, 0xc7ff, 0 }, + { 0xc89b, 0xc89b, 0xc89b, 0 }, + { 0xc937, 0xc937, 0xc937, 0 }, + { 0xc9d2, 0xc9d2, 0xc9d2, 0 }, + { 0xca6c, 0xca6c, 0xca6c, 0 }, + { 0xcb06, 0xcb06, 0xcb06, 0 }, + { 0xcb9f, 0xcb9f, 0xcb9f, 0 }, + { 0xcc37, 0xcc37, 0xcc37, 0 }, + { 0xcccf, 0xcccf, 0xcccf, 0 }, + { 0xcd66, 0xcd66, 0xcd66, 0 }, + { 0xcdfd, 0xcdfd, 0xcdfd, 0 }, + { 0xce93, 0xce93, 0xce93, 0 }, + { 0xcf29, 0xcf29, 0xcf29, 0 }, + { 0xcfbe, 0xcfbe, 0xcfbe, 0 }, + { 0xd053, 0xd053, 0xd053, 0 }, + { 0xd0e7, 0xd0e7, 0xd0e7, 0 }, + { 0xd17a, 0xd17a, 0xd17a, 0 }, + { 0xd20d, 0xd20d, 0xd20d, 0 }, + { 0xd2a0, 0xd2a0, 0xd2a0, 0 }, + { 0xd331, 0xd331, 0xd331, 0 }, + { 0xd3c3, 0xd3c3, 0xd3c3, 0 }, + { 0xd454, 0xd454, 0xd454, 0 }, + { 0xd4e4, 0xd4e4, 0xd4e4, 0 }, + { 0xd574, 0xd574, 0xd574, 0 }, + { 0xd603, 0xd603, 0xd603, 0 }, + { 0xd692, 0xd692, 0xd692, 0 }, + { 0xd720, 0xd720, 0xd720, 0 }, + { 0xd7ae, 0xd7ae, 0xd7ae, 0 }, + { 0xd83c, 0xd83c, 0xd83c, 0 }, + { 0xd8c9, 0xd8c9, 0xd8c9, 0 }, + { 0xd955, 0xd955, 0xd955, 0 }, + { 0xd9e1, 0xd9e1, 0xd9e1, 0 }, + { 0xda6d, 0xda6d, 0xda6d, 0 }, + { 0xdaf8, 0xdaf8, 0xdaf8, 0 }, + { 0xdb83, 0xdb83, 0xdb83, 0 }, + { 0xdc0d, 0xdc0d, 0xdc0d, 0 }, + { 0xdc97, 0xdc97, 0xdc97, 0 }, + { 0xdd20, 0xdd20, 0xdd20, 0 }, + { 0xdda9, 0xdda9, 0xdda9, 0 }, + { 0xde31, 0xde31, 0xde31, 0 }, + { 0xdeb9, 0xdeb9, 0xdeb9, 0 }, + { 0xdf41, 0xdf41, 0xdf41, 0 }, + { 0xdfc8, 0xdfc8, 0xdfc8, 0 }, + { 0xe04f, 0xe04f, 0xe04f, 0 }, + { 0xe0d5, 0xe0d5, 0xe0d5, 0 }, + { 0xe15b, 0xe15b, 0xe15b, 0 }, + { 0xe1e0, 0xe1e0, 0xe1e0, 0 }, + { 0xe266, 0xe266, 0xe266, 0 }, + { 0xe2ea, 0xe2ea, 0xe2ea, 0 }, + { 0xe36f, 0xe36f, 0xe36f, 0 }, + { 0xe3f3, 0xe3f3, 0xe3f3, 0 }, + { 0xe476, 0xe476, 0xe476, 0 }, + { 0xe4f9, 0xe4f9, 0xe4f9, 0 }, + { 0xe57c, 0xe57c, 0xe57c, 0 }, + { 0xe5fe, 0xe5fe, 0xe5fe, 0 }, + { 0xe680, 0xe680, 0xe680, 0 }, + { 0xe702, 0xe702, 0xe702, 0 }, + { 0xe783, 0xe783, 0xe783, 0 }, + { 0xe804, 0xe804, 0xe804, 0 }, + { 0xe884, 0xe884, 0xe884, 0 }, + { 0xe905, 0xe905, 0xe905, 0 }, + { 0xe984, 0xe984, 0xe984, 0 }, + { 0xea04, 0xea04, 0xea04, 0 }, + { 0xea83, 0xea83, 0xea83, 0 }, + { 0xeb02, 0xeb02, 0xeb02, 0 }, + { 0xeb80, 0xeb80, 0xeb80, 0 }, + { 0xebfe, 0xebfe, 0xebfe, 0 }, + { 0xec7b, 0xec7b, 0xec7b, 0 }, + { 0xecf9, 0xecf9, 0xecf9, 0 }, + { 0xed76, 0xed76, 0xed76, 0 }, + { 0xedf2, 0xedf2, 0xedf2, 0 }, + { 0xee6f, 0xee6f, 0xee6f, 0 }, + { 0xeeeb, 0xeeeb, 0xeeeb, 0 }, + { 0xef66, 0xef66, 0xef66, 0 }, + { 0xefe2, 0xefe2, 0xefe2, 0 }, + { 0xf05d, 0xf05d, 0xf05d, 0 }, + { 0xf0d7, 0xf0d7, 0xf0d7, 0 }, + { 0xf152, 0xf152, 0xf152, 0 }, + { 0xf1cc, 0xf1cc, 0xf1cc, 0 }, + { 0xf245, 0xf245, 0xf245, 0 }, + { 0xf2bf, 0xf2bf, 0xf2bf, 0 }, + { 0xf338, 0xf338, 0xf338, 0 }, + { 0xf3b0, 0xf3b0, 0xf3b0, 0 }, + { 0xf429, 0xf429, 0xf429, 0 }, + { 0xf4a1, 0xf4a1, 0xf4a1, 0 }, + { 0xf519, 0xf519, 0xf519, 0 }, + { 0xf590, 0xf590, 0xf590, 0 }, + { 0xf608, 0xf608, 0xf608, 0 }, + { 0xf67e, 0xf67e, 0xf67e, 0 }, + { 0xf6f5, 0xf6f5, 0xf6f5, 0 }, + { 0xf76b, 0xf76b, 0xf76b, 0 }, + { 0xf7e1, 0xf7e1, 0xf7e1, 0 }, + { 0xf857, 0xf857, 0xf857, 0 }, + { 0xf8cd, 0xf8cd, 0xf8cd, 0 }, + { 0xf942, 0xf942, 0xf942, 0 }, + { 0xf9b7, 0xf9b7, 0xf9b7, 0 }, + { 0xfa2b, 0xfa2b, 0xfa2b, 0 }, + { 0xfaa0, 0xfaa0, 0xfaa0, 0 }, + { 0xfb14, 0xfb14, 0xfb14, 0 }, + { 0xfb88, 0xfb88, 0xfb88, 0 }, + { 0xfbfb, 0xfbfb, 0xfbfb, 0 }, + { 0xfc6e, 0xfc6e, 0xfc6e, 0 }, + { 0xfce1, 0xfce1, 0xfce1, 0 }, + { 0xfd54, 0xfd54, 0xfd54, 0 }, + { 0xfdc6, 0xfdc6, 0xfdc6, 0 }, + { 0xfe39, 0xfe39, 0xfe39, 0 }, + { 0xfeaa, 0xfeaa, 0xfeaa, 0 }, + { 0xff1c, 0xff1c, 0xff1c, 0 }, + { 0xff8d, 0xff8d, 0xff8d, 0 }, + { 0xffff, 0xffff, 0xffff, 0 }, +}; + +const struct vkms_color_lut srgb_inv_eotf = { + .base = srgb_inv_array, + .lut_length = LUT_SIZE, + .channel_value2index_ratio = 0xff00ffll +}; +EXPORT_SYMBOL(srgb_inv_eotf); diff --git a/drivers/gpu/drm/vkms/vkms_luts.h b/drivers/gpu/drm/vkms/vkms_luts.h new file mode 100644 index 000000000000..925a4a7b84e2 --- /dev/null +++ b/drivers/gpu/drm/vkms/vkms_luts.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef _VKMS_LUTS_H_ +#define _VKMS_LUTS_H_ + +#define LUT_SIZE 256 + +extern const struct vkms_color_lut linear_eotf; +extern const struct vkms_color_lut srgb_eotf; +extern const struct vkms_color_lut srgb_inv_eotf; + +#endif /* _VKMS_LUTS_H_ */ diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c index 2ee3749e2b28..86ce07a617f5 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -4,6 +4,7 @@ #include "vkms_connector.h" #include "vkms_drv.h" #include <drm/drm_managed.h> +#include <drm/drm_print.h> int vkms_output_init(struct vkms_device *vkmsdev) { @@ -19,11 +20,7 @@ int vkms_output_init(struct vkms_device *vkmsdev) return -EINVAL; vkms_config_for_each_plane(vkmsdev->config, plane_cfg) { - enum drm_plane_type type; - - type = vkms_config_plane_get_type(plane_cfg); - - plane_cfg->plane = vkms_plane_init(vkmsdev, type); + plane_cfg->plane = vkms_plane_init(vkmsdev, plane_cfg); if (IS_ERR(plane_cfg->plane)) { DRM_DEV_ERROR(dev->dev, "Failed to init vkms plane\n"); return PTR_ERR(plane_cfg->plane); diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c index e592e47a5736..19fe6acad306 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ +#include "vkms_config.h" #include <linux/iosys-map.h> #include <drm/drm_atomic.h> @@ -8,6 +9,7 @@ #include <drm/drm_fourcc.h> #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_print.h> #include "vkms_drv.h" #include "vkms_formats.h" @@ -217,7 +219,7 @@ static const struct drm_plane_helper_funcs vkms_plane_helper_funcs = { }; struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, - enum drm_plane_type type) + struct vkms_config_plane *plane_cfg) { struct drm_device *dev = &vkmsdev->drm; struct vkms_plane *plane; @@ -225,7 +227,8 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 0, &vkms_plane_funcs, vkms_formats, ARRAY_SIZE(vkms_formats), - NULL, type, NULL); + NULL, vkms_config_plane_get_type(plane_cfg), + NULL); if (IS_ERR(plane)) return plane; @@ -243,5 +246,8 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, DRM_COLOR_YCBCR_BT601, DRM_COLOR_YCBCR_FULL_RANGE); + if (vkms_config_plane_get_default_pipeline(plane_cfg)) + vkms_initialize_colorops(&plane->base); + return plane; } diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c index 45d69a3b85f6..097ae1f0a230 100644 --- a/drivers/gpu/drm/vkms/vkms_writeback.c +++ b/drivers/gpu/drm/vkms/vkms_writeback.c @@ -6,6 +6,7 @@ #include <drm/drm_edid.h> #include <drm/drm_fourcc.h> #include <drm/drm_writeback.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_gem_framebuffer_helper.h> |
