diff options
Diffstat (limited to 'drivers/gpu/drm/vc4/vc4_drv.c')
| -rw-r--r-- | drivers/gpu/drm/vc4/vc4_drv.c | 230 |
1 files changed, 184 insertions, 46 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 16abc3a3d601..3846996f9028 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -20,23 +20,27 @@ * driver. */ +#include <linux/aperture.h> #include <linux/clk.h> #include <linux/component.h> #include <linux/device.h> #include <linux/dma-mapping.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/of_platform.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <drm/drm_aperture.h> +#include <drm/clients/drm_client_setup.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_drv.h> -#include <drm/drm_fb_cma_helper.h> -#include <drm/drm_fb_helper.h> +#include <drm/drm_fbdev_dma.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_print.h> #include <drm/drm_vblank.h> +#include <soc/bcm2835/raspberrypi-firmware.h> + #include "uapi/drm/vc4_drm.h" #include "vc4_drv.h" @@ -44,7 +48,6 @@ #define DRIVER_NAME "vc4" #define DRIVER_DESC "Broadcom VC4 graphics" -#define DRIVER_DATE "20140616" #define DRIVER_MAJOR 0 #define DRIVER_MINOR 0 #define DRIVER_PATCHLEVEL 0 @@ -61,6 +64,32 @@ void __iomem *vc4_ioremap_regs(struct platform_device *pdev, int index) return map; } +int vc4_dumb_fixup_args(struct drm_mode_create_dumb *args) +{ + int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); + + if (args->pitch < min_pitch) + args->pitch = min_pitch; + + if (args->size < args->pitch * args->height) + args->size = args->pitch * args->height; + + return 0; +} + +static int vc5_dumb_create(struct drm_file *file_priv, + struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + int ret; + + ret = vc4_dumb_fixup_args(args); + if (ret) + return ret; + + return drm_gem_dma_dumb_create_internal(file_priv, dev, args); +} + static int vc4_get_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -71,6 +100,9 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data, if (args->pad != 0) return -EINVAL; + if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + if (!vc4->v3d) return -ENODEV; @@ -114,11 +146,16 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data, static int vc4_open(struct drm_device *dev, struct drm_file *file) { + struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_file *vc4file; + if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return -ENODEV; + vc4file = kzalloc(sizeof(*vc4file), GFP_KERNEL); if (!vc4file) return -ENOMEM; + vc4file->dev = vc4; vc4_perfmon_open_file(vc4file); file->driver_priv = vc4file; @@ -130,6 +167,9 @@ static void vc4_close(struct drm_device *dev, struct drm_file *file) struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_file *vc4file = file->driver_priv; + if (WARN_ON_ONCE(vc4->gen > VC4_GEN_4)) + return; + if (vc4file->bin_bo_used) vc4_v3d_bin_bo_put(vc4); @@ -158,7 +198,7 @@ static const struct drm_ioctl_desc vc4_drm_ioctls[] = { DRM_IOCTL_DEF_DRV(VC4_PERFMON_GET_VALUES, vc4_perfmon_get_values_ioctl, DRM_RENDER_ALLOW), }; -static struct drm_driver vc4_drm_driver = { +const struct drm_driver vc4_drm_driver = { .driver_features = (DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM | @@ -173,7 +213,8 @@ static struct drm_driver vc4_drm_driver = { .gem_create_object = vc4_create_object, - DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(vc4_dumb_create), + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(vc4_bo_dumb_create), + DRM_FBDEV_DMA_DRIVER_OPS, .ioctls = vc4_drm_ioctls, .num_ioctls = ARRAY_SIZE(vc4_drm_ioctls), @@ -181,16 +222,31 @@ static struct drm_driver vc4_drm_driver = { .name = DRIVER_NAME, .desc = DRIVER_DESC, - .date = DRIVER_DATE, .major = DRIVER_MAJOR, .minor = DRIVER_MINOR, .patchlevel = DRIVER_PATCHLEVEL, }; -static int compare_dev(struct device *dev, void *data) -{ - return dev == data; -} +const struct drm_driver vc5_drm_driver = { + .driver_features = (DRIVER_MODESET | + DRIVER_ATOMIC | + DRIVER_GEM), + +#if defined(CONFIG_DEBUG_FS) + .debugfs_init = vc4_debugfs_init, +#endif + + DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(vc5_dumb_create), + DRM_FBDEV_DMA_DRIVER_OPS, + + .fops = &vc4_drm_fops, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, +}; static void vc4_match_add_drivers(struct device *dev, struct component_match **match, @@ -205,82 +261,149 @@ static void vc4_match_add_drivers(struct device *dev, while ((d = platform_find_device_by_driver(p, drv))) { put_device(p); - component_match_add(dev, match, compare_dev, d); + component_match_add(dev, match, component_compare_dev, d); p = d; } put_device(p); } } +static void vc4_component_unbind_all(void *ptr) +{ + struct vc4_dev *vc4 = ptr; + + component_unbind_all(vc4->dev, &vc4->base); +} + +static const struct of_device_id vc4_dma_range_matches[] = { + { .compatible = "brcm,bcm2711-hvs" }, + { .compatible = "brcm,bcm2712-hvs" }, + { .compatible = "brcm,bcm2835-hvs" }, + { .compatible = "brcm,bcm2835-v3d" }, + { .compatible = "brcm,cygnus-v3d" }, + { .compatible = "brcm,vc4-v3d" }, + {} +}; + static int vc4_drm_bind(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); + const struct drm_driver *driver; + struct rpi_firmware *firmware = NULL; struct drm_device *drm; struct vc4_dev *vc4; struct device_node *node; struct drm_crtc *crtc; + enum vc4_gen gen; int ret = 0; dev->coherent_dma_mask = DMA_BIT_MASK(32); - /* If VC4 V3D is missing, don't advertise render nodes. */ - node = of_find_matching_node_and_match(NULL, vc4_v3d_dt_match, NULL); - if (!node || !of_device_is_available(node)) - vc4_drm_driver.driver_features &= ~DRIVER_RENDER; - of_node_put(node); + gen = (enum vc4_gen)of_device_get_match_data(dev); + + if (gen > VC4_GEN_4) + driver = &vc5_drm_driver; + else + driver = &vc4_drm_driver; + + if (gen >= VC4_GEN_6_C) + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36)); + else + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + + node = of_find_matching_node_and_match(NULL, vc4_dma_range_matches, + NULL); + if (node) { + ret = of_dma_configure(dev, node, true); + of_node_put(node); + + if (ret) + return ret; + } - vc4 = devm_drm_dev_alloc(dev, &vc4_drm_driver, struct vc4_dev, base); + vc4 = devm_drm_dev_alloc(dev, driver, struct vc4_dev, base); if (IS_ERR(vc4)) return PTR_ERR(vc4); + vc4->gen = gen; + vc4->dev = dev; drm = &vc4->base; platform_set_drvdata(pdev, drm); - INIT_LIST_HEAD(&vc4->debugfs_list); - mutex_init(&vc4->bin_bo_lock); + if (gen == VC4_GEN_4) { + ret = drmm_mutex_init(drm, &vc4->bin_bo_lock); + if (ret) + goto err; - ret = vc4_bo_cache_init(drm); - if (ret) - return ret; + ret = vc4_bo_cache_init(drm); + if (ret) + goto err; + } ret = drmm_mode_config_init(drm); if (ret) - return ret; + goto err; + + if (gen == VC4_GEN_4) { + ret = vc4_gem_init(drm); + if (ret) + goto err; + } + + node = of_find_compatible_node(NULL, NULL, "raspberrypi,bcm2835-firmware"); + if (node) { + firmware = rpi_firmware_get(node); + of_node_put(node); - ret = vc4_gem_init(drm); + if (!firmware) { + ret = -EPROBE_DEFER; + goto err; + } + } + + ret = aperture_remove_all_conflicting_devices(driver->name); if (ret) - return ret; + goto err; + + if (firmware) { + ret = rpi_firmware_property(firmware, + RPI_FIRMWARE_NOTIFY_DISPLAY_DONE, + NULL, 0); + if (ret) + drm_warn(drm, "Couldn't stop firmware display driver: %d\n", ret); + + rpi_firmware_put(firmware); + } ret = component_bind_all(dev, drm); if (ret) - return ret; + goto err; - ret = vc4_plane_create_additional_planes(drm); + ret = devm_add_action_or_reset(dev, vc4_component_unbind_all, vc4); if (ret) - goto unbind_all; + goto err; - ret = drm_aperture_remove_framebuffers(false, &vc4_drm_driver); + ret = vc4_plane_create_additional_planes(drm); if (ret) - goto unbind_all; + goto err; ret = vc4_kms_load(drm); if (ret < 0) - goto unbind_all; + goto err; drm_for_each_crtc(crtc, drm) vc4_crtc_disable_at_boot(crtc); ret = drm_dev_register(drm, 0); if (ret < 0) - goto unbind_all; + goto err; - drm_fbdev_generic_setup(drm, 16); + drm_client_setup_with_fourcc(drm, DRM_FORMAT_RGB565); return 0; -unbind_all: - component_unbind_all(dev, drm); - +err: + platform_set_drvdata(pdev, NULL); return ret; } @@ -288,9 +411,9 @@ static void vc4_drm_unbind(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); - drm_dev_unregister(drm); - + drm_dev_unplug(drm); drm_atomic_helper_shutdown(drm); + dev_set_drvdata(dev, NULL); } static const struct component_master_ops vc4_drm_ops = { @@ -329,17 +452,22 @@ static int vc4_platform_drm_probe(struct platform_device *pdev) return component_master_add_with_match(dev, &vc4_drm_ops, match); } -static int vc4_platform_drm_remove(struct platform_device *pdev) +static void vc4_platform_drm_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &vc4_drm_ops); +} - return 0; +static void vc4_platform_drm_shutdown(struct platform_device *pdev) +{ + drm_atomic_helper_shutdown(platform_get_drvdata(pdev)); } static const struct of_device_id vc4_of_match[] = { - { .compatible = "brcm,bcm2711-vc5", }, - { .compatible = "brcm,bcm2835-vc4", }, - { .compatible = "brcm,cygnus-vc4", }, + { .compatible = "brcm,bcm2711-vc5", .data = (void *)VC4_GEN_5 }, + /* NB GEN_6_C will be corrected on D0 hw to GEN_6_D via vc4_hvs_bind */ + { .compatible = "brcm,bcm2712-vc6", .data = (void *)VC4_GEN_6_C }, + { .compatible = "brcm,bcm2835-vc4", .data = (void *)VC4_GEN_4 }, + { .compatible = "brcm,cygnus-vc4", .data = (void *)VC4_GEN_4 }, {}, }; MODULE_DEVICE_TABLE(of, vc4_of_match); @@ -347,6 +475,7 @@ MODULE_DEVICE_TABLE(of, vc4_of_match); static struct platform_driver vc4_platform_driver = { .probe = vc4_platform_drm_probe, .remove = vc4_platform_drm_remove, + .shutdown = vc4_platform_drm_shutdown, .driver = { .name = "vc4-drm", .of_match_table = vc4_of_match, @@ -357,12 +486,20 @@ static int __init vc4_drm_register(void) { int ret; + if (drm_firmware_drivers_only()) + return -ENODEV; + ret = platform_register_drivers(component_drivers, ARRAY_SIZE(component_drivers)); if (ret) return ret; - return platform_driver_register(&vc4_platform_driver); + ret = platform_driver_register(&vc4_platform_driver); + if (ret) + platform_unregister_drivers(component_drivers, + ARRAY_SIZE(component_drivers)); + + return ret; } static void __exit vc4_drm_unregister(void) @@ -376,6 +513,7 @@ module_init(vc4_drm_register); module_exit(vc4_drm_unregister); MODULE_ALIAS("platform:vc4-drm"); +MODULE_SOFTDEP("pre: snd-soc-hdmi-codec"); MODULE_DESCRIPTION("Broadcom VC4 DRM Driver"); MODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); MODULE_LICENSE("GPL v2"); |
