1 // SPDX-License-Identifier: GPL-2.0+
2 #include <drm/drm_of.h>
3 #include <drm/drm_crtc_helper.h>
4 #include <drm/drm_probe_helper.h>
5 #include <drm/drm_simple_kms_helper.h>
6 #include <linux/component.h>
7 #include <linux/module.h>
8 #include <linux/platform_device.h>
9
10 #include "rockchip_drm_drv.h"
11 #include "rockchip_drm_vop.h"
12
13 #define XRES_DEF 1920
14 #define YRES_DEF 1080
15
16 struct vconn_device {
17 struct rockchip_vconn *vconn;
18 struct drm_encoder encoder;
19 struct drm_connector connector;
20 struct list_head list;
21 int encoder_type;
22 int output_type;
23 int output_mode;
24 int bus_format;
25 int if_id;
26 int vp_id_mask;
27 bool connected;
28 };
29
30 struct rockchip_vconn {
31 struct device *dev;
32 struct drm_device *drm_dev;
33 struct platform_device *pdev;
34 struct list_head list_head;
35 };
36
37 #define to_vconn_device(x) container_of(x, struct vconn_device, x)
38
39 static const struct drm_display_mode edid_cea_modes_1[] = {
40 /* 1 - 640x480@60Hz 4:3 */
41 { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
42 752, 800, 0, 480, 490, 492, 525, 0,
43 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
44 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
45 /* 2 - 720x480@60Hz 4:3 */
46 { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
47 798, 858, 0, 480, 489, 495, 525, 0,
48 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
49 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
50 /* 3 - 720x480@60Hz 16:9 */
51 { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
52 798, 858, 0, 480, 489, 495, 525, 0,
53 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
54 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
55 /* 4 - 1280x720@60Hz 16:9 */
56 { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
57 1430, 1650, 0, 720, 725, 730, 750, 0,
58 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
59 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
60 /* 5 - 1920x1080i@60Hz 16:9 */
61 { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
62 2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
63 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
64 DRM_MODE_FLAG_INTERLACE),
65 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
66 /* 6 - 720(1440)x480i@60Hz 4:3 */
67 { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 739,
68 801, 858, 0, 480, 488, 494, 525, 0,
69 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
70 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
71 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
72 /* 7 - 720(1440)x480i@60Hz 16:9 */
73 { DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500, 720, 739,
74 801, 858, 0, 480, 488, 494, 525, 0,
75 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
76 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
77 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
78 /* 16 - 1920x1080@60Hz 16:9 */
79 { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
80 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
81 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
82 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
83 /* 17 - 720x576@50Hz 4:3 */
84 { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
85 796, 864, 0, 576, 581, 586, 625, 0,
86 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
87 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
88 /* 18 - 720x576@50Hz 16:9 */
89 { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
90 796, 864, 0, 576, 581, 586, 625, 0,
91 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
92 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
93 /* 19 - 1280x720@50Hz 16:9 */
94 { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
95 1760, 1980, 0, 720, 725, 730, 750, 0,
96 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
97 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
98 /* 20 - 1920x1080i@50Hz 16:9 */
99 { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
100 2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
101 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
102 DRM_MODE_FLAG_INTERLACE),
103 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
104 /* 21 - 720(1440)x576i@50Hz 4:3 */
105 { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 732,
106 795, 864, 0, 576, 580, 586, 625, 0,
107 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
108 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
109 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
110 /* 22 - 720(1440)x576i@50Hz 16:9 */
111 { DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500, 720, 732,
112 795, 864, 0, 576, 580, 586, 625, 0,
113 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
114 DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
115 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
116 /* 31 - 1920x1080@50Hz 16:9 */
117 { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
118 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
119 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
120 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
121 /* 34 - 1920x1080@30Hz 16:9 */
122 { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
123 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
124 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
125 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
126 /* 39 - 1920x1080i@50Hz 16:9 */
127 { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952,
128 2120, 2304, 0, 1080, 1126, 1136, 1250, 0,
129 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC |
130 DRM_MODE_FLAG_INTERLACE),
131 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
132 /* 62 - 1280x720@30Hz 16:9 */
133 { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040,
134 3080, 3300, 0, 720, 725, 730, 750, 0,
135 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
136 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
137 /* 63 - 1920x1080@120Hz 16:9 */
138 { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008,
139 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
140 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
141 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
142 /* 67 - 1280x720@30Hz 64:27 */
143 { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040,
144 3080, 3300, 0, 720, 725, 730, 750, 0,
145 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
146 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
147 /* 68 - 1280x720@50Hz 64:27 */
148 { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
149 1760, 1980, 0, 720, 725, 730, 750, 0,
150 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
151 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
152 /* 69 - 1280x720@60Hz 64:27 */
153 { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
154 1430, 1650, 0, 720, 725, 730, 750, 0,
155 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
156 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
157 /* 70 - 1280x720@100Hz 64:27 */
158 { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720,
159 1760, 1980, 0, 720, 725, 730, 750, 0,
160 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
161 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
162 /* 71 - 1280x720@120Hz 64:27 */
163 { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390,
164 1430, 1650, 0, 720, 725, 730, 750, 0,
165 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
166 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
167 /* 74 - 1920x1080@30Hz 64:27 */
168 { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
169 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
170 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
171 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
172 /* 75 - 1920x1080@50Hz 64:27 */
173 { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
174 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
175 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
176 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
177 /* 76 - 1920x1080@60Hz 64:27 */
178 { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
179 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
180 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
181 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
182 /* 77 - 1920x1080@100Hz 64:27 */
183 { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448,
184 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
185 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
186 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
187 /* 78 - 1920x1080@120Hz 64:27 */
188 { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008,
189 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
190 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
191 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
192 /* 95 - 3840x2160@30Hz 16:9 */
193 { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016,
194 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
195 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
196 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
197 /* 96 - 3840x2160@50Hz 16:9 */
198 { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896,
199 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
200 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
201 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
202 /* 97 - 3840x2160@60Hz 16:9 */
203 { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016,
204 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
205 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
206 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
207 /* 100 - 4096x2160@30Hz 256:135 */
208 { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 4184,
209 4272, 4400, 0, 2160, 2168, 2178, 2250, 0,
210 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
211 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
212 /* 101 - 4096x2160@50Hz 256:135 */
213 { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 5064,
214 5152, 5280, 0, 2160, 2168, 2178, 2250, 0,
215 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
216 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
217 /* 102 - 4096x2160@60Hz 256:135 */
218 { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 4184,
219 4272, 4400, 0, 2160, 2168, 2178, 2250, 0,
220 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
221 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
222 /* 105 - 3840x2160@30Hz 64:27 */
223 { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016,
224 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
225 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
226 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
227 /* 106 - 3840x2160@50Hz 64:27 */
228 { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896,
229 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
230 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
231 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
232 /* 107 - 3840x2160@60Hz 64:27 */
233 { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016,
234 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
235 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
236 .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
237 };
238
vconn_drm_add_modes_noedid(struct drm_connector * connector)239 static int vconn_drm_add_modes_noedid(struct drm_connector *connector)
240 {
241 struct drm_device *dev = connector->dev;
242 struct drm_display_mode *mode;
243 int i, count, num_modes = 0;
244
245 count = ARRAY_SIZE(edid_cea_modes_1);
246
247 for (i = 0; i < count; i++) {
248 const struct drm_display_mode *ptr = &edid_cea_modes_1[i];
249
250 mode = drm_mode_duplicate(dev, ptr);
251 if (mode) {
252 drm_mode_probed_add(connector, mode);
253 num_modes++;
254 }
255 }
256
257 return num_modes;
258 }
259
rockchip_virtual_encoder_enable(struct drm_encoder * encoder)260 static void rockchip_virtual_encoder_enable(struct drm_encoder *encoder)
261 {
262 struct vconn_device *vconn_dev = to_vconn_device(encoder);
263 struct rockchip_vconn *vconn = vconn_dev->vconn;
264
265 dev_info(vconn->dev, "encoder enable for output%d\n", ffs(vconn_dev->if_id) - 1);
266 }
267
rockchip_virtual_encoder_disable(struct drm_encoder * encoder)268 static void rockchip_virtual_encoder_disable(struct drm_encoder *encoder)
269 {
270 struct vconn_device *vconn_dev = to_vconn_device(encoder);
271 struct rockchip_vconn *vconn = vconn_dev->vconn;
272 struct drm_crtc *crtc = encoder->crtc;
273 struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
274
275 vcstate->output_if &= ~vconn_dev->if_id;
276
277 dev_info(vconn->dev, "encoder disable for output%d\n", ffs(vconn_dev->if_id) - 1);
278 }
279
rockchip_virtual_encoder_atomic_check(struct drm_encoder * encoder,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)280 static int rockchip_virtual_encoder_atomic_check(struct drm_encoder *encoder,
281 struct drm_crtc_state *crtc_state,
282 struct drm_connector_state *conn_state)
283 {
284 return 0;
285 }
286
rockchip_virtual_encoder_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adj)287 static void rockchip_virtual_encoder_mode_set(struct drm_encoder *encoder,
288 struct drm_display_mode *mode,
289 struct drm_display_mode *adj)
290 {
291 struct drm_crtc *crtc = encoder->crtc;
292 struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
293 struct vconn_device *vconn_dev = to_vconn_device(encoder);
294 struct rockchip_vconn *vconn = vconn_dev->vconn;
295
296 vcstate->output_if |= vconn_dev->if_id;
297 vcstate->output_mode = vconn_dev->output_mode;
298 vcstate->output_type = vconn_dev->output_type;
299 vcstate->bus_format = vconn_dev->bus_format;
300
301 dev_info(vconn->dev, "mode set for output%d\n", ffs(vconn_dev->if_id) - 1);
302 }
303
304 static const struct drm_encoder_helper_funcs rockchip_virtual_encoder_helper_funcs = {
305 .enable = rockchip_virtual_encoder_enable,
306 .disable = rockchip_virtual_encoder_disable,
307 .atomic_check = rockchip_virtual_encoder_atomic_check,
308 .mode_set = rockchip_virtual_encoder_mode_set,
309 };
310
311 static enum drm_connector_status
rockchip_virtual_connector_detect(struct drm_connector * connector,bool force)312 rockchip_virtual_connector_detect(struct drm_connector *connector, bool force)
313 {
314 struct vconn_device *vconn_dev = to_vconn_device(connector);
315
316 if (vconn_dev->output_type == DRM_MODE_CONNECTOR_VIRTUAL)
317 return vconn_dev->connected ? connector_status_connected :
318 connector_status_disconnected;
319
320 return connector_status_connected;
321 }
322
rockchip_virtual_connector_destroy(struct drm_connector * connector)323 static void rockchip_virtual_connector_destroy(struct drm_connector *connector)
324 {
325 drm_connector_unregister(connector);
326 drm_connector_cleanup(connector);
327 }
328
329 static const struct drm_connector_funcs rockchip_virtual_connector_funcs = {
330 .detect = rockchip_virtual_connector_detect,
331 .fill_modes = drm_helper_probe_single_connector_modes,
332 .destroy = rockchip_virtual_connector_destroy,
333 .reset = drm_atomic_helper_connector_reset,
334 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
335 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
336 };
337
vvop_conn_get_modes(struct drm_connector * connector)338 static int vvop_conn_get_modes(struct drm_connector *connector)
339 {
340 int count;
341
342 count = vconn_drm_add_modes_noedid(connector);
343 drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF);
344
345 return count;
346 }
347
348 static const struct drm_connector_helper_funcs rockchip_virtual_connector_helper_funcs = {
349 .get_modes = vvop_conn_get_modes,
350 };
351
rockchip_virtual_connector_register(struct rockchip_vconn * vconn)352 static int rockchip_virtual_connector_register(struct rockchip_vconn *vconn)
353 {
354 struct vconn_device *vconn_dev, *n;
355 struct drm_encoder *encoder;
356 struct drm_connector *connector;
357 int ret;
358
359 list_for_each_entry_safe(vconn_dev, n, &vconn->list_head, list) {
360 encoder = &vconn_dev->encoder;
361 connector = &vconn_dev->connector;
362 encoder->possible_crtcs = vconn_dev->vp_id_mask;
363 drm_encoder_helper_add(encoder, &rockchip_virtual_encoder_helper_funcs);
364 ret = drm_simple_encoder_init(vconn->drm_dev, encoder, vconn_dev->encoder_type);
365 if (ret < 0) {
366 dev_err(vconn->dev, "failed to register encoder for output%d",
367 ffs(vconn_dev->if_id) - 1);
368 return ret;
369 }
370
371 drm_connector_helper_add(connector, &rockchip_virtual_connector_helper_funcs);
372 ret = drm_connector_init(vconn->drm_dev, connector,
373 &rockchip_virtual_connector_funcs, vconn_dev->output_type);
374 if (ret) {
375 dev_err(vconn->dev, "Failed to initialize connector for output%d\n",
376 ffs(vconn_dev->if_id) - 1);
377 return ret;
378 }
379
380 drm_connector_attach_encoder(connector, encoder);
381 }
382
383 return 0;
384 }
385
rockchip_vconn_parse_vp_id(struct rockchip_vconn * vconn,const char * name)386 static int rockchip_vconn_parse_vp_id(struct rockchip_vconn *vconn, const char *name)
387 {
388 struct device_node *np = vconn->dev->of_node;
389 char propname[16];
390 int ret;
391 u32 id;
392
393 if (strlen(name) > 6) {
394 dev_err(vconn->dev, "invalid connector name %s\n", name);
395 return -EINVAL;
396 }
397
398 snprintf(propname, sizeof(propname), "%s-enable", name);
399 if (of_property_read_bool(np, propname)) {
400 snprintf(propname, sizeof(propname), "%s-vp-id", name);
401 ret = of_property_read_u32(np, propname, &id);
402 if (ret < 0) {
403 dev_err(vconn->dev, "no specific vp-id for %s\n", name);
404 return ret;
405 }
406 return id;
407 }
408
409 return -ENODEV;
410 }
411
rockchip_vconn_get_encoder_type(int conn_type)412 static int rockchip_vconn_get_encoder_type(int conn_type)
413 {
414 if (conn_type == DRM_MODE_CONNECTOR_DSI)
415 return DRM_MODE_ENCODER_DSI;
416 else if (conn_type == DRM_MODE_CONNECTOR_DPI)
417 return DRM_MODE_ENCODER_DPI;
418 else if (conn_type == DRM_MODE_CONNECTOR_VIRTUAL)
419 return DRM_MODE_ENCODER_VIRTUAL;
420 else
421 return DRM_MODE_ENCODER_TMDS;
422 }
423
rockchip_vconn_device_create(struct rockchip_vconn * vconn,const char * name,int conn_type,int output_mode,int bus_format,int if_id)424 static int rockchip_vconn_device_create(struct rockchip_vconn *vconn,
425 const char *name,
426 int conn_type,
427 int output_mode,
428 int bus_format,
429 int if_id)
430 {
431 struct vconn_device *vconn_dev;
432 int id;
433
434 id = rockchip_vconn_parse_vp_id(vconn, name);
435 if (id >= 0) {
436 vconn_dev = devm_kzalloc(vconn->dev, sizeof(*vconn_dev), GFP_KERNEL);
437 if (!vconn_dev)
438 return -ENOMEM;
439 vconn_dev->vconn = vconn;
440 vconn_dev->encoder_type = rockchip_vconn_get_encoder_type(conn_type);
441 vconn_dev->output_type = conn_type;
442 vconn_dev->output_mode = output_mode;
443 vconn_dev->bus_format = bus_format;
444 vconn_dev->if_id = if_id;
445 vconn_dev->vp_id_mask = BIT(id);
446 list_add_tail(&vconn_dev->list, &vconn->list_head);
447 }
448
449 return 0;
450 }
451
rockchip_virtual_connectors_create(struct rockchip_vconn * vconn)452 static int rockchip_virtual_connectors_create(struct rockchip_vconn *vconn)
453 {
454 struct device_node *np = vconn->dev->of_node;
455 struct vconn_device *vconn_dev;
456 char propname[64];
457 u32 count;
458 int i;
459 int ret;
460
461 ret = of_property_read_u32(np, "virtual-connector-count", &count);
462 if (ret)
463 return ret;
464
465 for (i = 0; i < count; i++) {
466 vconn_dev = devm_kzalloc(vconn->dev, sizeof(*vconn_dev), GFP_KERNEL);
467 if (!vconn_dev)
468 return -ENOMEM;
469 snprintf(propname, sizeof(propname), "virtual%d-disconnected", i);
470 vconn_dev->connected = !of_property_read_bool(np, propname);
471 vconn_dev->vconn = vconn;
472 vconn_dev->encoder_type = DRM_MODE_ENCODER_VIRTUAL;
473 vconn_dev->output_type = DRM_MODE_CONNECTOR_VIRTUAL;
474 vconn_dev->output_mode = ROCKCHIP_OUT_MODE_AAAA;
475 vconn_dev->bus_format = MEDIA_BUS_FMT_FIXED;
476 vconn_dev->if_id = 0;
477 vconn_dev->vp_id_mask = 0;
478 list_add_tail(&vconn_dev->list, &vconn->list_head);
479 }
480
481 return 0;
482 }
483
rockchip_virtual_connector_bind(struct device * dev,struct device * master,void * data)484 static int rockchip_virtual_connector_bind(struct device *dev, struct device *master, void *data)
485 {
486 struct platform_device *pdev = to_platform_device(dev);
487 struct drm_device *drm = data;
488 struct rockchip_vconn *vconn;
489
490 if (!pdev->dev.of_node)
491 return -ENODEV;
492
493 vconn = devm_kzalloc(&pdev->dev, sizeof(*vconn), GFP_KERNEL);
494 if (!vconn)
495 return -ENOMEM;
496 vconn->dev = dev;
497 vconn->drm_dev = drm;
498
499 INIT_LIST_HEAD(&vconn->list_head);
500
501 rockchip_vconn_device_create(vconn, "hdmi0", DRM_MODE_CONNECTOR_HDMIA,
502 ROCKCHIP_OUT_MODE_AAAA, MEDIA_BUS_FMT_RGB888_1X24,
503 VOP_OUTPUT_IF_HDMI0);
504
505 rockchip_vconn_device_create(vconn, "hdmi1", DRM_MODE_CONNECTOR_HDMIA,
506 ROCKCHIP_OUT_MODE_AAAA, MEDIA_BUS_FMT_RGB888_1X24,
507 VOP_OUTPUT_IF_HDMI1);
508
509 rockchip_vconn_device_create(vconn, "dp0", DRM_MODE_CONNECTOR_DisplayPort,
510 ROCKCHIP_OUT_MODE_AAAA, MEDIA_BUS_FMT_RGB888_1X24,
511 VOP_OUTPUT_IF_DP0);
512
513 rockchip_vconn_device_create(vconn, "dp1", DRM_MODE_CONNECTOR_DisplayPort,
514 ROCKCHIP_OUT_MODE_AAAA, MEDIA_BUS_FMT_RGB888_1X24,
515 VOP_OUTPUT_IF_DP1);
516
517 rockchip_vconn_device_create(vconn, "edp0", DRM_MODE_CONNECTOR_eDP,
518 ROCKCHIP_OUT_MODE_AAAA, MEDIA_BUS_FMT_RGB888_1X24,
519 VOP_OUTPUT_IF_eDP0);
520
521 rockchip_vconn_device_create(vconn, "edp0", DRM_MODE_CONNECTOR_eDP,
522 ROCKCHIP_OUT_MODE_AAAA, MEDIA_BUS_FMT_RGB888_1X24,
523 VOP_OUTPUT_IF_eDP1);
524
525 rockchip_vconn_device_create(vconn, "mipi0", DRM_MODE_CONNECTOR_DSI,
526 ROCKCHIP_OUT_MODE_P888, MEDIA_BUS_FMT_RGB888_1X24,
527 VOP_OUTPUT_IF_MIPI0);
528
529 rockchip_vconn_device_create(vconn, "mipi1", DRM_MODE_CONNECTOR_DSI,
530 ROCKCHIP_OUT_MODE_P888, MEDIA_BUS_FMT_RGB888_1X24,
531 VOP_OUTPUT_IF_MIPI1);
532
533 rockchip_vconn_device_create(vconn, "rgb", DRM_MODE_CONNECTOR_DPI,
534 ROCKCHIP_OUT_MODE_P888, MEDIA_BUS_FMT_RGB888_1X24,
535 VOP_OUTPUT_IF_RGB);
536
537 rockchip_virtual_connectors_create(vconn);
538
539 platform_set_drvdata(pdev, vconn);
540
541 rockchip_virtual_connector_register(vconn);
542
543 return 0;
544 }
545
rockchip_virtual_connector_unbind(struct device * dev,struct device * master,void * data)546 static void rockchip_virtual_connector_unbind(struct device *dev, struct device *master,
547 void *data)
548 {
549 }
550
551 static const struct component_ops rockchip_virtual_connector_ops = {
552 .bind = rockchip_virtual_connector_bind,
553 .unbind = rockchip_virtual_connector_unbind,
554 };
555
rockchip_virtual_connector_probe(struct platform_device * pdev)556 static int rockchip_virtual_connector_probe(struct platform_device *pdev)
557 {
558 return component_add(&pdev->dev, &rockchip_virtual_connector_ops);
559 }
560
rockchip_virtual_connector_shutdown(struct platform_device * pdev)561 static void rockchip_virtual_connector_shutdown(struct platform_device *pdev)
562 {
563 }
564
rockchip_virtual_connector_remove(struct platform_device * pdev)565 static int rockchip_virtual_connector_remove(struct platform_device *pdev)
566 {
567 component_del(&pdev->dev, &rockchip_virtual_connector_ops);
568
569 return 0;
570 }
571
572 static const struct of_device_id rockchip_virtual_connector_dt_ids[] = {
573 { .compatible = "rockchip,virtual-connector",
574 },
575 {},
576 };
577 MODULE_DEVICE_TABLE(of, rockchip_virtual_connector_dt_ids);
578
579 struct platform_driver vconn_platform_driver = {
580 .probe = rockchip_virtual_connector_probe,
581 .remove = rockchip_virtual_connector_remove,
582 .shutdown = rockchip_virtual_connector_shutdown,
583 .driver = {
584 .name = "drm-virtual-connector",
585 .of_match_table = rockchip_virtual_connector_dt_ids,
586 },
587 };
588