xref: /linux/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c (revision be1ca3ee8f97067fee87fda73ea5959d5ab75bbf)
1 // SPDX-License-Identifier: GPL-2.0+
2 
3 /*
4  * Copyright 2020 NXP
5  */
6 
7 #include <linux/bitfield.h>
8 #include <linux/clk.h>
9 #include <linux/delay.h>
10 #include <linux/io.h>
11 #include <linux/media-bus-format.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/of_graph.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm_runtime.h>
17 
18 #include <drm/drm_atomic_state_helper.h>
19 #include <drm/drm_bridge.h>
20 #include <drm/drm_print.h>
21 
22 #define PC_CTRL_REG			0x0
23 #define  PC_COMBINE_ENABLE		BIT(0)
24 #define  PC_DISP_BYPASS(n)		BIT(1 + 21 * (n))
25 #define  PC_DISP_HSYNC_POLARITY(n)	BIT(2 + 11 * (n))
26 #define  PC_DISP_HSYNC_POLARITY_POS(n)	DISP_HSYNC_POLARITY(n)
27 #define  PC_DISP_VSYNC_POLARITY(n)	BIT(3 + 11 * (n))
28 #define  PC_DISP_VSYNC_POLARITY_POS(n)	DISP_VSYNC_POLARITY(n)
29 #define  PC_DISP_DVALID_POLARITY(n)	BIT(4 + 11 * (n))
30 #define  PC_DISP_DVALID_POLARITY_POS(n)	DISP_DVALID_POLARITY(n)
31 #define  PC_VSYNC_MASK_ENABLE		BIT(5)
32 #define  PC_SKIP_MODE			BIT(6)
33 #define  PC_SKIP_NUMBER_MASK		GENMASK(12, 7)
34 #define  PC_SKIP_NUMBER(n)		FIELD_PREP(PC_SKIP_NUMBER_MASK, (n))
35 #define  PC_DISP0_PIX_DATA_FORMAT_MASK	GENMASK(18, 16)
36 #define  PC_DISP0_PIX_DATA_FORMAT(fmt)	\
37 				FIELD_PREP(PC_DISP0_PIX_DATA_FORMAT_MASK, (fmt))
38 #define  PC_DISP1_PIX_DATA_FORMAT_MASK	GENMASK(21, 19)
39 #define  PC_DISP1_PIX_DATA_FORMAT(fmt)	\
40 				FIELD_PREP(PC_DISP1_PIX_DATA_FORMAT_MASK, (fmt))
41 
42 #define PC_SW_RESET_REG			0x20
43 #define  PC_SW_RESET_N			BIT(0)
44 #define  PC_DISP_SW_RESET_N(n)		BIT(1 + (n))
45 #define  PC_FULL_RESET_N		(PC_SW_RESET_N |		\
46 					 PC_DISP_SW_RESET_N(0) |	\
47 					 PC_DISP_SW_RESET_N(1))
48 
49 #define PC_REG_SET			0x4
50 #define PC_REG_CLR			0x8
51 
52 #define DRIVER_NAME			"imx8qxp-pixel-combiner"
53 
54 enum imx8qxp_pc_pix_data_format {
55 	RGB,
56 	YUV444,
57 	YUV422,
58 	SPLIT_RGB,
59 };
60 
61 struct imx8qxp_pc_channel {
62 	struct drm_bridge bridge;
63 	struct imx8qxp_pc *pc;
64 	unsigned int stream_id;
65 };
66 
67 struct imx8qxp_pc {
68 	struct device *dev;
69 	struct imx8qxp_pc_channel *ch[2];
70 	struct clk *clk_apb;
71 	void __iomem *base;
72 };
73 
74 static inline u32 imx8qxp_pc_read(struct imx8qxp_pc *pc, unsigned int offset)
75 {
76 	return readl(pc->base + offset);
77 }
78 
79 static inline void
80 imx8qxp_pc_write(struct imx8qxp_pc *pc, unsigned int offset, u32 value)
81 {
82 	writel(value, pc->base + offset);
83 }
84 
85 static inline void
86 imx8qxp_pc_write_set(struct imx8qxp_pc *pc, unsigned int offset, u32 value)
87 {
88 	imx8qxp_pc_write(pc, offset + PC_REG_SET, value);
89 }
90 
91 static inline void
92 imx8qxp_pc_write_clr(struct imx8qxp_pc *pc, unsigned int offset, u32 value)
93 {
94 	imx8qxp_pc_write(pc, offset + PC_REG_CLR, value);
95 }
96 
97 static enum drm_mode_status
98 imx8qxp_pc_bridge_mode_valid(struct drm_bridge *bridge,
99 			     const struct drm_display_info *info,
100 			     const struct drm_display_mode *mode)
101 {
102 	if (mode->hdisplay > 2560)
103 		return MODE_BAD_HVALUE;
104 
105 	return MODE_OK;
106 }
107 
108 static int imx8qxp_pc_bridge_attach(struct drm_bridge *bridge,
109 				    struct drm_encoder *encoder,
110 				    enum drm_bridge_attach_flags flags)
111 {
112 	struct imx8qxp_pc_channel *ch = bridge->driver_private;
113 	struct imx8qxp_pc *pc = ch->pc;
114 
115 	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
116 		DRM_DEV_ERROR(pc->dev,
117 			      "do not support creating a drm_connector\n");
118 		return -EINVAL;
119 	}
120 
121 	return drm_bridge_attach(encoder,
122 				 ch->bridge.next_bridge, bridge,
123 				 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
124 }
125 
126 static void
127 imx8qxp_pc_bridge_mode_set(struct drm_bridge *bridge,
128 			   const struct drm_display_mode *mode,
129 			   const struct drm_display_mode *adjusted_mode)
130 {
131 	struct imx8qxp_pc_channel *ch = bridge->driver_private;
132 	struct imx8qxp_pc *pc = ch->pc;
133 	u32 val;
134 	int ret;
135 
136 	ret = pm_runtime_get_sync(pc->dev);
137 	if (ret < 0)
138 		DRM_DEV_ERROR(pc->dev,
139 			      "failed to get runtime PM sync: %d\n", ret);
140 
141 	ret = clk_prepare_enable(pc->clk_apb);
142 	if (ret)
143 		DRM_DEV_ERROR(pc->dev, "%s: failed to enable apb clock: %d\n",
144 			      __func__,  ret);
145 
146 	/* HSYNC to pixel link is active low. */
147 	imx8qxp_pc_write_clr(pc, PC_CTRL_REG,
148 			     PC_DISP_HSYNC_POLARITY(ch->stream_id));
149 
150 	/* VSYNC to pixel link is active low. */
151 	imx8qxp_pc_write_clr(pc, PC_CTRL_REG,
152 			     PC_DISP_VSYNC_POLARITY(ch->stream_id));
153 
154 	/* Data enable to pixel link is active high. */
155 	imx8qxp_pc_write_set(pc, PC_CTRL_REG,
156 			     PC_DISP_DVALID_POLARITY(ch->stream_id));
157 
158 	/* Mask the first frame output which may be incomplete. */
159 	imx8qxp_pc_write_set(pc, PC_CTRL_REG, PC_VSYNC_MASK_ENABLE);
160 
161 	/* Only support RGB currently. */
162 	val = imx8qxp_pc_read(pc, PC_CTRL_REG);
163 	if (ch->stream_id == 0) {
164 		val &= ~PC_DISP0_PIX_DATA_FORMAT_MASK;
165 		val |= PC_DISP0_PIX_DATA_FORMAT(RGB);
166 	} else {
167 		val &= ~PC_DISP1_PIX_DATA_FORMAT_MASK;
168 		val |= PC_DISP1_PIX_DATA_FORMAT(RGB);
169 	}
170 	imx8qxp_pc_write(pc, PC_CTRL_REG, val);
171 
172 	/* Only support bypass mode currently. */
173 	imx8qxp_pc_write_set(pc, PC_CTRL_REG, PC_DISP_BYPASS(ch->stream_id));
174 
175 	clk_disable_unprepare(pc->clk_apb);
176 }
177 
178 static void imx8qxp_pc_bridge_atomic_disable(struct drm_bridge *bridge,
179 					     struct drm_atomic_state *state)
180 {
181 	struct imx8qxp_pc_channel *ch = bridge->driver_private;
182 	struct imx8qxp_pc *pc = ch->pc;
183 
184 	pm_runtime_put(pc->dev);
185 }
186 
187 static const u32 imx8qxp_pc_bus_output_fmts[] = {
188 	MEDIA_BUS_FMT_RGB888_1X36_CPADLO,
189 	MEDIA_BUS_FMT_RGB666_1X36_CPADLO,
190 };
191 
192 static bool imx8qxp_pc_bus_output_fmt_supported(u32 fmt)
193 {
194 	int i;
195 
196 	for (i = 0; i < ARRAY_SIZE(imx8qxp_pc_bus_output_fmts); i++) {
197 		if (imx8qxp_pc_bus_output_fmts[i] == fmt)
198 			return true;
199 	}
200 
201 	return false;
202 }
203 
204 static u32 *
205 imx8qxp_pc_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
206 					    struct drm_bridge_state *bridge_state,
207 					    struct drm_crtc_state *crtc_state,
208 					    struct drm_connector_state *conn_state,
209 					    u32 output_fmt,
210 					    unsigned int *num_input_fmts)
211 {
212 	u32 *input_fmts;
213 
214 	if (!imx8qxp_pc_bus_output_fmt_supported(output_fmt))
215 		return NULL;
216 
217 	*num_input_fmts = 1;
218 
219 	input_fmts = kmalloc_obj(*input_fmts);
220 	if (!input_fmts)
221 		return NULL;
222 
223 	switch (output_fmt) {
224 	case MEDIA_BUS_FMT_RGB888_1X36_CPADLO:
225 		input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X30_CPADLO;
226 		break;
227 	case MEDIA_BUS_FMT_RGB666_1X36_CPADLO:
228 		input_fmts[0] = MEDIA_BUS_FMT_RGB666_1X30_CPADLO;
229 		break;
230 	default:
231 		kfree(input_fmts);
232 		input_fmts = NULL;
233 		break;
234 	}
235 
236 	return input_fmts;
237 }
238 
239 static u32 *
240 imx8qxp_pc_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
241 					     struct drm_bridge_state *bridge_state,
242 					     struct drm_crtc_state *crtc_state,
243 					     struct drm_connector_state *conn_state,
244 					     unsigned int *num_output_fmts)
245 {
246 	*num_output_fmts = ARRAY_SIZE(imx8qxp_pc_bus_output_fmts);
247 	return kmemdup(imx8qxp_pc_bus_output_fmts,
248 			sizeof(imx8qxp_pc_bus_output_fmts), GFP_KERNEL);
249 }
250 
251 static const struct drm_bridge_funcs imx8qxp_pc_bridge_funcs = {
252 	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
253 	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
254 	.atomic_reset		= drm_atomic_helper_bridge_reset,
255 	.mode_valid		= imx8qxp_pc_bridge_mode_valid,
256 	.attach			= imx8qxp_pc_bridge_attach,
257 	.mode_set		= imx8qxp_pc_bridge_mode_set,
258 	.atomic_disable		= imx8qxp_pc_bridge_atomic_disable,
259 	.atomic_get_input_bus_fmts =
260 				imx8qxp_pc_bridge_atomic_get_input_bus_fmts,
261 	.atomic_get_output_bus_fmts =
262 				imx8qxp_pc_bridge_atomic_get_output_bus_fmts,
263 };
264 
265 static int imx8qxp_pc_bridge_probe(struct platform_device *pdev)
266 {
267 	struct imx8qxp_pc *pc;
268 	struct imx8qxp_pc_channel *ch;
269 	struct device *dev = &pdev->dev;
270 	struct device_node *np = dev->of_node;
271 	struct device_node *child, *remote;
272 	u32 i;
273 	int ret;
274 
275 	pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
276 	if (!pc)
277 		return -ENOMEM;
278 
279 	pc->base = devm_platform_ioremap_resource(pdev, 0);
280 	if (IS_ERR(pc->base))
281 		return PTR_ERR(pc->base);
282 
283 	pc->dev = dev;
284 
285 	pc->clk_apb = devm_clk_get(dev, "apb");
286 	if (IS_ERR(pc->clk_apb)) {
287 		ret = PTR_ERR(pc->clk_apb);
288 		if (ret != -EPROBE_DEFER)
289 			DRM_DEV_ERROR(dev, "failed to get apb clock: %d\n", ret);
290 		return ret;
291 	}
292 
293 	platform_set_drvdata(pdev, pc);
294 	pm_runtime_enable(dev);
295 
296 	for_each_available_child_of_node(np, child) {
297 		ret = of_property_read_u32(child, "reg", &i);
298 		if (ret || i > 1) {
299 			ret = -EINVAL;
300 			DRM_DEV_ERROR(dev,
301 				      "invalid channel(%u) node address\n", i);
302 			goto free_child;
303 		}
304 
305 		ch = devm_drm_bridge_alloc(dev, struct imx8qxp_pc_channel, bridge,
306 					   &imx8qxp_pc_bridge_funcs);
307 		if (IS_ERR(ch)) {
308 			ret = PTR_ERR(ch);
309 			goto free_child;
310 		}
311 
312 		pc->ch[i] = ch;
313 		ch->pc = pc;
314 		ch->stream_id = i;
315 
316 		remote = of_graph_get_remote_node(child, 1, 0);
317 		if (!remote) {
318 			ret = -ENODEV;
319 			DRM_DEV_ERROR(dev,
320 				      "channel%u failed to get port1's remote node: %d\n",
321 				      i, ret);
322 			goto free_child;
323 		}
324 
325 		ch->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
326 		if (!ch->bridge.next_bridge) {
327 			of_node_put(remote);
328 			ret = -EPROBE_DEFER;
329 			DRM_DEV_DEBUG_DRIVER(dev,
330 					     "channel%u failed to find next bridge: %d\n",
331 					     i, ret);
332 			goto free_child;
333 		}
334 
335 		of_node_put(remote);
336 
337 		ch->bridge.driver_private = ch;
338 		ch->bridge.of_node = child;
339 
340 		drm_bridge_add(&ch->bridge);
341 	}
342 
343 	return 0;
344 
345 free_child:
346 	of_node_put(child);
347 
348 	if (i == 1 && pc->ch[0] && pc->ch[0]->bridge.next_bridge)
349 		drm_bridge_remove(&pc->ch[0]->bridge);
350 
351 	pm_runtime_disable(dev);
352 	return ret;
353 }
354 
355 static void imx8qxp_pc_bridge_remove(struct platform_device *pdev)
356 {
357 	struct imx8qxp_pc *pc = platform_get_drvdata(pdev);
358 	struct imx8qxp_pc_channel *ch;
359 	int i;
360 
361 	for (i = 0; i < 2; i++) {
362 		ch = pc->ch[i];
363 
364 		if (ch)
365 			drm_bridge_remove(&ch->bridge);
366 	}
367 
368 	pm_runtime_disable(&pdev->dev);
369 }
370 
371 static int imx8qxp_pc_runtime_suspend(struct device *dev)
372 {
373 	struct platform_device *pdev = to_platform_device(dev);
374 	struct imx8qxp_pc *pc = platform_get_drvdata(pdev);
375 	int ret;
376 
377 	ret = clk_prepare_enable(pc->clk_apb);
378 	if (ret)
379 		DRM_DEV_ERROR(pc->dev, "%s: failed to enable apb clock: %d\n",
380 			      __func__,  ret);
381 
382 	/* Disable pixel combiner by full reset. */
383 	imx8qxp_pc_write_clr(pc, PC_SW_RESET_REG, PC_FULL_RESET_N);
384 
385 	clk_disable_unprepare(pc->clk_apb);
386 
387 	/* Ensure the reset takes effect. */
388 	usleep_range(10, 20);
389 
390 	return ret;
391 }
392 
393 static int imx8qxp_pc_runtime_resume(struct device *dev)
394 {
395 	struct platform_device *pdev = to_platform_device(dev);
396 	struct imx8qxp_pc *pc = platform_get_drvdata(pdev);
397 	int ret;
398 
399 	ret = clk_prepare_enable(pc->clk_apb);
400 	if (ret) {
401 		DRM_DEV_ERROR(pc->dev, "%s: failed to enable apb clock: %d\n",
402 			      __func__, ret);
403 		return ret;
404 	}
405 
406 	/* out of reset */
407 	imx8qxp_pc_write_set(pc, PC_SW_RESET_REG, PC_FULL_RESET_N);
408 
409 	clk_disable_unprepare(pc->clk_apb);
410 
411 	return ret;
412 }
413 
414 static const struct dev_pm_ops imx8qxp_pc_pm_ops = {
415 	RUNTIME_PM_OPS(imx8qxp_pc_runtime_suspend, imx8qxp_pc_runtime_resume, NULL)
416 };
417 
418 static const struct of_device_id imx8qxp_pc_dt_ids[] = {
419 	{ .compatible = "fsl,imx8qm-pixel-combiner", },
420 	{ .compatible = "fsl,imx8qxp-pixel-combiner", },
421 	{ /* sentinel */ }
422 };
423 MODULE_DEVICE_TABLE(of, imx8qxp_pc_dt_ids);
424 
425 static struct platform_driver imx8qxp_pc_bridge_driver = {
426 	.probe	= imx8qxp_pc_bridge_probe,
427 	.remove = imx8qxp_pc_bridge_remove,
428 	.driver	= {
429 		.pm = pm_ptr(&imx8qxp_pc_pm_ops),
430 		.name = DRIVER_NAME,
431 		.of_match_table = imx8qxp_pc_dt_ids,
432 	},
433 };
434 module_platform_driver(imx8qxp_pc_bridge_driver);
435 
436 MODULE_DESCRIPTION("i.MX8QM/QXP pixel combiner bridge driver");
437 MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
438 MODULE_LICENSE("GPL v2");
439 MODULE_ALIAS("platform:" DRIVER_NAME);
440