xref: /linux/drivers/gpu/drm/vc4/vc4_drv.c (revision 5b0764a53235d3c77e1ed674e836e1b3fe1a4b1f)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2014-2015 Broadcom
4  * Copyright (C) 2013 Red Hat
5  */
6 
7 /**
8  * DOC: Broadcom VC4 Graphics Driver
9  *
10  * The Broadcom VideoCore 4 (present in the Raspberry Pi) contains a
11  * OpenGL ES 2.0-compatible 3D engine called V3D, and a highly
12  * configurable display output pipeline that supports HDMI, DSI, DPI,
13  * and Composite TV output.
14  *
15  * The 3D engine also has an interface for submitting arbitrary
16  * compute shader-style jobs using the same shader processor as is
17  * used for vertex and fragment shaders in GLES 2.0.  However, given
18  * that the hardware isn't able to expose any standard interfaces like
19  * OpenGL compute shaders or OpenCL, it isn't supported by this
20  * driver.
21  */
22 
23 #include <linux/aperture.h>
24 #include <linux/clk.h>
25 #include <linux/component.h>
26 #include <linux/device.h>
27 #include <linux/io.h>
28 #include <linux/module.h>
29 #include <linux/platform_device.h>
30 #include <linux/pm_runtime.h>
31 
32 #include <drm/clients/drm_client_setup.h>
33 #include <drm/drm_atomic_helper.h>
34 #include <drm/drm_drv.h>
35 #include <drm/drm_fbdev_dma.h>
36 #include <drm/drm_fourcc.h>
37 #include <drm/drm_print.h>
38 #include <drm/drm_vblank.h>
39 
40 #include <soc/bcm2835/raspberrypi-firmware.h>
41 
42 #include "vc4_drv.h"
43 #include "vc4_regs.h"
44 
45 #define DRIVER_NAME "vc4"
46 #define DRIVER_DESC "Broadcom VC4 graphics"
47 #define DRIVER_MAJOR 0
48 #define DRIVER_MINOR 0
49 #define DRIVER_PATCHLEVEL 0
50 
51 /* Helper function for mapping the regs on a platform device. */
52 void __iomem *vc4_ioremap_regs(struct platform_device *pdev, int index)
53 {
54 	void __iomem *map;
55 
56 	map = devm_platform_ioremap_resource(pdev, index);
57 	if (IS_ERR(map))
58 		return map;
59 
60 	return map;
61 }
62 
63 int vc4_dumb_fixup_args(struct drm_mode_create_dumb *args)
64 {
65 	int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
66 
67 	if (args->pitch < min_pitch)
68 		args->pitch = min_pitch;
69 
70 	if (args->size < args->pitch * args->height)
71 		args->size = args->pitch * args->height;
72 
73 	return 0;
74 }
75 
76 static int vc5_dumb_create(struct drm_file *file_priv,
77 			   struct drm_device *dev,
78 			   struct drm_mode_create_dumb *args)
79 {
80 	int ret;
81 
82 	ret = vc4_dumb_fixup_args(args);
83 	if (ret)
84 		return ret;
85 
86 	return drm_gem_dma_dumb_create_internal(file_priv, dev, args);
87 }
88 
89 static int vc4_get_param_ioctl(struct drm_device *dev, void *data,
90 			       struct drm_file *file_priv)
91 {
92 	struct vc4_dev *vc4 = to_vc4_dev(dev);
93 	struct drm_vc4_get_param *args = data;
94 	int ret;
95 
96 	if (args->pad != 0)
97 		return -EINVAL;
98 
99 	if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
100 		return -ENODEV;
101 
102 	if (!vc4->v3d)
103 		return -ENODEV;
104 
105 	switch (args->param) {
106 	case DRM_VC4_PARAM_V3D_IDENT0:
107 		ret = vc4_v3d_pm_get(vc4);
108 		if (ret)
109 			return ret;
110 		args->value = V3D_READ(V3D_IDENT0);
111 		vc4_v3d_pm_put(vc4);
112 		break;
113 	case DRM_VC4_PARAM_V3D_IDENT1:
114 		ret = vc4_v3d_pm_get(vc4);
115 		if (ret)
116 			return ret;
117 		args->value = V3D_READ(V3D_IDENT1);
118 		vc4_v3d_pm_put(vc4);
119 		break;
120 	case DRM_VC4_PARAM_V3D_IDENT2:
121 		ret = vc4_v3d_pm_get(vc4);
122 		if (ret)
123 			return ret;
124 		args->value = V3D_READ(V3D_IDENT2);
125 		vc4_v3d_pm_put(vc4);
126 		break;
127 	case DRM_VC4_PARAM_SUPPORTS_BRANCHES:
128 	case DRM_VC4_PARAM_SUPPORTS_ETC1:
129 	case DRM_VC4_PARAM_SUPPORTS_THREADED_FS:
130 	case DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER:
131 	case DRM_VC4_PARAM_SUPPORTS_MADVISE:
132 	case DRM_VC4_PARAM_SUPPORTS_PERFMON:
133 		args->value = true;
134 		break;
135 	default:
136 		DRM_DEBUG("Unknown parameter %d\n", args->param);
137 		return -EINVAL;
138 	}
139 
140 	return 0;
141 }
142 
143 static int vc4_open(struct drm_device *dev, struct drm_file *file)
144 {
145 	struct vc4_dev *vc4 = to_vc4_dev(dev);
146 	struct vc4_file *vc4file;
147 
148 	if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
149 		return -ENODEV;
150 
151 	vc4file = kzalloc_obj(*vc4file);
152 	if (!vc4file)
153 		return -ENOMEM;
154 	vc4file->dev = vc4;
155 
156 	vc4_perfmon_open_file(vc4file);
157 	file->driver_priv = vc4file;
158 	return 0;
159 }
160 
161 static void vc4_close(struct drm_device *dev, struct drm_file *file)
162 {
163 	struct vc4_dev *vc4 = to_vc4_dev(dev);
164 	struct vc4_file *vc4file = file->driver_priv;
165 
166 	if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4))
167 		return;
168 
169 	if (vc4file->bin_bo_used)
170 		vc4_v3d_bin_bo_put(vc4);
171 
172 	vc4_perfmon_close_file(vc4file);
173 	kfree(vc4file);
174 }
175 
176 DEFINE_DRM_GEM_FOPS(vc4_drm_fops);
177 
178 static const struct drm_ioctl_desc vc4_drm_ioctls[] = {
179 	DRM_IOCTL_DEF_DRV(VC4_SUBMIT_CL, vc4_submit_cl_ioctl, DRM_RENDER_ALLOW),
180 	DRM_IOCTL_DEF_DRV(VC4_WAIT_SEQNO, vc4_wait_seqno_ioctl, DRM_RENDER_ALLOW),
181 	DRM_IOCTL_DEF_DRV(VC4_WAIT_BO, vc4_wait_bo_ioctl, DRM_RENDER_ALLOW),
182 	DRM_IOCTL_DEF_DRV(VC4_CREATE_BO, vc4_create_bo_ioctl, DRM_RENDER_ALLOW),
183 	DRM_IOCTL_DEF_DRV(VC4_MMAP_BO, vc4_mmap_bo_ioctl, DRM_RENDER_ALLOW),
184 	DRM_IOCTL_DEF_DRV(VC4_CREATE_SHADER_BO, vc4_create_shader_bo_ioctl, DRM_RENDER_ALLOW),
185 	DRM_IOCTL_DEF_DRV(VC4_GET_HANG_STATE, vc4_get_hang_state_ioctl,
186 			  DRM_ROOT_ONLY),
187 	DRM_IOCTL_DEF_DRV(VC4_GET_PARAM, vc4_get_param_ioctl, DRM_RENDER_ALLOW),
188 	DRM_IOCTL_DEF_DRV(VC4_SET_TILING, vc4_set_tiling_ioctl, DRM_RENDER_ALLOW),
189 	DRM_IOCTL_DEF_DRV(VC4_GET_TILING, vc4_get_tiling_ioctl, DRM_RENDER_ALLOW),
190 	DRM_IOCTL_DEF_DRV(VC4_LABEL_BO, vc4_label_bo_ioctl, DRM_RENDER_ALLOW),
191 	DRM_IOCTL_DEF_DRV(VC4_GEM_MADVISE, vc4_gem_madvise_ioctl, DRM_RENDER_ALLOW),
192 	DRM_IOCTL_DEF_DRV(VC4_PERFMON_CREATE, vc4_perfmon_create_ioctl, DRM_RENDER_ALLOW),
193 	DRM_IOCTL_DEF_DRV(VC4_PERFMON_DESTROY, vc4_perfmon_destroy_ioctl, DRM_RENDER_ALLOW),
194 	DRM_IOCTL_DEF_DRV(VC4_PERFMON_GET_VALUES, vc4_perfmon_get_values_ioctl, DRM_RENDER_ALLOW),
195 };
196 
197 const struct drm_driver vc4_drm_driver = {
198 	.driver_features = (DRIVER_MODESET |
199 			    DRIVER_ATOMIC |
200 			    DRIVER_GEM |
201 			    DRIVER_RENDER |
202 			    DRIVER_SYNCOBJ),
203 	.open = vc4_open,
204 	.postclose = vc4_close,
205 
206 #if defined(CONFIG_DEBUG_FS)
207 	.debugfs_init = vc4_debugfs_init,
208 #endif
209 
210 	.gem_create_object = vc4_create_object,
211 
212 	DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(vc4_bo_dumb_create),
213 	DRM_FBDEV_DMA_DRIVER_OPS,
214 
215 	.ioctls = vc4_drm_ioctls,
216 	.num_ioctls = ARRAY_SIZE(vc4_drm_ioctls),
217 	.fops = &vc4_drm_fops,
218 
219 	.name = DRIVER_NAME,
220 	.desc = DRIVER_DESC,
221 	.major = DRIVER_MAJOR,
222 	.minor = DRIVER_MINOR,
223 	.patchlevel = DRIVER_PATCHLEVEL,
224 };
225 
226 const struct drm_driver vc5_drm_driver = {
227 	.driver_features = (DRIVER_MODESET |
228 			    DRIVER_ATOMIC |
229 			    DRIVER_GEM),
230 
231 #if defined(CONFIG_DEBUG_FS)
232 	.debugfs_init = vc4_debugfs_init,
233 #endif
234 
235 	DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(vc5_dumb_create),
236 	DRM_FBDEV_DMA_DRIVER_OPS,
237 
238 	.fops = &vc4_drm_fops,
239 
240 	.name = DRIVER_NAME,
241 	.desc = DRIVER_DESC,
242 	.major = DRIVER_MAJOR,
243 	.minor = DRIVER_MINOR,
244 	.patchlevel = DRIVER_PATCHLEVEL,
245 };
246 
247 static void vc4_match_add_drivers(struct device *dev,
248 				  struct component_match **match,
249 				  struct platform_driver *const *drivers,
250 				  int count)
251 {
252 	int i;
253 
254 	for (i = 0; i < count; i++) {
255 		struct device_driver *drv = &drivers[i]->driver;
256 		struct device *p = NULL, *d;
257 
258 		while ((d = platform_find_device_by_driver(p, drv))) {
259 			put_device(p);
260 			component_match_add(dev, match, component_compare_dev, d);
261 			p = d;
262 		}
263 		put_device(p);
264 	}
265 }
266 
267 static void vc4_component_unbind_all(void *ptr)
268 {
269 	struct vc4_dev *vc4 = ptr;
270 
271 	component_unbind_all(vc4->dev, &vc4->base);
272 }
273 
274 static int vc4_drm_bind(struct device *dev)
275 {
276 	struct platform_device *pdev = to_platform_device(dev);
277 	const struct drm_driver *driver;
278 	struct rpi_firmware *firmware = NULL;
279 	struct drm_device *drm;
280 	struct vc4_dev *vc4;
281 	struct device_node *node;
282 	struct drm_crtc *crtc;
283 	enum vc4_gen gen;
284 	int ret = 0;
285 
286 	gen = (enum vc4_gen)of_device_get_match_data(dev);
287 
288 	if (gen > VC4_GEN_4)
289 		driver = &vc5_drm_driver;
290 	else
291 		driver = &vc4_drm_driver;
292 
293 	vc4 = devm_drm_dev_alloc(dev, driver, struct vc4_dev, base);
294 	if (IS_ERR(vc4))
295 		return PTR_ERR(vc4);
296 	vc4->gen = gen;
297 	vc4->dev = dev;
298 
299 	drm = &vc4->base;
300 	platform_set_drvdata(pdev, drm);
301 
302 	if (gen == VC4_GEN_4) {
303 		ret = drmm_mutex_init(drm, &vc4->bin_bo_lock);
304 		if (ret)
305 			goto err;
306 
307 		ret = vc4_bo_cache_init(drm);
308 		if (ret)
309 			goto err;
310 	}
311 
312 	ret = drmm_mode_config_init(drm);
313 	if (ret)
314 		goto err;
315 
316 	if (gen == VC4_GEN_4) {
317 		ret = vc4_gem_init(drm);
318 		if (ret)
319 			goto err;
320 	}
321 
322 	node = of_find_compatible_node(NULL, NULL, "raspberrypi,bcm2835-firmware");
323 	if (node) {
324 		firmware = rpi_firmware_get(node);
325 		of_node_put(node);
326 
327 		if (!firmware) {
328 			ret = -EPROBE_DEFER;
329 			goto err;
330 		}
331 	}
332 
333 	ret = aperture_remove_all_conflicting_devices(driver->name);
334 	if (ret) {
335 		if (firmware)
336 			rpi_firmware_put(firmware);
337 		goto err;
338 	}
339 
340 	if (firmware) {
341 		ret = rpi_firmware_property(firmware,
342 					    RPI_FIRMWARE_NOTIFY_DISPLAY_DONE,
343 					    NULL, 0);
344 		if (ret)
345 			drm_warn(drm, "Couldn't stop firmware display driver: %d\n", ret);
346 
347 		rpi_firmware_put(firmware);
348 	}
349 
350 	ret = component_bind_all(dev, drm);
351 	if (ret)
352 		goto err;
353 
354 	ret = devm_add_action_or_reset(dev, vc4_component_unbind_all, vc4);
355 	if (ret)
356 		goto err;
357 
358 	ret = vc4_plane_create_additional_planes(drm);
359 	if (ret)
360 		goto err;
361 
362 	ret = vc4_kms_load(drm);
363 	if (ret < 0)
364 		goto err;
365 
366 	drm_for_each_crtc(crtc, drm)
367 		vc4_crtc_disable_at_boot(crtc);
368 
369 	ret = drm_dev_register(drm, 0);
370 	if (ret < 0)
371 		goto err;
372 
373 	drm_client_setup_with_fourcc(drm, DRM_FORMAT_RGB565);
374 
375 	return 0;
376 
377 err:
378 	platform_set_drvdata(pdev, NULL);
379 	return ret;
380 }
381 
382 static void vc4_drm_unbind(struct device *dev)
383 {
384 	struct drm_device *drm = dev_get_drvdata(dev);
385 
386 	drm_dev_unplug(drm);
387 	drm_atomic_helper_shutdown(drm);
388 	dev_set_drvdata(dev, NULL);
389 }
390 
391 static const struct component_master_ops vc4_drm_ops = {
392 	.bind = vc4_drm_bind,
393 	.unbind = vc4_drm_unbind,
394 };
395 
396 /*
397  * This list determines the binding order of our components, and we have
398  * a few constraints:
399  *   - The TXP driver needs to be bound before the PixelValves (CRTC)
400  *     but after the HVS to set the possible_crtc field properly
401  *   - The HDMI driver needs to be bound after the HVS so that we can
402  *     lookup the HVS maximum core clock rate and figure out if we
403  *     support 4kp60 or not.
404  */
405 static struct platform_driver *const component_drivers[] = {
406 	&vc4_hvs_driver,
407 	&vc4_hdmi_driver,
408 	&vc4_vec_driver,
409 	&vc4_dpi_driver,
410 	&vc4_dsi_driver,
411 	&vc4_txp_driver,
412 	&vc4_crtc_driver,
413 	&vc4_v3d_driver,
414 };
415 
416 static int vc4_platform_drm_probe(struct platform_device *pdev)
417 {
418 	struct component_match *match = NULL;
419 	struct device *dev = &pdev->dev;
420 
421 	vc4_match_add_drivers(dev, &match,
422 			      component_drivers, ARRAY_SIZE(component_drivers));
423 
424 	return component_master_add_with_match(dev, &vc4_drm_ops, match);
425 }
426 
427 static void vc4_platform_drm_remove(struct platform_device *pdev)
428 {
429 	component_master_del(&pdev->dev, &vc4_drm_ops);
430 }
431 
432 static void vc4_platform_drm_shutdown(struct platform_device *pdev)
433 {
434 	drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
435 }
436 
437 static const struct of_device_id vc4_of_match[] = {
438 	{ .compatible = "brcm,bcm2711-vc5", .data = (void *)VC4_GEN_5 },
439 	/* NB GEN_6_C will be corrected on D0 hw to GEN_6_D via vc4_hvs_bind */
440 	{ .compatible = "brcm,bcm2712-vc6", .data = (void *)VC4_GEN_6_C },
441 	{ .compatible = "brcm,bcm2835-vc4", .data = (void *)VC4_GEN_4 },
442 	{ .compatible = "brcm,cygnus-vc4", .data = (void *)VC4_GEN_4 },
443 	{},
444 };
445 MODULE_DEVICE_TABLE(of, vc4_of_match);
446 
447 static struct platform_driver vc4_platform_driver = {
448 	.probe		= vc4_platform_drm_probe,
449 	.remove		= vc4_platform_drm_remove,
450 	.shutdown	= vc4_platform_drm_shutdown,
451 	.driver		= {
452 		.name	= "vc4-drm",
453 		.of_match_table = vc4_of_match,
454 	},
455 };
456 
457 static int __init vc4_drm_register(void)
458 {
459 	int ret;
460 
461 	if (drm_firmware_drivers_only())
462 		return -ENODEV;
463 
464 	ret = platform_register_drivers(component_drivers,
465 					ARRAY_SIZE(component_drivers));
466 	if (ret)
467 		return ret;
468 
469 	ret = platform_driver_register(&vc4_platform_driver);
470 	if (ret)
471 		platform_unregister_drivers(component_drivers,
472 					    ARRAY_SIZE(component_drivers));
473 
474 	return ret;
475 }
476 
477 static void __exit vc4_drm_unregister(void)
478 {
479 	platform_unregister_drivers(component_drivers,
480 				    ARRAY_SIZE(component_drivers));
481 	platform_driver_unregister(&vc4_platform_driver);
482 }
483 
484 module_init(vc4_drm_register);
485 module_exit(vc4_drm_unregister);
486 
487 MODULE_ALIAS("platform:vc4-drm");
488 MODULE_SOFTDEP("pre: snd-soc-hdmi-codec");
489 MODULE_DESCRIPTION("Broadcom VC4 DRM Driver");
490 MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
491 MODULE_LICENSE("GPL v2");
492