diff options
author | Maxime Ripard <maxime@cerno.tech> | 2022-12-01 18:11:48 +0300 |
---|---|---|
committer | Maxime Ripard <maxime@cerno.tech> | 2022-12-08 11:56:56 +0300 |
commit | f759f5b53f1caf734bdffcb9519d4edd877b017f (patch) | |
tree | 2cf006f4295577581a3b5df7b383f085f703e6da /drivers/gpu/drm/vc4/tests | |
parent | 640dbcc91dec76aeeae782d97f0e8ed3c65b58f6 (diff) | |
download | linux-f759f5b53f1caf734bdffcb9519d4edd877b017f.tar.xz |
drm/vc4: tests: Introduce a mocking infrastructure
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>
Reviewed-by: MaĆra Canal <mcanal@igalia.com>
Link: https://lore.kernel.org/r/20221123-rpi-kunit-tests-v3-17-4615a663a84a@cerno.tech
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Diffstat (limited to 'drivers/gpu/drm/vc4/tests')
-rw-r--r-- | drivers/gpu/drm/vc4/tests/.kunitconfig | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/tests/vc4_mock.c | 200 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/tests/vc4_mock.h | 60 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c | 41 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/tests/vc4_mock_output.c | 99 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 47 |
6 files changed, 460 insertions, 0 deletions
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; +} |