xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/rockchip/rockchip_drm_vconn.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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