cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vc4_drv.c (11314B)


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