1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | #include <drm/drm_drv.h> |
4 | #include <drm/drm_kunit_helpers.h> |
5 | |
6 | #include <kunit/test.h> |
7 | |
8 | #include "vc4_mock.h" |
9 | |
10 | struct vc4_mock_output_desc { |
11 | enum vc4_encoder_type vc4_encoder_type; |
12 | unsigned int encoder_type; |
13 | unsigned int connector_type; |
14 | }; |
15 | |
16 | #define VC4_MOCK_OUTPUT_DESC(_vc4_type, _etype, _ctype) \ |
17 | { \ |
18 | .vc4_encoder_type = _vc4_type, \ |
19 | .encoder_type = _etype, \ |
20 | .connector_type = _ctype, \ |
21 | } |
22 | |
23 | struct vc4_mock_pipe_desc { |
24 | const struct vc4_crtc_data *data; |
25 | const struct vc4_mock_output_desc *outputs; |
26 | unsigned int noutputs; |
27 | }; |
28 | |
29 | #define VC4_MOCK_CRTC_DESC(_data, ...) \ |
30 | { \ |
31 | .data = _data, \ |
32 | .outputs = (struct vc4_mock_output_desc[]) { __VA_ARGS__ }, \ |
33 | .noutputs = sizeof((struct vc4_mock_output_desc[]) { __VA_ARGS__ }) / \ |
34 | sizeof(struct vc4_mock_output_desc), \ |
35 | } |
36 | |
37 | #define VC4_MOCK_PIXELVALVE_DESC(_data, ...) \ |
38 | VC4_MOCK_CRTC_DESC(&(_data)->base, __VA_ARGS__) |
39 | |
40 | struct vc4_mock_desc { |
41 | const struct vc4_mock_pipe_desc *pipes; |
42 | unsigned int npipes; |
43 | }; |
44 | |
45 | #define VC4_MOCK_DESC(...) \ |
46 | { \ |
47 | .pipes = (struct vc4_mock_pipe_desc[]) { __VA_ARGS__ }, \ |
48 | .npipes = sizeof((struct vc4_mock_pipe_desc[]) { __VA_ARGS__ }) / \ |
49 | sizeof(struct vc4_mock_pipe_desc), \ |
50 | } |
51 | |
52 | static const struct vc4_mock_desc vc4_mock = |
53 | VC4_MOCK_DESC( |
54 | VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data, |
55 | VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP, |
56 | DRM_MODE_ENCODER_VIRTUAL, |
57 | DRM_MODE_CONNECTOR_WRITEBACK)), |
58 | VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv0_data, |
59 | VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI0, |
60 | DRM_MODE_ENCODER_DSI, |
61 | DRM_MODE_CONNECTOR_DSI), |
62 | VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DPI, |
63 | DRM_MODE_ENCODER_DPI, |
64 | DRM_MODE_CONNECTOR_DPI)), |
65 | VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv1_data, |
66 | VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI1, |
67 | DRM_MODE_ENCODER_DSI, |
68 | DRM_MODE_CONNECTOR_DSI)), |
69 | VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv2_data, |
70 | VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI0, |
71 | DRM_MODE_ENCODER_TMDS, |
72 | DRM_MODE_CONNECTOR_HDMIA), |
73 | VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_VEC, |
74 | DRM_MODE_ENCODER_TVDAC, |
75 | DRM_MODE_CONNECTOR_Composite)), |
76 | ); |
77 | |
78 | static const struct vc4_mock_desc vc5_mock = |
79 | VC4_MOCK_DESC( |
80 | VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data, |
81 | VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP, |
82 | DRM_MODE_ENCODER_VIRTUAL, |
83 | DRM_MODE_CONNECTOR_WRITEBACK)), |
84 | VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv0_data, |
85 | VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI0, |
86 | DRM_MODE_ENCODER_DSI, |
87 | DRM_MODE_CONNECTOR_DSI), |
88 | VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DPI, |
89 | DRM_MODE_ENCODER_DPI, |
90 | DRM_MODE_CONNECTOR_DPI)), |
91 | VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv1_data, |
92 | VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI1, |
93 | DRM_MODE_ENCODER_DSI, |
94 | DRM_MODE_CONNECTOR_DSI)), |
95 | VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv2_data, |
96 | VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI0, |
97 | DRM_MODE_ENCODER_TMDS, |
98 | DRM_MODE_CONNECTOR_HDMIA)), |
99 | VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv3_data, |
100 | VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_VEC, |
101 | DRM_MODE_ENCODER_TVDAC, |
102 | DRM_MODE_CONNECTOR_Composite)), |
103 | VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv4_data, |
104 | VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI1, |
105 | DRM_MODE_ENCODER_TMDS, |
106 | DRM_MODE_CONNECTOR_HDMIA)), |
107 | ); |
108 | |
109 | static int __build_one_pipe(struct kunit *test, struct drm_device *drm, |
110 | const struct vc4_mock_pipe_desc *pipe) |
111 | { |
112 | struct vc4_dummy_plane *dummy_plane; |
113 | struct drm_plane *plane; |
114 | struct vc4_dummy_crtc *dummy_crtc; |
115 | struct drm_crtc *crtc; |
116 | unsigned int i; |
117 | |
118 | dummy_plane = vc4_dummy_plane(test, drm, type: DRM_PLANE_TYPE_PRIMARY); |
119 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane); |
120 | |
121 | plane = &dummy_plane->plane.base; |
122 | dummy_crtc = vc4_mock_pv(test, drm, plane, data: pipe->data); |
123 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_crtc); |
124 | |
125 | crtc = &dummy_crtc->crtc.base; |
126 | for (i = 0; i < pipe->noutputs; i++) { |
127 | const struct vc4_mock_output_desc *mock_output = &pipe->outputs[i]; |
128 | struct vc4_dummy_output *dummy_output; |
129 | |
130 | dummy_output = vc4_dummy_output(test, drm, crtc, |
131 | vc4_encoder_type: mock_output->vc4_encoder_type, |
132 | kms_encoder_type: mock_output->encoder_type, |
133 | connector_type: mock_output->connector_type); |
134 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_output); |
135 | } |
136 | |
137 | return 0; |
138 | } |
139 | |
140 | static int __build_mock(struct kunit *test, struct drm_device *drm, |
141 | const struct vc4_mock_desc *mock) |
142 | { |
143 | unsigned int i; |
144 | |
145 | for (i = 0; i < mock->npipes; i++) { |
146 | const struct vc4_mock_pipe_desc *pipe = &mock->pipes[i]; |
147 | int ret; |
148 | |
149 | ret = __build_one_pipe(test, drm, pipe); |
150 | KUNIT_ASSERT_EQ(test, ret, 0); |
151 | } |
152 | |
153 | return 0; |
154 | } |
155 | |
156 | KUNIT_DEFINE_ACTION_WRAPPER(kunit_action_drm_dev_unregister, |
157 | drm_dev_unregister, |
158 | struct drm_device *); |
159 | |
160 | static struct vc4_dev *__mock_device(struct kunit *test, bool is_vc5) |
161 | { |
162 | struct drm_device *drm; |
163 | const struct drm_driver *drv = is_vc5 ? &vc5_drm_driver : &vc4_drm_driver; |
164 | const struct vc4_mock_desc *desc = is_vc5 ? &vc5_mock : &vc4_mock; |
165 | struct vc4_dev *vc4; |
166 | struct device *dev; |
167 | int ret; |
168 | |
169 | dev = drm_kunit_helper_alloc_device(test); |
170 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); |
171 | |
172 | vc4 = drm_kunit_helper_alloc_drm_device_with_driver(test, dev, |
173 | struct vc4_dev, base, |
174 | drv); |
175 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4); |
176 | |
177 | vc4->dev = dev; |
178 | vc4->is_vc5 = is_vc5; |
179 | |
180 | vc4->hvs = __vc4_hvs_alloc(vc4, NULL); |
181 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4->hvs); |
182 | |
183 | drm = &vc4->base; |
184 | ret = __build_mock(test, drm, mock: desc); |
185 | KUNIT_ASSERT_EQ(test, ret, 0); |
186 | |
187 | ret = vc4_kms_load(dev: drm); |
188 | KUNIT_ASSERT_EQ(test, ret, 0); |
189 | |
190 | ret = drm_dev_register(dev: drm, flags: 0); |
191 | KUNIT_ASSERT_EQ(test, ret, 0); |
192 | |
193 | ret = kunit_add_action_or_reset(test, |
194 | action: kunit_action_drm_dev_unregister, |
195 | ctx: drm); |
196 | KUNIT_ASSERT_EQ(test, ret, 0); |
197 | |
198 | return vc4; |
199 | } |
200 | |
201 | struct vc4_dev *vc4_mock_device(struct kunit *test) |
202 | { |
203 | return __mock_device(test, is_vc5: false); |
204 | } |
205 | |
206 | struct vc4_dev *vc5_mock_device(struct kunit *test) |
207 | { |
208 | return __mock_device(test, is_vc5: true); |
209 | } |
210 | |