xref: /linux/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c (revision fbf5df34a4dbcd09d433dd4f0916bf9b2ddb16de)
1 // SPDX-License-Identifier: GPL-2.0+
2 
3 /*
4  * Copyright 2020,2022 NXP
5  */
6 
7 #include <linux/firmware/imx/svc/misc.h>
8 #include <linux/media-bus-format.h>
9 #include <linux/module.h>
10 #include <linux/of.h>
11 #include <linux/of_graph.h>
12 #include <linux/platform_device.h>
13 
14 #include <drm/drm_atomic_state_helper.h>
15 #include <drm/drm_bridge.h>
16 #include <drm/drm_print.h>
17 
18 #include <dt-bindings/firmware/imx/rsrc.h>
19 
20 #define DRIVER_NAME		"imx8qxp-display-pixel-link"
21 #define PL_MAX_MST_ADDR		3
22 #define PL_MAX_NEXT_BRIDGES	2
23 
24 struct imx8qxp_pixel_link {
25 	struct drm_bridge bridge;
26 	struct device *dev;
27 	struct imx_sc_ipc *ipc_handle;
28 	u8 stream_id;
29 	u8 dc_id;
30 	u32 sink_rsc;
31 	u32 mst_addr;
32 	u8 mst_addr_ctrl;
33 	u8 mst_en_ctrl;
34 	u8 mst_vld_ctrl;
35 	u8 sync_ctrl;
36 };
37 
38 static void imx8qxp_pixel_link_enable_mst_en(struct imx8qxp_pixel_link *pl)
39 {
40 	int ret;
41 
42 	ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
43 				      pl->mst_en_ctrl, true);
44 	if (ret)
45 		DRM_DEV_ERROR(pl->dev,
46 			      "failed to enable DC%u stream%u pixel link mst_en: %d\n",
47 			      pl->dc_id, pl->stream_id, ret);
48 }
49 
50 static void imx8qxp_pixel_link_enable_mst_vld(struct imx8qxp_pixel_link *pl)
51 {
52 	int ret;
53 
54 	ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
55 				      pl->mst_vld_ctrl, true);
56 	if (ret)
57 		DRM_DEV_ERROR(pl->dev,
58 			      "failed to enable DC%u stream%u pixel link mst_vld: %d\n",
59 			      pl->dc_id, pl->stream_id, ret);
60 }
61 
62 static void imx8qxp_pixel_link_enable_sync(struct imx8qxp_pixel_link *pl)
63 {
64 	int ret;
65 
66 	ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
67 				      pl->sync_ctrl, true);
68 	if (ret)
69 		DRM_DEV_ERROR(pl->dev,
70 			      "failed to enable DC%u stream%u pixel link sync: %d\n",
71 			      pl->dc_id, pl->stream_id, ret);
72 }
73 
74 static int imx8qxp_pixel_link_disable_mst_en(struct imx8qxp_pixel_link *pl)
75 {
76 	int ret;
77 
78 	ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
79 				      pl->mst_en_ctrl, false);
80 	if (ret)
81 		DRM_DEV_ERROR(pl->dev,
82 			      "failed to disable DC%u stream%u pixel link mst_en: %d\n",
83 			      pl->dc_id, pl->stream_id, ret);
84 
85 	return ret;
86 }
87 
88 static int imx8qxp_pixel_link_disable_mst_vld(struct imx8qxp_pixel_link *pl)
89 {
90 	int ret;
91 
92 	ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
93 				      pl->mst_vld_ctrl, false);
94 	if (ret)
95 		DRM_DEV_ERROR(pl->dev,
96 			      "failed to disable DC%u stream%u pixel link mst_vld: %d\n",
97 			      pl->dc_id, pl->stream_id, ret);
98 
99 	return ret;
100 }
101 
102 static int imx8qxp_pixel_link_disable_sync(struct imx8qxp_pixel_link *pl)
103 {
104 	int ret;
105 
106 	ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
107 				      pl->sync_ctrl, false);
108 	if (ret)
109 		DRM_DEV_ERROR(pl->dev,
110 			      "failed to disable DC%u stream%u pixel link sync: %d\n",
111 			      pl->dc_id, pl->stream_id, ret);
112 
113 	return ret;
114 }
115 
116 static void imx8qxp_pixel_link_set_mst_addr(struct imx8qxp_pixel_link *pl)
117 {
118 	int ret;
119 
120 	ret = imx_sc_misc_set_control(pl->ipc_handle,
121 				      pl->sink_rsc, pl->mst_addr_ctrl,
122 				      pl->mst_addr);
123 	if (ret)
124 		DRM_DEV_ERROR(pl->dev,
125 			      "failed to set DC%u stream%u pixel link mst addr(%u): %d\n",
126 			      pl->dc_id, pl->stream_id, pl->mst_addr, ret);
127 }
128 
129 static int imx8qxp_pixel_link_bridge_attach(struct drm_bridge *bridge,
130 					    struct drm_encoder *encoder,
131 					    enum drm_bridge_attach_flags flags)
132 {
133 	struct imx8qxp_pixel_link *pl = bridge->driver_private;
134 
135 	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
136 		DRM_DEV_ERROR(pl->dev,
137 			      "do not support creating a drm_connector\n");
138 		return -EINVAL;
139 	}
140 
141 	return drm_bridge_attach(encoder,
142 				 pl->bridge.next_bridge, bridge,
143 				 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
144 }
145 
146 static void
147 imx8qxp_pixel_link_bridge_mode_set(struct drm_bridge *bridge,
148 				   const struct drm_display_mode *mode,
149 				   const struct drm_display_mode *adjusted_mode)
150 {
151 	struct imx8qxp_pixel_link *pl = bridge->driver_private;
152 
153 	imx8qxp_pixel_link_set_mst_addr(pl);
154 }
155 
156 static void imx8qxp_pixel_link_bridge_atomic_enable(struct drm_bridge *bridge,
157 						    struct drm_atomic_state *state)
158 {
159 	struct imx8qxp_pixel_link *pl = bridge->driver_private;
160 
161 	imx8qxp_pixel_link_enable_mst_en(pl);
162 	imx8qxp_pixel_link_enable_mst_vld(pl);
163 	imx8qxp_pixel_link_enable_sync(pl);
164 }
165 
166 static void imx8qxp_pixel_link_bridge_atomic_disable(struct drm_bridge *bridge,
167 						     struct drm_atomic_state *state)
168 {
169 	struct imx8qxp_pixel_link *pl = bridge->driver_private;
170 
171 	imx8qxp_pixel_link_disable_mst_en(pl);
172 	imx8qxp_pixel_link_disable_mst_vld(pl);
173 	imx8qxp_pixel_link_disable_sync(pl);
174 }
175 
176 static const u32 imx8qxp_pixel_link_bus_output_fmts[] = {
177 	MEDIA_BUS_FMT_RGB888_1X36_CPADLO,
178 	MEDIA_BUS_FMT_RGB666_1X36_CPADLO,
179 };
180 
181 static bool imx8qxp_pixel_link_bus_output_fmt_supported(u32 fmt)
182 {
183 	int i;
184 
185 	for (i = 0; i < ARRAY_SIZE(imx8qxp_pixel_link_bus_output_fmts); i++) {
186 		if (imx8qxp_pixel_link_bus_output_fmts[i] == fmt)
187 			return true;
188 	}
189 
190 	return false;
191 }
192 
193 static u32 *
194 imx8qxp_pixel_link_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
195 						    struct drm_bridge_state *bridge_state,
196 						    struct drm_crtc_state *crtc_state,
197 						    struct drm_connector_state *conn_state,
198 						    u32 output_fmt,
199 						    unsigned int *num_input_fmts)
200 {
201 	u32 *input_fmts;
202 
203 	if (!imx8qxp_pixel_link_bus_output_fmt_supported(output_fmt))
204 		return NULL;
205 
206 	*num_input_fmts = 1;
207 
208 	input_fmts = kmalloc_obj(*input_fmts);
209 	if (!input_fmts)
210 		return NULL;
211 
212 	input_fmts[0] = output_fmt;
213 
214 	return input_fmts;
215 }
216 
217 static u32 *
218 imx8qxp_pixel_link_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
219 						     struct drm_bridge_state *bridge_state,
220 						     struct drm_crtc_state *crtc_state,
221 						     struct drm_connector_state *conn_state,
222 						     unsigned int *num_output_fmts)
223 {
224 	*num_output_fmts = ARRAY_SIZE(imx8qxp_pixel_link_bus_output_fmts);
225 	return kmemdup(imx8qxp_pixel_link_bus_output_fmts,
226 			sizeof(imx8qxp_pixel_link_bus_output_fmts), GFP_KERNEL);
227 }
228 
229 static const struct drm_bridge_funcs imx8qxp_pixel_link_bridge_funcs = {
230 	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
231 	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
232 	.atomic_reset		= drm_atomic_helper_bridge_reset,
233 	.attach			= imx8qxp_pixel_link_bridge_attach,
234 	.mode_set		= imx8qxp_pixel_link_bridge_mode_set,
235 	.atomic_enable		= imx8qxp_pixel_link_bridge_atomic_enable,
236 	.atomic_disable		= imx8qxp_pixel_link_bridge_atomic_disable,
237 	.atomic_get_input_bus_fmts =
238 			imx8qxp_pixel_link_bridge_atomic_get_input_bus_fmts,
239 	.atomic_get_output_bus_fmts =
240 			imx8qxp_pixel_link_bridge_atomic_get_output_bus_fmts,
241 };
242 
243 static int imx8qxp_pixel_link_disable_all_controls(struct imx8qxp_pixel_link *pl)
244 {
245 	int ret;
246 
247 	ret = imx8qxp_pixel_link_disable_mst_en(pl);
248 	if (ret)
249 		return ret;
250 
251 	ret = imx8qxp_pixel_link_disable_mst_vld(pl);
252 	if (ret)
253 		return ret;
254 
255 	return imx8qxp_pixel_link_disable_sync(pl);
256 }
257 
258 static int imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
259 {
260 	struct device_node *np = pl->dev->of_node;
261 	struct device_node *port;
262 	u32 port_id;
263 	bool found_port = false;
264 	int reg;
265 
266 	for (port_id = 1; port_id <= PL_MAX_MST_ADDR + 1; port_id++) {
267 		port = of_graph_get_port_by_id(np, port_id);
268 		if (!port)
269 			continue;
270 
271 		if (of_device_is_available(port)) {
272 			found_port = true;
273 			of_node_put(port);
274 			break;
275 		}
276 
277 		of_node_put(port);
278 	}
279 
280 	if (!found_port) {
281 		DRM_DEV_ERROR(pl->dev, "no available output port\n");
282 		return -ENODEV;
283 	}
284 
285 	for (reg = 0; reg < PL_MAX_NEXT_BRIDGES; reg++) {
286 		struct device_node *remote __free(device_node) =
287 			of_graph_get_remote_node(np, port_id, reg);
288 		if (!remote)
289 			continue;
290 
291 		if (!of_device_is_available(remote->parent)) {
292 			DRM_DEV_DEBUG(pl->dev,
293 				      "port%u endpoint%u remote parent is not available\n",
294 				      port_id, reg);
295 			continue;
296 		}
297 
298 		if (!pl->bridge.next_bridge) {
299 			/* Select the first bridge by default... */
300 			pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
301 			if (!pl->bridge.next_bridge)
302 				return -EPROBE_DEFER;
303 		} else if (of_property_present(remote, "fsl,companion-pxl2dpi")) {
304 			/* ... but prefer the companion PXL2DPI if present */
305 			drm_bridge_put(pl->bridge.next_bridge);
306 			pl->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
307 			if (!pl->bridge.next_bridge)
308 				return -EPROBE_DEFER;
309 		}
310 	}
311 
312 	pl->mst_addr = port_id - 1;
313 
314 	return 0;
315 }
316 
317 static int imx8qxp_pixel_link_bridge_probe(struct platform_device *pdev)
318 {
319 	struct imx8qxp_pixel_link *pl;
320 	struct device *dev = &pdev->dev;
321 	struct device_node *np = dev->of_node;
322 	int ret;
323 
324 	pl = devm_drm_bridge_alloc(dev, struct imx8qxp_pixel_link, bridge,
325 				   &imx8qxp_pixel_link_bridge_funcs);
326 	if (IS_ERR(pl))
327 		return PTR_ERR(pl);
328 
329 	ret = imx_scu_get_handle(&pl->ipc_handle);
330 	if (ret) {
331 		if (ret != -EPROBE_DEFER)
332 			DRM_DEV_ERROR(dev, "failed to get SCU ipc handle: %d\n",
333 				      ret);
334 		return ret;
335 	}
336 
337 	ret = of_property_read_u8(np, "fsl,dc-id", &pl->dc_id);
338 	if (ret) {
339 		DRM_DEV_ERROR(dev, "failed to get DC index: %d\n", ret);
340 		return ret;
341 	}
342 
343 	ret = of_property_read_u8(np, "fsl,dc-stream-id", &pl->stream_id);
344 	if (ret) {
345 		DRM_DEV_ERROR(dev, "failed to get DC stream index: %d\n", ret);
346 		return ret;
347 	}
348 
349 	pl->dev = dev;
350 
351 	pl->sink_rsc = pl->dc_id ? IMX_SC_R_DC_1 : IMX_SC_R_DC_0;
352 
353 	if (pl->stream_id == 0) {
354 		pl->mst_addr_ctrl = IMX_SC_C_PXL_LINK_MST1_ADDR;
355 		pl->mst_en_ctrl   = IMX_SC_C_PXL_LINK_MST1_ENB;
356 		pl->mst_vld_ctrl  = IMX_SC_C_PXL_LINK_MST1_VLD;
357 		pl->sync_ctrl     = IMX_SC_C_SYNC_CTRL0;
358 	} else {
359 		pl->mst_addr_ctrl = IMX_SC_C_PXL_LINK_MST2_ADDR;
360 		pl->mst_en_ctrl   = IMX_SC_C_PXL_LINK_MST2_ENB;
361 		pl->mst_vld_ctrl  = IMX_SC_C_PXL_LINK_MST2_VLD;
362 		pl->sync_ctrl     = IMX_SC_C_SYNC_CTRL1;
363 	}
364 
365 	/* disable all controls to POR default */
366 	ret = imx8qxp_pixel_link_disable_all_controls(pl);
367 	if (ret)
368 		return ret;
369 
370 	ret = imx8qxp_pixel_link_find_next_bridge(pl);
371 	if (ret)
372 		return ret;
373 
374 	platform_set_drvdata(pdev, pl);
375 
376 	pl->bridge.driver_private = pl;
377 	pl->bridge.of_node = np;
378 
379 	drm_bridge_add(&pl->bridge);
380 
381 	return ret;
382 }
383 
384 static void imx8qxp_pixel_link_bridge_remove(struct platform_device *pdev)
385 {
386 	struct imx8qxp_pixel_link *pl = platform_get_drvdata(pdev);
387 
388 	drm_bridge_remove(&pl->bridge);
389 }
390 
391 static const struct of_device_id imx8qxp_pixel_link_dt_ids[] = {
392 	{ .compatible = "fsl,imx8qm-dc-pixel-link", },
393 	{ .compatible = "fsl,imx8qxp-dc-pixel-link", },
394 	{ /* sentinel */ }
395 };
396 MODULE_DEVICE_TABLE(of, imx8qxp_pixel_link_dt_ids);
397 
398 static struct platform_driver imx8qxp_pixel_link_bridge_driver = {
399 	.probe	= imx8qxp_pixel_link_bridge_probe,
400 	.remove = imx8qxp_pixel_link_bridge_remove,
401 	.driver	= {
402 		.of_match_table = imx8qxp_pixel_link_dt_ids,
403 		.name = DRIVER_NAME,
404 	},
405 };
406 module_platform_driver(imx8qxp_pixel_link_bridge_driver);
407 
408 MODULE_DESCRIPTION("i.MX8QXP/QM display pixel link bridge driver");
409 MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
410 MODULE_LICENSE("GPL v2");
411 MODULE_ALIAS("platform:" DRIVER_NAME);
412