* Re: [PATCH v3 20/20] Documentation: gpu: vc4: Add KUnit Tests Section
[not found] ` <20221123-rpi-kunit-tests-v3-20-4615a663a84a@cerno.tech>
@ 2022-12-07 13:55 ` Maíra Canal
0 siblings, 0 replies; 7+ messages in thread
From: Maíra Canal @ 2022-12-07 13:55 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, linux-kselftest, kunit-dev, linux-media
On 12/1/22 12:11, Maxime Ripard wrote:
> Now that we have VC4-specific tests in place, let's document them
> properly.
>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Just a small nit below.
> ---
> Documentation/gpu/vc4.rst | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/Documentation/gpu/vc4.rst b/Documentation/gpu/vc4.rst
> index 5df1d98b9544..a2375f1584e6 100644
> --- a/Documentation/gpu/vc4.rst
> +++ b/Documentation/gpu/vc4.rst
> @@ -54,6 +54,22 @@ VEC (Composite TV out) encoder
> .. kernel-doc:: drivers/gpu/drm/vc4/vc4_vec.c
> :doc: VC4 SDTV module
>
> +KUnit Tests
> +===========
> +
> +The VC4 Driver uses KUnit to perform driver-specific unit and
> +integration tests.
> +
> +These tests are using a mock driver and can be ran using the
> +command::
> + ./tools/testing/kunit/kunit.py run \
> + --kunitconfig=drivers/gpu/drm/vc4/tests/.kunitconfig \
> + --cross_compile aarch64-linux-gnu- --arch arm64
I believe you could use a code block here, like:
.. code-block:: bash
$ ./tools/testing/kunit/kunit.py run \
--kunitconfig=drivers/gpu/drm/vc4/tests/.kunitconfig \
--cross_compile aarch64-linux-gnu- --arch arm64
You could also mention that you can run the tests with --arch arm.
Best Regards,
- Maíra Canal
> +
> +Parts of the driver that are currently covered by tests are:
> + * The HVS to PixelValve dynamic FIFO assignment, for the BCM2835-7
> + and BCM2711.
> +
> Memory Management and 3D Command Submission
> ===========================================
>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v3 02/20] drm/tests: Introduce a config option for the KUnit helpers
[not found] ` <20221123-rpi-kunit-tests-v3-2-4615a663a84a@cerno.tech>
@ 2022-12-07 13:57 ` Maíra Canal
0 siblings, 0 replies; 7+ messages in thread
From: Maíra Canal @ 2022-12-07 13:57 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, linux-kselftest, kunit-dev, linux-media
On 12/1/22 12:11, Maxime Ripard wrote:
> Driver-specific tests will need access to the helpers without pulling
> every DRM framework test. Let's create an intermediate Kconfig options
> for the helpers.
>
> Suggested-by: Maíra Canal <mcanal@igalia.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/Kconfig | 7 +++++++
> drivers/gpu/drm/Makefile | 2 +-
> drivers/gpu/drm/tests/Makefile | 4 +++-
> 3 files changed, 11 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 315cbdf61979..9f019cd053e1 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -63,6 +63,12 @@ config DRM_USE_DYNAMIC_DEBUG
> bytes per callsite, the .data costs can be substantial, and
> are therefore configurable.
>
> +config DRM_KUNIT_TEST_HELPERS
> + tristate
> + depends on DRM && KUNIT
> + help
> + KUnit Helpers for KMS drivers.
> +
> config DRM_KUNIT_TEST
> tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS
> depends on DRM && KUNIT
> @@ -73,6 +79,7 @@ config DRM_KUNIT_TEST
> select DRM_KMS_HELPER
> select DRM_BUDDY
> select DRM_EXPORT_FOR_TESTS if m
> + select DRM_KUNIT_TEST_HELPERS
> default KUNIT_ALL_TESTS
> help
> This builds unit tests for DRM. This option is not useful for
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index f92cd7892711..8d61fbdfdfac 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -125,7 +125,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
> # Drivers and the rest
> #
>
> -obj-$(CONFIG_DRM_KUNIT_TEST) += tests/
> +obj-y += tests/
>
> obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
> obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
> diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
> index 94fe546d937d..ef14bd481139 100644
> --- a/drivers/gpu/drm/tests/Makefile
> +++ b/drivers/gpu/drm/tests/Makefile
> @@ -1,5 +1,8 @@
> # SPDX-License-Identifier: GPL-2.0
>
> +obj-$(CONFIG_DRM_KUNIT_TEST_HELPERS) += \
> + drm_kunit_helpers.o
> +
> obj-$(CONFIG_DRM_KUNIT_TEST) += \
> drm_buddy_test.o \
> drm_cmdline_parser_test.o \
> @@ -9,7 +12,6 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \
> drm_format_helper_test.o \
> drm_format_test.o \
> drm_framebuffer_test.o \
> - drm_kunit_helpers.o \
> drm_mm_test.o \
> drm_modes_test.o \
> drm_plane_helper_test.o \
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v3 04/20] drm/tests: helpers: Switch to EXPORT_SYMBOL_GPL
[not found] ` <20221123-rpi-kunit-tests-v3-4-4615a663a84a@cerno.tech>
@ 2022-12-07 13:59 ` Maíra Canal
0 siblings, 0 replies; 7+ messages in thread
From: Maíra Canal @ 2022-12-07 13:59 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, linux-kselftest, kunit-dev, linux-media
On 12/1/22 12:11, Maxime Ripard wrote:
> drm_kunit_device_init() among other things will allocate a device and
> wrap around root_device_register. This function is exported with
> EXPORT_SYMBOL_GPL, so we can't really change the license.
>
> Fixes: 199557fab925 ("drm/tests: helpers: Add missing export")
> Suggested-by: Javier Martinez Canillas <javierm@redhat.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/tests/drm_kunit_helpers.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
> index 9ed3cfc2ac03..4fe131141718 100644
> --- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
> +++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
> @@ -82,7 +82,7 @@ struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char
>
> return drm;
> }
> -EXPORT_SYMBOL(drm_kunit_device_init);
> +EXPORT_SYMBOL_GPL(drm_kunit_device_init);
>
> MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
> MODULE_LICENSE("GPL");
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v3 17/20] drm/vc4: tests: Introduce a mocking infrastructure
[not found] ` <20221123-rpi-kunit-tests-v3-17-4615a663a84a@cerno.tech>
@ 2022-12-07 14:08 ` Maíra Canal
0 siblings, 0 replies; 7+ messages in thread
From: Maíra Canal @ 2022-12-07 14:08 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, linux-kselftest, kunit-dev, Maíra Canal,
linux-media
On 12/1/22 12:11, Maxime Ripard wrote:
> In order to test the current atomic_check hooks we need to have a DRM
> device that has roughly the same capabilities and layout that the actual
> hardware. We'll also need a bunch of functions to create arbitrary
> atomic states.
>
> Let's create some helpers to create a device that behaves like the real
> one, and some helpers to maintain the atomic state we want to check.
>
> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
But it would be nice if you could fix the checkpatch problems in the
vc4/tests folder.
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/vc4/Kconfig | 16 +++
> drivers/gpu/drm/vc4/Makefile | 6 +
> drivers/gpu/drm/vc4/tests/.kunitconfig | 13 ++
> drivers/gpu/drm/vc4/tests/vc4_mock.c | 200 ++++++++++++++++++++++++++++
> drivers/gpu/drm/vc4/tests/vc4_mock.h | 60 +++++++++
> drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c | 41 ++++++
> drivers/gpu/drm/vc4/tests/vc4_mock_output.c | 99 ++++++++++++++
> drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 47 +++++++
> drivers/gpu/drm/vc4/vc4_crtc.c | 20 +--
> drivers/gpu/drm/vc4/vc4_drv.c | 4 +-
> drivers/gpu/drm/vc4/vc4_drv.h | 16 +++
> drivers/gpu/drm/vc4/vc4_txp.c | 2 +-
> 12 files changed, 511 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig
> index 246305d17a52..f423941c028d 100644
> --- a/drivers/gpu/drm/vc4/Kconfig
> +++ b/drivers/gpu/drm/vc4/Kconfig
> @@ -34,3 +34,19 @@ config DRM_VC4_HDMI_CEC
> help
> Choose this option if you have a Broadcom VC4 GPU
> and want to use CEC.
> +
> +config DRM_VC4_KUNIT_TEST
> + bool "KUnit tests for VC4" if !KUNIT_ALL_TESTS
> + depends on DRM_VC4 && KUNIT
> + select DRM_KUNIT_TEST_HELPERS
> + default KUNIT_ALL_TESTS
> + help
> + This builds unit tests for the VC4 DRM/KMS driver. This option is
> + not useful for distributions or general kernels, but only for kernel
> + developers working on the VC4 driver.
> +
> + For more information on KUnit and unit tests in general,
> + please refer to the KUnit documentation in
> + Documentation/dev-tools/kunit/.
> +
> + If in doubt, say "N".
> diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
> index d0163e18e9ca..f974a8c80e2f 100644
> --- a/drivers/gpu/drm/vc4/Makefile
> +++ b/drivers/gpu/drm/vc4/Makefile
> @@ -25,6 +25,12 @@ vc4-y := \
> vc4_validate.o \
> vc4_validate_shaders.o
>
> +vc4-$(CONFIG_DRM_VC4_KUNIT_TEST) += \
> + tests/vc4_mock.o \
> + tests/vc4_mock_crtc.o \
> + tests/vc4_mock_output.o \
> + tests/vc4_mock_plane.o
> +
> vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o
>
> obj-$(CONFIG_DRM_VC4) += vc4.o
> diff --git a/drivers/gpu/drm/vc4/tests/.kunitconfig b/drivers/gpu/drm/vc4/tests/.kunitconfig
> new file mode 100644
> index 000000000000..b503e9036c7f
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/.kunitconfig
> @@ -0,0 +1,13 @@
> +CONFIG_ARCH_BCM=y
> +CONFIG_ARCH_BCM2835=y
> +CONFIG_BCM2835_MBOX=y
> +CONFIG_KUNIT=y
> +CONFIG_DRM=y
> +CONFIG_DRM_VC4=y
> +CONFIG_DRM_VC4_KUNIT_TEST=y
> +CONFIG_MAILBOX=y
> +CONFIG_RASPBERRYPI_FIRMWARE=y
> +CONFIG_SND=y
> +CONFIG_SND_SOC=y
> +CONFIG_SOUND=y
> +CONFIG_COMMON_CLK=y
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.c b/drivers/gpu/drm/vc4/tests/vc4_mock.c
> new file mode 100644
> index 000000000000..a4bed26af32f
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c
> @@ -0,0 +1,200 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_drv.h>
> +#include <drm/drm_kunit_helpers.h>
> +
> +#include <kunit/test.h>
> +
> +#include "vc4_mock.h"
> +
> +struct vc4_mock_output_desc {
> + enum vc4_encoder_type vc4_encoder_type;
> + unsigned int encoder_type;
> + unsigned int connector_type;
> +};
> +
> +#define VC4_MOCK_OUTPUT_DESC(_vc4_type, _etype, _ctype) \
> + { \
> + .vc4_encoder_type = _vc4_type, \
> + .encoder_type = _etype, \
> + .connector_type = _ctype, \
> + }
> +
> +struct vc4_mock_pipe_desc {
> + const struct vc4_crtc_data *data;
> + const struct vc4_mock_output_desc *outputs;
> + unsigned int noutputs;
> +};
> +
> +#define VC4_MOCK_CRTC_DESC(_data, ...) \
> + { \
> + .data = _data, \
> + .outputs = (struct vc4_mock_output_desc[]) { __VA_ARGS__ }, \
> + .noutputs = sizeof((struct vc4_mock_output_desc[]) { __VA_ARGS__ }) / \
> + sizeof(struct vc4_mock_output_desc), \
> + }
> +
> +#define VC4_MOCK_PIXELVALVE_DESC(_data, ...) \
> + VC4_MOCK_CRTC_DESC(&(_data)->base, __VA_ARGS__)
> +
> +struct vc4_mock_desc {
> + const struct vc4_mock_pipe_desc *pipes;
> + unsigned int npipes;
> +};
> +
> +#define VC4_MOCK_DESC(...) \
> + { \
> + .pipes = (struct vc4_mock_pipe_desc[]) { __VA_ARGS__ }, \
> + .npipes = sizeof((struct vc4_mock_pipe_desc[]) { __VA_ARGS__ }) / \
> + sizeof(struct vc4_mock_pipe_desc), \
> + }
> +
> +static const struct vc4_mock_desc vc4_mock =
> + VC4_MOCK_DESC(
> + VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP,
> + DRM_MODE_ENCODER_VIRTUAL,
> + DRM_MODE_CONNECTOR_WRITEBACK)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv0_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI0,
> + DRM_MODE_ENCODER_DSI,
> + DRM_MODE_CONNECTOR_DSI),
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DPI,
> + DRM_MODE_ENCODER_DPI,
> + DRM_MODE_CONNECTOR_DPI)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv1_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI1,
> + DRM_MODE_ENCODER_DSI,
> + DRM_MODE_CONNECTOR_DSI)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv2_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI0,
> + DRM_MODE_ENCODER_TMDS,
> + DRM_MODE_CONNECTOR_HDMIA),
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_VEC,
> + DRM_MODE_ENCODER_TVDAC,
> + DRM_MODE_CONNECTOR_Composite)),
> +);
> +
> +static const struct vc4_mock_desc vc5_mock =
> + VC4_MOCK_DESC(
> + VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP,
> + DRM_MODE_ENCODER_VIRTUAL,
> + DRM_MODE_CONNECTOR_WRITEBACK)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv0_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI0,
> + DRM_MODE_ENCODER_DSI,
> + DRM_MODE_CONNECTOR_DSI),
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DPI,
> + DRM_MODE_ENCODER_DPI,
> + DRM_MODE_CONNECTOR_DPI)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv1_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI1,
> + DRM_MODE_ENCODER_DSI,
> + DRM_MODE_CONNECTOR_DSI)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv2_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI0,
> + DRM_MODE_ENCODER_TMDS,
> + DRM_MODE_CONNECTOR_HDMIA)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv3_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_VEC,
> + DRM_MODE_ENCODER_TVDAC,
> + DRM_MODE_CONNECTOR_Composite)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv4_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI1,
> + DRM_MODE_ENCODER_TMDS,
> + DRM_MODE_CONNECTOR_HDMIA)),
> +);
> +
> +static int __build_one_pipe(struct kunit *test, struct drm_device *drm,
> + const struct vc4_mock_pipe_desc *pipe)
> +{
> + struct vc4_dummy_plane *dummy_plane;
> + struct drm_plane *plane;
> + struct vc4_dummy_crtc *dummy_crtc;
> + struct drm_crtc *crtc;
> + unsigned int i;
> +
> + dummy_plane = vc4_dummy_plane(test, drm, DRM_PLANE_TYPE_PRIMARY);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane);
> +
> + plane = &dummy_plane->plane.base;
> + dummy_crtc = vc4_mock_pv(test, drm, plane, pipe->data);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_crtc);
> +
> + crtc = &dummy_crtc->crtc.base;
> + for (i = 0; i < pipe->noutputs; i++) {
> + const struct vc4_mock_output_desc *mock_output = &pipe->outputs[i];
> + struct vc4_dummy_output *dummy_output;
> +
> + dummy_output = vc4_dummy_output(test, drm, crtc,
> + mock_output->vc4_encoder_type,
> + mock_output->encoder_type,
> + mock_output->connector_type);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_output);
> + }
> +
> + return 0;
> +}
> +
> +static int __build_mock(struct kunit *test, struct drm_device *drm,
> + const struct vc4_mock_desc *mock)
> +{
> + unsigned int i;
> +
> + for (i = 0; i < mock->npipes; i++) {
> + const struct vc4_mock_pipe_desc *pipe = &mock->pipes[i];
> + int ret;
> +
> + ret = __build_one_pipe(test, drm, pipe);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> + }
> +
> + return 0;
> +}
> +
> +static struct vc4_dev *__mock_device(struct kunit *test, bool is_vc5)
> +{
> + struct drm_device *drm;
> + const struct drm_driver *drv = is_vc5 ? &vc5_drm_driver : &vc4_drm_driver;
> + const struct vc4_mock_desc *desc = is_vc5 ? &vc5_mock : &vc4_mock;
> + struct vc4_dev *vc4;
> + struct device *dev;
> + int ret;
> +
> + dev = drm_kunit_helper_alloc_device(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
> +
> + vc4 = drm_kunit_helper_alloc_drm_device_with_driver(test, dev,
> + struct vc4_dev, base,
> + drv);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> +
> + vc4->dev = dev;
> + vc4->is_vc5 = is_vc5;
> +
> + vc4->hvs = __vc4_hvs_alloc(vc4, NULL);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4->hvs);
> +
> + drm = &vc4->base;
> + ret = __build_mock(test, drm, desc);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = vc4_kms_load(drm);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_dev_register(drm, 0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + return vc4;
> +}
> +
> +struct vc4_dev *vc4_mock_device(struct kunit *test)
> +{
> + return __mock_device(test, false);
> +}
> +
> +struct vc4_dev *vc5_mock_device(struct kunit *test)
> +{
> + return __mock_device(test, true);
> +}
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h b/drivers/gpu/drm/vc4/tests/vc4_mock.h
> new file mode 100644
> index 000000000000..ace5b2e00f4a
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h
> @@ -0,0 +1,60 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef VC4_MOCK_H_
> +#define VC4_MOCK_H_
> +
> +#include "../vc4_drv.h"
> +
> +static inline
> +struct drm_crtc *vc4_find_crtc_for_encoder(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_encoder *encoder)
> +{
> + struct drm_crtc *crtc;
> +
> + KUNIT_ASSERT_EQ(test, hweight32(encoder->possible_crtcs), 1);
> +
> + drm_for_each_crtc(crtc, drm)
> + if (encoder->possible_crtcs & drm_crtc_mask(crtc))
> + return crtc;
> +
> + return NULL;
> +}
> +
> +struct vc4_dummy_plane {
> + struct vc4_plane plane;
> +};
> +
> +struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test,
> + struct drm_device *drm,
> + enum drm_plane_type type);
> +
> +struct vc4_dummy_crtc {
> + struct vc4_crtc crtc;
> +};
> +
> +struct vc4_dummy_crtc *vc4_mock_pv(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_plane *plane,
> + const struct vc4_crtc_data *data);
> +
> +struct vc4_dummy_output {
> + struct vc4_encoder encoder;
> + struct drm_connector connector;
> +};
> +
> +struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_crtc *crtc,
> + enum vc4_encoder_type vc4_encoder_type,
> + unsigned int kms_encoder_type,
> + unsigned int connector_type);
> +
> +struct vc4_dev *vc4_mock_device(struct kunit *test);
> +struct vc4_dev *vc5_mock_device(struct kunit *test);
> +
> +int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
> + enum vc4_encoder_type type,
> + struct drm_atomic_state *state);
> +
> +#endif // VC4_MOCK_H_
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c b/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c
> new file mode 100644
> index 000000000000..5d12d7beef0e
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c
> @@ -0,0 +1,41 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +
> +#include <kunit/test.h>
> +
> +#include "vc4_mock.h"
> +
> +static const struct drm_crtc_helper_funcs vc4_dummy_crtc_helper_funcs = {
> + .atomic_check = vc4_crtc_atomic_check,
> +};
> +
> +static const struct drm_crtc_funcs vc4_dummy_crtc_funcs = {
> + .atomic_destroy_state = vc4_crtc_destroy_state,
> + .atomic_duplicate_state = vc4_crtc_duplicate_state,
> + .reset = vc4_crtc_reset,
> +};
> +
> +struct vc4_dummy_crtc *vc4_mock_pv(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_plane *plane,
> + const struct vc4_crtc_data *data)
> +{
> + struct vc4_dummy_crtc *dummy_crtc;
> + struct vc4_crtc *vc4_crtc;
> + int ret;
> +
> + dummy_crtc = kunit_kzalloc(test, sizeof(*dummy_crtc), GFP_KERNEL);
> + KUNIT_ASSERT_NOT_NULL(test, dummy_crtc);
> +
> + vc4_crtc = &dummy_crtc->crtc;
> + ret = __vc4_crtc_init(drm, NULL,
> + vc4_crtc, data, plane,
> + &vc4_dummy_crtc_funcs,
> + &vc4_dummy_crtc_helper_funcs,
> + false);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + return dummy_crtc;
> +}
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> new file mode 100644
> index 000000000000..cb16ab4451f7
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> @@ -0,0 +1,99 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_atomic_uapi.h>
> +#include <drm/drm_connector.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_encoder.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +
> +#include <kunit/test.h>
> +
> +#include "vc4_mock.h"
> +
> +static const struct drm_connector_helper_funcs vc4_dummy_connector_helper_funcs = {
> +};
> +
> +static const struct drm_connector_funcs vc4_dummy_connector_funcs = {
> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> + .reset = drm_atomic_helper_connector_reset,
> +};
> +
> +struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_crtc *crtc,
> + enum vc4_encoder_type vc4_encoder_type,
> + unsigned int kms_encoder_type,
> + unsigned int connector_type)
> +{
> + struct vc4_dummy_output *dummy_output;
> + struct drm_connector *conn;
> + struct drm_encoder *enc;
> + int ret;
> +
> + dummy_output = kunit_kzalloc(test, sizeof(*dummy_output), GFP_KERNEL);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_output);
> + dummy_output->encoder.type = vc4_encoder_type;
> +
> + enc = &dummy_output->encoder.base;
> + ret = drmm_encoder_init(drm, enc,
> + NULL,
> + kms_encoder_type,
> + NULL);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> + enc->possible_crtcs = drm_crtc_mask(crtc);
> +
> + conn = &dummy_output->connector;
> + ret = drmm_connector_init(drm, conn,
> + &vc4_dummy_connector_funcs,
> + connector_type,
> + NULL);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + drm_connector_helper_add(conn, &vc4_dummy_connector_helper_funcs);
> + drm_connector_attach_encoder(conn, enc);
> +
> + return dummy_output;
> +}
> +
> +static const struct drm_display_mode default_mode = {
> + DRM_SIMPLE_MODE(640, 480, 64, 48)
> +};
> +
> +int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
> + enum vc4_encoder_type type,
> + struct drm_atomic_state *state)
> +{
> + struct vc4_dummy_output *output;
> + struct drm_connector *conn;
> + struct drm_connector_state *conn_state;
> + struct drm_encoder *encoder;
> + struct drm_crtc *crtc;
> + struct drm_crtc_state *crtc_state;
> + int ret;
> +
> + encoder = vc4_find_encoder_by_type(drm, type);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
> +
> + crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
> +
> + output = container_of(encoder, struct vc4_dummy_output, encoder.base);
> + conn = &output->connector;
> + conn_state = drm_atomic_get_connector_state(state, conn);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
> +
> + ret = drm_atomic_set_crtc_for_connector(conn_state, crtc);
> + KUNIT_EXPECT_EQ(test, ret, 0);
> +
> + crtc_state = drm_atomic_get_crtc_state(state, crtc);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
> +
> + ret = drm_atomic_set_mode_for_crtc(crtc_state, &default_mode);
> + KUNIT_EXPECT_EQ(test, ret, 0);
> +
> + crtc_state->active = true;
> +
> + return 0;
> +}
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
> new file mode 100644
> index 000000000000..62b18f5f41db
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
> @@ -0,0 +1,47 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +#include <drm/drm_plane.h>
> +
> +#include <kunit/test.h>
> +
> +#include "vc4_mock.h"
> +
> +static const struct drm_plane_helper_funcs vc4_dummy_plane_helper_funcs = {
> +};
> +
> +static const struct drm_plane_funcs vc4_dummy_plane_funcs = {
> + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
> + .reset = drm_atomic_helper_plane_reset,
> +};
> +
> +static const uint32_t vc4_dummy_plane_formats[] = {
> + DRM_FORMAT_XRGB8888,
> +};
> +
> +struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test,
> + struct drm_device *drm,
> + enum drm_plane_type type)
> +{
> + struct vc4_dummy_plane *dummy_plane;
> + struct drm_plane *plane;
> +
> + dummy_plane = drmm_universal_plane_alloc(drm,
> + struct vc4_dummy_plane, plane.base,
> + 0,
> + &vc4_dummy_plane_funcs,
> + vc4_dummy_plane_formats,
> + ARRAY_SIZE(vc4_dummy_plane_formats),
> + NULL,
> + DRM_PLANE_TYPE_PRIMARY,
> + NULL);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane);
> +
> + plane = &dummy_plane->plane.base;
> + drm_plane_helper_add(plane, &vc4_dummy_plane_helper_funcs);
> +
> + return dummy_plane;
> +}
> diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
> index 195d2b61839d..7d1a696477ce 100644
> --- a/drivers/gpu/drm/vc4/vc4_crtc.c
> +++ b/drivers/gpu/drm/vc4/vc4_crtc.c
> @@ -675,8 +675,8 @@ void vc4_crtc_get_margins(struct drm_crtc_state *state,
> }
> }
>
> -static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
> - struct drm_atomic_state *state)
> +int vc4_crtc_atomic_check(struct drm_crtc *crtc,
> + struct drm_atomic_state *state)
> {
> struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
> crtc);
> @@ -1116,7 +1116,7 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
> .get_scanout_position = vc4_crtc_get_scanout_position,
> };
>
> -static const struct vc4_pv_data bcm2835_pv0_data = {
> +const struct vc4_pv_data bcm2835_pv0_data = {
> .base = {
> .name = "pixelvalve-0",
> .debugfs_name = "crtc0_regs",
> @@ -1131,7 +1131,7 @@ static const struct vc4_pv_data bcm2835_pv0_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2835_pv1_data = {
> +const struct vc4_pv_data bcm2835_pv1_data = {
> .base = {
> .name = "pixelvalve-1",
> .debugfs_name = "crtc1_regs",
> @@ -1146,7 +1146,7 @@ static const struct vc4_pv_data bcm2835_pv1_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2835_pv2_data = {
> +const struct vc4_pv_data bcm2835_pv2_data = {
> .base = {
> .name = "pixelvalve-2",
> .debugfs_name = "crtc2_regs",
> @@ -1161,7 +1161,7 @@ static const struct vc4_pv_data bcm2835_pv2_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv0_data = {
> +const struct vc4_pv_data bcm2711_pv0_data = {
> .base = {
> .name = "pixelvalve-0",
> .debugfs_name = "crtc0_regs",
> @@ -1176,7 +1176,7 @@ static const struct vc4_pv_data bcm2711_pv0_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv1_data = {
> +const struct vc4_pv_data bcm2711_pv1_data = {
> .base = {
> .name = "pixelvalve-1",
> .debugfs_name = "crtc1_regs",
> @@ -1191,7 +1191,7 @@ static const struct vc4_pv_data bcm2711_pv1_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv2_data = {
> +const struct vc4_pv_data bcm2711_pv2_data = {
> .base = {
> .name = "pixelvalve-2",
> .debugfs_name = "crtc2_regs",
> @@ -1205,7 +1205,7 @@ static const struct vc4_pv_data bcm2711_pv2_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv3_data = {
> +const struct vc4_pv_data bcm2711_pv3_data = {
> .base = {
> .name = "pixelvalve-3",
> .debugfs_name = "crtc3_regs",
> @@ -1219,7 +1219,7 @@ static const struct vc4_pv_data bcm2711_pv3_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv4_data = {
> +const struct vc4_pv_data bcm2711_pv4_data = {
> .base = {
> .name = "pixelvalve-4",
> .debugfs_name = "crtc4_regs",
> diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
> index 5990d8f8c363..3b0ae2c3e33c 100644
> --- a/drivers/gpu/drm/vc4/vc4_drv.c
> +++ b/drivers/gpu/drm/vc4/vc4_drv.c
> @@ -196,7 +196,7 @@ static const struct drm_ioctl_desc vc4_drm_ioctls[] = {
> DRM_IOCTL_DEF_DRV(VC4_PERFMON_GET_VALUES, vc4_perfmon_get_values_ioctl, DRM_RENDER_ALLOW),
> };
>
> -static const struct drm_driver vc4_drm_driver = {
> +const struct drm_driver vc4_drm_driver = {
> .driver_features = (DRIVER_MODESET |
> DRIVER_ATOMIC |
> DRIVER_GEM |
> @@ -225,7 +225,7 @@ static const struct drm_driver vc4_drm_driver = {
> .patchlevel = DRIVER_PATCHLEVEL,
> };
>
> -static const struct drm_driver vc5_drm_driver = {
> +const struct drm_driver vc5_drm_driver = {
> .driver_features = (DRIVER_MODESET |
> DRIVER_ATOMIC |
> DRIVER_GEM),
> diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
> index e0be7a81a24a..418f4f308e36 100644
> --- a/drivers/gpu/drm/vc4/vc4_drv.h
> +++ b/drivers/gpu/drm/vc4/vc4_drv.h
> @@ -24,6 +24,9 @@
> struct drm_device;
> struct drm_gem_object;
>
> +extern const struct drm_driver vc4_drm_driver;
> +extern const struct drm_driver vc5_drm_driver;
> +
> /* Don't forget to update vc4_bo.c: bo_type_names[] when adding to
> * this.
> */
> @@ -523,6 +526,8 @@ struct vc4_crtc_data {
> int hvs_output;
> };
>
> +extern const struct vc4_crtc_data vc4_txp_crtc_data;
> +
> struct vc4_pv_data {
> struct vc4_crtc_data base;
>
> @@ -535,6 +540,15 @@ struct vc4_pv_data {
> enum vc4_encoder_type encoder_types[4];
> };
>
> +extern const struct vc4_pv_data bcm2835_pv0_data;
> +extern const struct vc4_pv_data bcm2835_pv1_data;
> +extern const struct vc4_pv_data bcm2835_pv2_data;
> +extern const struct vc4_pv_data bcm2711_pv0_data;
> +extern const struct vc4_pv_data bcm2711_pv1_data;
> +extern const struct vc4_pv_data bcm2711_pv2_data;
> +extern const struct vc4_pv_data bcm2711_pv3_data;
> +extern const struct vc4_pv_data bcm2711_pv4_data;
> +
> struct vc4_crtc {
> struct drm_crtc base;
> struct platform_device *pdev;
> @@ -920,6 +934,8 @@ int vc4_page_flip(struct drm_crtc *crtc,
> struct drm_pending_vblank_event *event,
> uint32_t flags,
> struct drm_modeset_acquire_ctx *ctx);
> +int vc4_crtc_atomic_check(struct drm_crtc *crtc,
> + struct drm_atomic_state *state);
> struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc);
> void vc4_crtc_destroy_state(struct drm_crtc *crtc,
> struct drm_crtc_state *state);
> diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
> index 4f7ce5d3e8ad..2b69454b8534 100644
> --- a/drivers/gpu/drm/vc4/vc4_txp.c
> +++ b/drivers/gpu/drm/vc4/vc4_txp.c
> @@ -479,7 +479,7 @@ static irqreturn_t vc4_txp_interrupt(int irq, void *data)
> return IRQ_HANDLED;
> }
>
> -static const struct vc4_crtc_data vc4_txp_crtc_data = {
> +const struct vc4_crtc_data vc4_txp_crtc_data = {
> .name = "txp",
> .debugfs_name = "txp_regs",
> .hvs_available_channels = BIT(2),
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v3 19/20] drm/vc4: tests: Add unit test suite for the PV muxing
[not found] ` <20221123-rpi-kunit-tests-v3-19-4615a663a84a@cerno.tech>
@ 2022-12-07 14:24 ` Maíra Canal
0 siblings, 0 replies; 7+ messages in thread
From: Maíra Canal @ 2022-12-07 14:24 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, linux-kselftest, kunit-dev, Maíra Canal,
linux-media
On 12/1/22 12:11, Maxime Ripard wrote:
> The HVS to PixelValve muxing code is fairly error prone and has a bunch
> of arbitrary constraints due to the hardware setup.
>
> Let's create a test suite that makes sure that the possible combinations
> work and the invalid ones don't.
>
> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/vc4/Makefile | 3 +-
> drivers/gpu/drm/vc4/tests/vc4_mock.h | 9 +-
> drivers/gpu/drm/vc4/tests/vc4_mock_output.c | 49 +-
> drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c | 1039 ++++++++++++++++++++++++
> 4 files changed, 1091 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
> index f974a8c80e2f..c41f89a15a55 100644
> --- a/drivers/gpu/drm/vc4/Makefile
> +++ b/drivers/gpu/drm/vc4/Makefile
> @@ -29,7 +29,8 @@ vc4-$(CONFIG_DRM_VC4_KUNIT_TEST) += \
> tests/vc4_mock.o \
> tests/vc4_mock_crtc.o \
> tests/vc4_mock_output.o \
> - tests/vc4_mock_plane.o
> + tests/vc4_mock_plane.o \
> + tests/vc4_test_pv_muxing.o
>
> vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o
>
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h b/drivers/gpu/drm/vc4/tests/vc4_mock.h
> index ace5b2e00f4a..db8e9a141ef8 100644
> --- a/drivers/gpu/drm/vc4/tests/vc4_mock.h
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h
> @@ -53,8 +53,11 @@ struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
> struct vc4_dev *vc4_mock_device(struct kunit *test);
> struct vc4_dev *vc5_mock_device(struct kunit *test);
>
> -int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
> - enum vc4_encoder_type type,
> - struct drm_atomic_state *state);
> +int vc4_mock_atomic_add_output(struct kunit *test,
> + struct drm_atomic_state *state,
> + enum vc4_encoder_type type);
> +int vc4_mock_atomic_del_output(struct kunit *test,
> + struct drm_atomic_state *state,
> + enum vc4_encoder_type type);
>
> #endif // VC4_MOCK_H_
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> index cb16ab4451f7..8d33be828d9a 100644
> --- a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> @@ -61,16 +61,17 @@ static const struct drm_display_mode default_mode = {
> DRM_SIMPLE_MODE(640, 480, 64, 48)
> };
>
> -int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
> - enum vc4_encoder_type type,
> - struct drm_atomic_state *state)
> +int vc4_mock_atomic_add_output(struct kunit *test,
> + struct drm_atomic_state *state,
> + enum vc4_encoder_type type)
> {
> + struct drm_device *drm = state->dev;
> + struct drm_connector_state *conn_state;
> + struct drm_crtc_state *crtc_state;
> struct vc4_dummy_output *output;
> struct drm_connector *conn;
> - struct drm_connector_state *conn_state;
> struct drm_encoder *encoder;
> struct drm_crtc *crtc;
> - struct drm_crtc_state *crtc_state;
> int ret;
>
> encoder = vc4_find_encoder_by_type(drm, type);
> @@ -97,3 +98,41 @@ int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
>
> return 0;
> }
> +
> +int vc4_mock_atomic_del_output(struct kunit *test,
> + struct drm_atomic_state *state,
> + enum vc4_encoder_type type)
> +{
> + struct drm_device *drm = state->dev;
> + struct drm_connector_state *conn_state;
> + struct drm_crtc_state *crtc_state;
> + struct vc4_dummy_output *output;
> + struct drm_connector *conn;
> + struct drm_encoder *encoder;
> + struct drm_crtc *crtc;
> + int ret;
> +
> + encoder = vc4_find_encoder_by_type(drm, type);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
> +
> + crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
> +
> + crtc_state = drm_atomic_get_crtc_state(state, crtc);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
> +
> + crtc_state->active = false;
> +
> + ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + output = container_of(encoder, struct vc4_dummy_output, encoder.base);
> + conn = &output->connector;
> + conn_state = drm_atomic_get_connector_state(state, conn);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
> +
> + ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + return 0;
> +}
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
> new file mode 100644
> index 000000000000..ae0bd0f81698
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
> @@ -0,0 +1,1039 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_atomic_uapi.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_drv.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_kunit_helpers.h>
> +#include <drm/drm_mode.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +#include <drm/drm_plane.h>
> +
> +#include <kunit/test.h>
> +
> +#include "../vc4_drv.h"
> +
> +#include "vc4_mock.h"
> +
> +struct pv_muxing_priv {
> + struct vc4_dev *vc4;
> + struct drm_modeset_acquire_ctx ctx;
> + struct drm_atomic_state *state;
> +};
> +
> +static bool check_fifo_conflict(struct kunit *test,
> + const struct drm_atomic_state *state)
> +{
> + struct vc4_hvs_state *hvs_state;
> + unsigned int used_fifos = 0;
> + unsigned int i;
> +
> + hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hvs_state);
> +
> + for (i = 0; i < HVS_NUM_CHANNELS; i++) {
> + if (!hvs_state->fifo_state[i].in_use)
> + continue;
> +
> + KUNIT_EXPECT_FALSE(test, used_fifos & BIT(i));
> + used_fifos |= BIT(i);
> + }
> +
> + return true;
> +}
> +
> +struct encoder_constraint {
> + enum vc4_encoder_type type;
> + unsigned int *channels;
> + size_t nchannels;
> +};
> +
> +#define ENCODER_CONSTRAINT(_type, ...) \
> + { \
> + .type = _type, \
> + .channels = (unsigned int[]) { __VA_ARGS__ }, \
> + .nchannels = sizeof((unsigned int[]) { __VA_ARGS__ }) / \
> + sizeof(unsigned int), \
> + }
> +
> +static bool __check_encoder_constraints(const struct encoder_constraint *constraints,
> + size_t nconstraints,
> + enum vc4_encoder_type type,
> + unsigned int channel)
> +{
> + unsigned int i;
> +
> + for (i = 0; i < nconstraints; i++) {
> + const struct encoder_constraint *constraint = &constraints[i];
> + unsigned int j;
> +
> + if (constraint->type != type)
> + continue;
> +
> + for (j = 0; j < constraint->nchannels; j++) {
> + unsigned int _channel = constraint->channels[j];
> +
> + if (channel != _channel)
> + continue;
> +
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> +static const struct encoder_constraint vc4_encoder_constraints[] = {
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DPI, 0),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI0, 0),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 1),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_VEC, 1),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP, 2),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI1, 2),
> +};
> +
> +static const struct encoder_constraint vc5_encoder_constraints[] = {
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DPI, 0),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI0, 0),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_VEC, 1),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP, 0, 2),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI1, 0, 1, 2),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 0, 1, 2),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI1, 0, 1, 2),
> +};
> +
> +static bool check_vc4_encoder_constraints(enum vc4_encoder_type type, unsigned int channel)
> +{
> + return __check_encoder_constraints(vc4_encoder_constraints,
> + ARRAY_SIZE(vc4_encoder_constraints),
> + type, channel);
> +}
> +
> +static bool check_vc5_encoder_constraints(enum vc4_encoder_type type, unsigned int channel)
> +{
> + return __check_encoder_constraints(vc5_encoder_constraints,
> + ARRAY_SIZE(vc5_encoder_constraints),
> + type, channel);
> +}
> +
> +static struct vc4_crtc_state *
> +get_vc4_crtc_state_for_encoder(struct kunit *test,
> + const struct drm_atomic_state *state,
> + enum vc4_encoder_type type)
> +{
> + struct drm_device *drm = state->dev;
> + struct drm_crtc_state *new_crtc_state;
> + struct drm_encoder *encoder;
> + struct drm_crtc *crtc;
> +
> + encoder = vc4_find_encoder_by_type(drm, type);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
> +
> + crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
> +
> + new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
> + if (!new_crtc_state)
> + return NULL;
> +
> + return to_vc4_crtc_state(new_crtc_state);
> +}
> +
> +static bool check_channel_for_encoder(struct kunit *test,
> + const struct drm_atomic_state *state,
> + enum vc4_encoder_type type,
> + bool (*check_fn)(enum vc4_encoder_type type, unsigned int channel))
> +{
> + struct vc4_crtc_state *new_vc4_crtc_state;
> + struct vc4_hvs_state *new_hvs_state;
> + unsigned int channel;
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state, type);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_EXPECT_NE(test, channel, VC4_HVS_CHANNEL_DISABLED);
> +
> + KUNIT_EXPECT_TRUE(test, new_hvs_state->fifo_state[channel].in_use);
> +
> + KUNIT_EXPECT_TRUE(test, check_fn(type, channel));
> +
> + return true;
> +}
> +
> +struct pv_muxing_param {
> + const char *name;
> + struct vc4_dev *(*mock_fn)(struct kunit *test);
> + bool (*check_fn)(enum vc4_encoder_type type, unsigned int channel);
> + enum vc4_encoder_type *encoders;
> + size_t nencoders;
> +};
> +
> +static void vc4_test_pv_muxing_desc(const struct pv_muxing_param *t, char *desc)
> +{
> + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
> +}
> +
> +#define PV_MUXING_TEST(_name, _mock_fn, _check_fn, ...) \
> + { \
> + .name = _name, \
> + .mock_fn = &_mock_fn, \
> + .check_fn = &_check_fn, \
> + .encoders = (enum vc4_encoder_type[]) { __VA_ARGS__ }, \
> + .nencoders = sizeof((enum vc4_encoder_type[]) { __VA_ARGS__ }) / \
> + sizeof(enum vc4_encoder_type), \
> + }
> +
> +#define VC4_PV_MUXING_TEST(_name, ...) \
> + PV_MUXING_TEST(_name, vc4_mock_device, check_vc4_encoder_constraints, __VA_ARGS__)
> +
> +#define VC5_PV_MUXING_TEST(_name, ...) \
> + PV_MUXING_TEST(_name, vc5_mock_device, check_vc5_encoder_constraints, __VA_ARGS__)
> +
> +static const struct pv_muxing_param vc4_test_pv_muxing_params[] = {
> + VC4_PV_MUXING_TEST("1 output: DSI0",
> + VC4_ENCODER_TYPE_DSI0),
> + VC4_PV_MUXING_TEST("1 output: DPI",
> + VC4_ENCODER_TYPE_DPI),
> + VC4_PV_MUXING_TEST("1 output: HDMI0",
> + VC4_ENCODER_TYPE_HDMI0),
> + VC4_PV_MUXING_TEST("1 output: VEC",
> + VC4_ENCODER_TYPE_VEC),
> + VC4_PV_MUXING_TEST("1 output: DSI1",
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("1 output: TXP",
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("2 outputs: DSI0, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC4_PV_MUXING_TEST("2 outputs: DSI0, VEC",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC),
> + VC4_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("2 outputs: DSI0, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("2 outputs: DPI, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC4_PV_MUXING_TEST("2 outputs: DPI, VEC",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC),
> + VC4_PV_MUXING_TEST("2 outputs: DPI, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("2 outputs: DPI, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("2 outputs: HDMI0, DSI1",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("2 outputs: HDMI0, TXP",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("2 outputs: VEC, DSI1",
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("2 outputs: VEC, TXP",
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("3 outputs: DSI0, VEC, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("3 outputs: DSI0, VEC, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("3 outputs: DPI, HDMI0, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("3 outputs: DPI, HDMI0, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("3 outputs: DPI, VEC, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("3 outputs: DPI, VEC, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> +};
> +
> +KUNIT_ARRAY_PARAM(vc4_test_pv_muxing,
> + vc4_test_pv_muxing_params,
> + vc4_test_pv_muxing_desc);
> +
> +static const struct pv_muxing_param vc4_test_pv_muxing_invalid_params[] = {
> + VC4_PV_MUXING_TEST("DPI/DSI0 Conflict",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI0),
> + VC4_PV_MUXING_TEST("TXP/DSI1 Conflict",
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("HDMI0/VEC Conflict",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_VEC),
> + VC4_PV_MUXING_TEST("More than 3 outputs: DSI0, HDMI0, DSI1, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("More than 3 outputs: DPI, HDMI0, DSI1, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> +};
> +
> +KUNIT_ARRAY_PARAM(vc4_test_pv_muxing_invalid,
> + vc4_test_pv_muxing_invalid_params,
> + vc4_test_pv_muxing_desc);
> +
> +static const struct pv_muxing_param vc5_test_pv_muxing_params[] = {
> + VC5_PV_MUXING_TEST("1 output: DPI",
> + VC4_ENCODER_TYPE_DPI),
> + VC5_PV_MUXING_TEST("1 output: DSI0",
> + VC4_ENCODER_TYPE_DSI0),
> + VC5_PV_MUXING_TEST("1 output: DSI1",
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("1 output: HDMI0",
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("1 output: HDMI1",
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("1 output: VEC",
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, VEC",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, VEC",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("2 outputs: DSI1, VEC",
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: DSI1, TXP",
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("2 outputs: DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI0, VEC",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI0, TXP",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI1, VEC",
> + VC4_ENCODER_TYPE_HDMI1,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI1, TXP",
> + VC4_ENCODER_TYPE_HDMI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: TXP, VEC",
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> +};
> +
> +KUNIT_ARRAY_PARAM(vc5_test_pv_muxing,
> + vc5_test_pv_muxing_params,
> + vc4_test_pv_muxing_desc);
> +
> +static const struct pv_muxing_param vc5_test_pv_muxing_invalid_params[] = {
> + VC5_PV_MUXING_TEST("DPI/DSI0 Conflict",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: VEC, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> +};
> +
> +KUNIT_ARRAY_PARAM(vc5_test_pv_muxing_invalid,
> + vc5_test_pv_muxing_invalid_params,
> + vc4_test_pv_muxing_desc);
> +
> +static void drm_vc4_test_pv_muxing(struct kunit *test)
> +{
> + const struct pv_muxing_param *params = test->param_value;
> + const struct pv_muxing_priv *priv = test->priv;
> + struct drm_atomic_state *state = priv->state;
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < params->nencoders; i++) {
> + enum vc4_encoder_type enc_type = params->encoders[i];
> +
> + ret = vc4_mock_atomic_add_output(test, state, enc_type);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> + }
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_EXPECT_EQ(test, ret, 0);
> +
> + KUNIT_EXPECT_TRUE(test,
> + check_fifo_conflict(test, state));
> +
> + for (i = 0; i < params->nencoders; i++) {
> + enum vc4_encoder_type enc_type = params->encoders[i];
> +
> + KUNIT_EXPECT_TRUE(test, check_channel_for_encoder(test, state, enc_type,
> + params->check_fn));
> + }
> +}
> +
> +static void drm_vc4_test_pv_muxing_invalid(struct kunit *test)
> +{
> + const struct pv_muxing_param *params = test->param_value;
> + const struct pv_muxing_priv *priv = test->priv;
> + struct drm_atomic_state *state = priv->state;
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < params->nencoders; i++) {
> + enum vc4_encoder_type enc_type = params->encoders[i];
> +
> + ret = vc4_mock_atomic_add_output(test, state, enc_type);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> + }
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_EXPECT_LT(test, ret, 0);
> +}
> +
> +static int vc4_pv_muxing_test_init(struct kunit *test)
> +{
> + const struct pv_muxing_param *params = test->param_value;
> + struct drm_atomic_state *state;
> + struct pv_muxing_priv *priv;
> + struct drm_device *drm;
> + struct vc4_dev *vc4;
> +
> + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
> + KUNIT_ASSERT_NOT_NULL(test, priv);
> + test->priv = priv;
> +
> + vc4 = params->mock_fn(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> + priv->vc4 = vc4;
> +
> + drm_modeset_acquire_init(&priv->ctx, 0);
> +
> + drm = &vc4->base;
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &priv->ctx;
> +
> + priv->state = state;
> +
> + return 0;
> +}
> +
> +static void vc4_pv_muxing_test_exit(struct kunit *test)
> +{
> + struct pv_muxing_priv *priv = test->priv;
> + struct vc4_dev *vc4 = priv->vc4;
> + struct drm_device *drm = &vc4->base;
> + struct drm_atomic_state *state = priv->state;
> +
> + drm_atomic_state_put(state);
> + drm_modeset_drop_locks(&priv->ctx);
> + drm_modeset_acquire_fini(&priv->ctx);
> + drm_dev_unregister(drm);
> + drm_kunit_helper_free_device(test, vc4->dev);
> +}
> +
> +static struct kunit_case vc4_pv_muxing_tests[] = {
> + KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing,
> + vc4_test_pv_muxing_gen_params),
> + KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing_invalid,
> + vc4_test_pv_muxing_invalid_gen_params),
> + {}
> +};
> +
> +static struct kunit_suite vc4_pv_muxing_test_suite = {
> + .name = "vc4-pv-muxing-combinations",
> + .init = vc4_pv_muxing_test_init,
> + .exit = vc4_pv_muxing_test_exit,
> + .test_cases = vc4_pv_muxing_tests,
> +};
> +
> +static struct kunit_case vc5_pv_muxing_tests[] = {
> + KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing,
> + vc5_test_pv_muxing_gen_params),
> + KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing_invalid,
> + vc5_test_pv_muxing_invalid_gen_params),
> + {}
> +};
> +
> +static struct kunit_suite vc5_pv_muxing_test_suite = {
> + .name = "vc5-pv-muxing-combinations",
> + .init = vc4_pv_muxing_test_init,
> + .exit = vc4_pv_muxing_test_exit,
> + .test_cases = vc5_pv_muxing_tests,
> +};
> +
> +/* See
> + * https://lore.kernel.org/all/3e113525-aa89-b1e2-56b7-ca55bd41d057@samsung.com/
> + * and
> + * https://lore.kernel.org/dri-devel/20200917121623.42023-1-maxime@cerno.tech/
> + */
> +static void drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable(struct kunit *test)
> +{
> + struct drm_modeset_acquire_ctx ctx;
> + struct drm_atomic_state *state;
> + struct vc4_crtc_state *new_vc4_crtc_state;
> + struct vc4_hvs_state *new_hvs_state;
> + unsigned int hdmi0_channel;
> + unsigned int hdmi1_channel;
> + struct drm_device *drm;
> + struct vc4_dev *vc4;
> + int ret;
> +
> + vc4 = vc5_mock_device(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> +
> + drm_modeset_acquire_init(&ctx, 0);
> +
> + drm = &vc4->base;
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + hdmi0_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, hdmi0_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi0_channel].in_use);
> +
> + ret = drm_atomic_helper_swap_state(state, false);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + drm_atomic_state_put(state);
> +
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + hdmi1_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi1_channel].in_use);
> +
> + KUNIT_EXPECT_NE(test, hdmi0_channel, hdmi1_channel);
> +
> + drm_atomic_state_put(state);
> + drm_modeset_drop_locks(&ctx);
> + drm_modeset_acquire_fini(&ctx);
> + drm_dev_unregister(drm);
> + drm_kunit_helper_free_device(test, vc4->dev);
> +}
> +
> +static void drm_test_vc5_pv_muxing_bugs_stable_fifo(struct kunit *test)
> +{
> + struct drm_modeset_acquire_ctx ctx;
> + struct drm_atomic_state *state;
> + struct vc4_crtc_state *new_vc4_crtc_state;
> + struct vc4_hvs_state *new_hvs_state;
> + unsigned int old_hdmi0_channel;
> + unsigned int old_hdmi1_channel;
> + struct drm_device *drm;
> + struct vc4_dev *vc4;
> + int ret;
> +
> + vc4 = vc5_mock_device(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> +
> + drm_modeset_acquire_init(&ctx, 0);
> +
> + drm = &vc4->base;
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + old_hdmi0_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, old_hdmi0_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[old_hdmi0_channel].in_use);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + old_hdmi1_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, old_hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[old_hdmi1_channel].in_use);
> +
> + ret = drm_atomic_helper_swap_state(state, false);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + drm_atomic_state_put(state);
> +
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_del_output(test, state, VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI1);
> +
> + if (new_vc4_crtc_state) {
> + unsigned int hdmi1_channel;
> +
> + hdmi1_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi1_channel].in_use);
> +
> + KUNIT_EXPECT_EQ(test, old_hdmi1_channel, hdmi1_channel);
> + }
> +
> + drm_atomic_state_put(state);
> + drm_modeset_drop_locks(&ctx);
> + drm_modeset_acquire_fini(&ctx);
> + drm_dev_unregister(drm);
> + drm_kunit_helper_free_device(test, vc4->dev);
> +}
> +
> +static void
> +drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state(struct kunit *test)
> +{
> + struct drm_modeset_acquire_ctx ctx;
> + struct drm_atomic_state *state;
> + struct vc4_crtc_state *new_vc4_crtc_state;
> + struct drm_device *drm;
> + struct vc4_dev *vc4;
> + int ret;
> +
> + vc4 = vc5_mock_device(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> +
> + drm_modeset_acquire_init(&ctx, 0);
> +
> + drm = &vc4->base;
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_helper_swap_state(state, false);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + drm_atomic_state_put(state);
> +
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_EXPECT_NULL(test, new_vc4_crtc_state);
> +
> + drm_atomic_state_put(state);
> + drm_modeset_drop_locks(&ctx);
> + drm_modeset_acquire_fini(&ctx);
> + drm_dev_unregister(drm);
> + drm_kunit_helper_free_device(test, vc4->dev);
> +}
> +
> +static struct kunit_case vc5_pv_muxing_bugs_tests[] = {
> + KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable),
> + KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state),
> + KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_stable_fifo),
> + {}
> +};
> +
> +static struct kunit_suite vc5_pv_muxing_bugs_test_suite = {
> + .name = "vc5-pv-muxing-bugs",
> + .test_cases = vc5_pv_muxing_bugs_tests,
> +};
> +
> +kunit_test_suites(
> + &vc4_pv_muxing_test_suite,
> + &vc5_pv_muxing_test_suite,
> + &vc5_pv_muxing_bugs_test_suite
> +);
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v3 18/20] drm/vc4: tests: Fail the current test if we access a register
[not found] ` <20221123-rpi-kunit-tests-v3-18-4615a663a84a@cerno.tech>
@ 2022-12-07 14:26 ` Maíra Canal
2022-12-07 16:11 ` Maxime Ripard
0 siblings, 1 reply; 7+ messages in thread
From: Maíra Canal @ 2022-12-07 14:26 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, linux-kselftest, kunit-dev, Maíra Canal,
linux-media
On 12/1/22 12:11, Maxime Ripard wrote:
> Accessing a register when running under kunit is a bad idea since our
> device is completely mocked.
>
> Fail the current test if we ever access any of our hardware registers.
>
> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Just a small nit: I believe that macros with multiple statements should
be enclosed in a do-while block [1], even READ macros. I saw that you
enclosed the WRITE macros on a do-while block, but not the READ macros.
[1]
https://www.kernel.org/doc/html/latest/process/coding-style.html#macros-enums-and-rtl
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/vc4/vc4_crtc.c | 13 +++++++++++--
> drivers/gpu/drm/vc4/vc4_dpi.c | 13 +++++++++++--
> drivers/gpu/drm/vc4/vc4_drv.h | 29 +++++++++++++++++++++++++----
> drivers/gpu/drm/vc4/vc4_dsi.c | 9 ++++++++-
> drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 4 ++++
> drivers/gpu/drm/vc4/vc4_txp.c | 13 +++++++++++--
> drivers/gpu/drm/vc4/vc4_vec.c | 13 +++++++++++--
> 7 files changed, 81 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
> index 7d1a696477ce..a1a3465948c4 100644
> --- a/drivers/gpu/drm/vc4/vc4_crtc.c
> +++ b/drivers/gpu/drm/vc4/vc4_crtc.c
> @@ -50,8 +50,17 @@
>
> #define HVS_FIFO_LATENCY_PIX 6
>
> -#define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset))
> -#define CRTC_READ(offset) readl(vc4_crtc->regs + (offset))
> +#define CRTC_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, vc4_crtc->regs + (offset)); \
> + } while (0)
> +
> +#define CRTC_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(vc4_crtc->regs + (offset)); \
> + })
>
> static const struct debugfs_reg32 crtc_regs[] = {
> VC4_REG32(PV_CONTROL),
> diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c
> index 1f8f44b7b5a5..0edf3c4c98c8 100644
> --- a/drivers/gpu/drm/vc4/vc4_dpi.c
> +++ b/drivers/gpu/drm/vc4/vc4_dpi.c
> @@ -103,8 +103,17 @@ to_vc4_dpi(struct drm_encoder *encoder)
> return container_of(encoder, struct vc4_dpi, encoder.base);
> }
>
> -#define DPI_READ(offset) readl(dpi->regs + (offset))
> -#define DPI_WRITE(offset, val) writel(val, dpi->regs + (offset))
> +#define DPI_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(dpi->regs + (offset)); \
> + })
> +
> +#define DPI_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, dpi->regs + (offset)); \
> + } while (0)
>
> static const struct debugfs_reg32 dpi_regs[] = {
> VC4_REG32(DPI_C),
> diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
> index 418f4f308e36..78fda5332cb3 100644
> --- a/drivers/gpu/drm/vc4/vc4_drv.h
> +++ b/drivers/gpu/drm/vc4/vc4_drv.h
> @@ -19,6 +19,8 @@
> #include <drm/drm_mm.h>
> #include <drm/drm_modeset_lock.h>
>
> +#include <kunit/test-bug.h>
> +
> #include "uapi/drm/vc4_drm.h"
>
> struct drm_device;
> @@ -645,10 +647,29 @@ to_vc4_crtc_state(const struct drm_crtc_state *crtc_state)
> return container_of(crtc_state, struct vc4_crtc_state, base);
> }
>
> -#define V3D_READ(offset) readl(vc4->v3d->regs + offset)
> -#define V3D_WRITE(offset, val) writel(val, vc4->v3d->regs + offset)
> -#define HVS_READ(offset) readl(hvs->regs + offset)
> -#define HVS_WRITE(offset, val) writel(val, hvs->regs + offset)
> +#define V3D_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(vc4->v3d->regs + (offset)); \
> + })
> +
> +#define V3D_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, vc4->v3d->regs + (offset)); \
> + } while (0)
> +
> +#define HVS_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(hvs->regs + (offset)); \
> + })
> +
> +#define HVS_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, hvs->regs + (offset)); \
> + } while (0)
>
> #define VC4_REG32(reg) { .name = #reg, .offset = reg }
>
> diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> index 878e05d79e81..2c9cb27903a0 100644
> --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> @@ -617,6 +617,8 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val)
> dma_cookie_t cookie;
> int ret;
>
> + kunit_fail_current_test("Accessing a register in a unit test!\n");
> +
> /* DSI0 should be able to write normally. */
> if (!chan) {
> writel(val, dsi->regs + offset);
> @@ -645,7 +647,12 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val)
> DRM_ERROR("Failed to wait for DMA: %d\n", ret);
> }
>
> -#define DSI_READ(offset) readl(dsi->regs + (offset))
> +#define DSI_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(dsi->regs + (offset)); \
> + })
> +
> #define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val)
> #define DSI_PORT_READ(offset) \
> DSI_READ(dsi->variant->port ? DSI1_##offset : DSI0_##offset)
> diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
> index 48db438550b1..b04b2fc8d831 100644
> --- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
> +++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
> @@ -456,6 +456,8 @@ static inline u32 vc4_hdmi_read(struct vc4_hdmi *hdmi,
>
> WARN_ON(pm_runtime_status_suspended(&hdmi->pdev->dev));
>
> + kunit_fail_current_test("Accessing an HDMI register in a unit test!\n");
> +
> if (reg >= variant->num_registers) {
> dev_warn(&hdmi->pdev->dev,
> "Invalid register ID %u\n", reg);
> @@ -486,6 +488,8 @@ static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi,
>
> WARN_ON(pm_runtime_status_suspended(&hdmi->pdev->dev));
>
> + kunit_fail_current_test("Accessing an HDMI register in a unit test!\n");
> +
> if (reg >= variant->num_registers) {
> dev_warn(&hdmi->pdev->dev,
> "Invalid register ID %u\n", reg);
> diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
> index 2b69454b8534..ef5cab2a3aa9 100644
> --- a/drivers/gpu/drm/vc4/vc4_txp.c
> +++ b/drivers/gpu/drm/vc4/vc4_txp.c
> @@ -145,8 +145,17 @@
> /* Number of lines received and committed to memory. */
> #define TXP_PROGRESS 0x10
>
> -#define TXP_READ(offset) readl(txp->regs + (offset))
> -#define TXP_WRITE(offset, val) writel(val, txp->regs + (offset))
> +#define TXP_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(txp->regs + (offset)); \
> + })
> +
> +#define TXP_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, txp->regs + (offset)); \
> + } while (0)
>
> struct vc4_txp {
> struct vc4_crtc base;
> diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
> index e270a4099be3..f589ab918f4d 100644
> --- a/drivers/gpu/drm/vc4/vc4_vec.c
> +++ b/drivers/gpu/drm/vc4/vc4_vec.c
> @@ -207,8 +207,17 @@ struct vc4_vec {
> struct debugfs_regset32 regset;
> };
>
> -#define VEC_READ(offset) readl(vec->regs + (offset))
> -#define VEC_WRITE(offset, val) writel(val, vec->regs + (offset))
> +#define VEC_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(vec->regs + (offset)); \
> + })
> +
> +#define VEC_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, vec->regs + (offset)); \
> + } while (0)
>
> static inline struct vc4_vec *
> encoder_to_vc4_vec(struct drm_encoder *encoder)
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v3 18/20] drm/vc4: tests: Fail the current test if we access a register
2022-12-07 14:26 ` [PATCH v3 18/20] drm/vc4: tests: Fail the current test if we access a register Maíra Canal
@ 2022-12-07 16:11 ` Maxime Ripard
0 siblings, 0 replies; 7+ messages in thread
From: Maxime Ripard @ 2022-12-07 16:11 UTC (permalink / raw)
To: Maíra Canal
Cc: Maarten Lankhorst, Daniel Vetter, Thomas Zimmermann,
David Airlie, David Gow, Dave Stevenson, Greg Kroah-Hartman,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, linux-kselftest, kunit-dev, Maíra Canal,
linux-media
[-- Attachment #1: Type: text/plain, Size: 937 bytes --]
Hi Maíra,
Thanks for your review!
On Wed, Dec 07, 2022 at 11:26:13AM -0300, Maíra Canal wrote:
> On 12/1/22 12:11, Maxime Ripard wrote:
> > Accessing a register when running under kunit is a bad idea since our
> > device is completely mocked.
> >
> > Fail the current test if we ever access any of our hardware registers.
> >
> > Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
> > Signed-off-by: Maxime Ripard <maxime@cerno.tech>
>
> Reviewed-by: Maíra Canal <mcanal@igalia.com>
>
> Just a small nit: I believe that macros with multiple statements should be
> enclosed in a do-while block [1], even READ macros. I saw that you enclosed
> the WRITE macros on a do-while block, but not the READ macros.
This is on purpose: do-while blocks don't return a value, but ({ ... })
blocks do. So we can do a write macros with a do-while, but can't for
read since we expect to get a value back.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2022-12-07 16:12 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <20221123-rpi-kunit-tests-v3-0-4615a663a84a@cerno.tech>
[not found] ` <20221123-rpi-kunit-tests-v3-20-4615a663a84a@cerno.tech>
2022-12-07 13:55 ` [PATCH v3 20/20] Documentation: gpu: vc4: Add KUnit Tests Section Maíra Canal
[not found] ` <20221123-rpi-kunit-tests-v3-2-4615a663a84a@cerno.tech>
2022-12-07 13:57 ` [PATCH v3 02/20] drm/tests: Introduce a config option for the KUnit helpers Maíra Canal
[not found] ` <20221123-rpi-kunit-tests-v3-4-4615a663a84a@cerno.tech>
2022-12-07 13:59 ` [PATCH v3 04/20] drm/tests: helpers: Switch to EXPORT_SYMBOL_GPL Maíra Canal
[not found] ` <20221123-rpi-kunit-tests-v3-17-4615a663a84a@cerno.tech>
2022-12-07 14:08 ` [PATCH v3 17/20] drm/vc4: tests: Introduce a mocking infrastructure Maíra Canal
[not found] ` <20221123-rpi-kunit-tests-v3-19-4615a663a84a@cerno.tech>
2022-12-07 14:24 ` [PATCH v3 19/20] drm/vc4: tests: Add unit test suite for the PV muxing Maíra Canal
[not found] ` <20221123-rpi-kunit-tests-v3-18-4615a663a84a@cerno.tech>
2022-12-07 14:26 ` [PATCH v3 18/20] drm/vc4: tests: Fail the current test if we access a register Maíra Canal
2022-12-07 16:11 ` Maxime Ripard
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).