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