diff options
author | Laurentiu Palcu <laurentiu.palcu@nxp.com> | 2020-07-31 11:18:30 +0300 |
---|---|---|
committer | Lucas Stach <l.stach@pengutronix.de> | 2020-09-09 16:39:48 +0200 |
commit | 9021c317b77024fb2642af7e84ad944769ae0949 (patch) | |
tree | 33cad18bdbf967a5ee7f503790a8cac014bb1ea1 /drivers/gpu/drm/imx/dcss/dcss-kms.c | |
parent | ce625f45670c90241e06d406cd1b0dbd19ed1044 (diff) | |
download | linux-9021c317b77024fb2642af7e84ad944769ae0949.tar.gz |
drm/imx: Add initial support for DCSS on iMX8MQ
This adds initial support for iMX8MQ's Display Controller Subsystem (DCSS).
Some of its capabilities include:
* 4K@60fps;
* HDR10;
* one graphics and 2 video pipelines;
* on-the-fly decompression of compressed video and graphics;
The reference manual can be found here:
https://www.nxp.com/webapp/Download?colCode=IMX8MDQLQRM
The current patch adds only basic functionality: one primary plane for
graphics, linear, tiled and super-tiled buffers support (no graphics
decompression yet), no HDR10 and no video planes.
Video planes support and HDR10 will be added in subsequent patches once
per-plane de-gamma/CSC/gamma support is in.
Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
Reviewed-by: Lucas Stach <l.stach@pengutronix.de>
Acked-by: Guido Günther <agx@sigxcpu.org>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20200731081836.3048-3-laurentiu.palcu@oss.nxp.com
Diffstat (limited to 'drivers/gpu/drm/imx/dcss/dcss-kms.c')
-rw-r--r-- | drivers/gpu/drm/imx/dcss/dcss-kms.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c new file mode 100644 index 000000000000..3ca49d0a3e61 --- /dev/null +++ b/drivers/gpu/drm/imx/dcss/dcss-kms.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 NXP. + */ + +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_drv.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_of.h> +#include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> + +#include "dcss-dev.h" +#include "dcss-kms.h" + +DEFINE_DRM_GEM_CMA_FOPS(dcss_cma_fops); + +static const struct drm_mode_config_funcs dcss_drm_mode_config_funcs = { + .fb_create = drm_gem_fb_create, + .output_poll_changed = drm_fb_helper_output_poll_changed, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static struct drm_driver dcss_kms_driver = { + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, + .gem_free_object_unlocked = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + .dumb_create = drm_gem_cma_dumb_create, + + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, + .fops = &dcss_cma_fops, + .name = "imx-dcss", + .desc = "i.MX8MQ Display Subsystem", + .date = "20190917", + .major = 1, + .minor = 0, + .patchlevel = 0, +}; + +static const struct drm_mode_config_helper_funcs dcss_mode_config_helpers = { + .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, +}; + +static void dcss_kms_mode_config_init(struct dcss_kms_dev *kms) +{ + struct drm_mode_config *config = &kms->base.mode_config; + + drm_mode_config_init(&kms->base); + + config->min_width = 1; + config->min_height = 1; + config->max_width = 4096; + config->max_height = 4096; + config->allow_fb_modifiers = true; + config->normalize_zpos = true; + + config->funcs = &dcss_drm_mode_config_funcs; + config->helper_private = &dcss_mode_config_helpers; +} + +static const struct drm_encoder_funcs dcss_kms_simple_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static int dcss_kms_setup_encoder(struct dcss_kms_dev *kms) +{ + struct drm_device *ddev = &kms->base; + struct drm_encoder *encoder = &kms->encoder; + struct drm_crtc *crtc = (struct drm_crtc *)&kms->crtc; + struct drm_panel *panel; + struct drm_bridge *bridge; + int ret; + + ret = drm_of_find_panel_or_bridge(ddev->dev->of_node, 0, 0, + &panel, &bridge); + if (ret) + return ret; + + if (!bridge) { + dev_err(ddev->dev, "No bridge found %d.\n", ret); + return -ENODEV; + } + + encoder->possible_crtcs = drm_crtc_mask(crtc); + + ret = drm_encoder_init(&kms->base, encoder, + &dcss_kms_simple_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) { + dev_err(ddev->dev, "Failed initializing encoder %d.\n", ret); + return ret; + } + + return drm_bridge_attach(encoder, bridge, NULL, 0); +} + +struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss) +{ + struct dcss_kms_dev *kms; + struct drm_device *drm; + struct dcss_crtc *crtc; + int ret; + + kms = devm_drm_dev_alloc(dcss->dev, &dcss_kms_driver, + struct dcss_kms_dev, base); + if (IS_ERR(kms)) + return kms; + + drm = &kms->base; + crtc = &kms->crtc; + + drm->dev_private = dcss; + + dcss_kms_mode_config_init(kms); + + ret = drm_vblank_init(drm, 1); + if (ret) + goto cleanup_mode_config; + + drm->irq_enabled = true; + + ret = dcss_crtc_init(crtc, drm); + if (ret) + goto cleanup_mode_config; + + ret = dcss_kms_setup_encoder(kms); + if (ret) + goto cleanup_crtc; + + drm_mode_config_reset(drm); + + drm_kms_helper_poll_init(drm); + + ret = drm_dev_register(drm, 0); + if (ret) + goto cleanup_crtc; + + drm_fbdev_generic_setup(drm, 32); + + return kms; + +cleanup_crtc: + drm_kms_helper_poll_fini(drm); + dcss_crtc_deinit(crtc, drm); + +cleanup_mode_config: + drm_mode_config_cleanup(drm); + drm->dev_private = NULL; + + return ERR_PTR(ret); +} + +void dcss_kms_detach(struct dcss_kms_dev *kms) +{ + struct drm_device *drm = &kms->base; + + drm_dev_unregister(drm); + drm_kms_helper_poll_fini(drm); + drm_atomic_helper_shutdown(drm); + drm_crtc_vblank_off(&kms->crtc.base); + drm->irq_enabled = false; + drm_mode_config_cleanup(drm); + dcss_crtc_deinit(&kms->crtc, drm); + drm->dev_private = NULL; +} |