Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright 2019 NXP.
0004  */
0005 
0006 #include <drm/drm_atomic.h>
0007 #include <drm/drm_atomic_helper.h>
0008 #include <drm/drm_bridge_connector.h>
0009 #include <drm/drm_drv.h>
0010 #include <drm/drm_fb_helper.h>
0011 #include <drm/drm_gem_cma_helper.h>
0012 #include <drm/drm_gem_framebuffer_helper.h>
0013 #include <drm/drm_of.h>
0014 #include <drm/drm_probe_helper.h>
0015 #include <drm/drm_vblank.h>
0016 
0017 #include "dcss-dev.h"
0018 #include "dcss-kms.h"
0019 
0020 DEFINE_DRM_GEM_CMA_FOPS(dcss_cma_fops);
0021 
0022 static const struct drm_mode_config_funcs dcss_drm_mode_config_funcs = {
0023     .fb_create = drm_gem_fb_create,
0024     .output_poll_changed = drm_fb_helper_output_poll_changed,
0025     .atomic_check = drm_atomic_helper_check,
0026     .atomic_commit = drm_atomic_helper_commit,
0027 };
0028 
0029 static const struct drm_driver dcss_kms_driver = {
0030     .driver_features    = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
0031     DRM_GEM_CMA_DRIVER_OPS,
0032     .fops           = &dcss_cma_fops,
0033     .name           = "imx-dcss",
0034     .desc           = "i.MX8MQ Display Subsystem",
0035     .date           = "20190917",
0036     .major          = 1,
0037     .minor          = 0,
0038     .patchlevel     = 0,
0039 };
0040 
0041 static const struct drm_mode_config_helper_funcs dcss_mode_config_helpers = {
0042     .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
0043 };
0044 
0045 static void dcss_kms_mode_config_init(struct dcss_kms_dev *kms)
0046 {
0047     struct drm_mode_config *config = &kms->base.mode_config;
0048 
0049     drm_mode_config_init(&kms->base);
0050 
0051     config->min_width = 1;
0052     config->min_height = 1;
0053     config->max_width = 4096;
0054     config->max_height = 4096;
0055     config->normalize_zpos = true;
0056 
0057     config->funcs = &dcss_drm_mode_config_funcs;
0058     config->helper_private = &dcss_mode_config_helpers;
0059 }
0060 
0061 static const struct drm_encoder_funcs dcss_kms_simple_encoder_funcs = {
0062     .destroy = drm_encoder_cleanup,
0063 };
0064 
0065 static int dcss_kms_bridge_connector_init(struct dcss_kms_dev *kms)
0066 {
0067     struct drm_device *ddev = &kms->base;
0068     struct drm_encoder *encoder = &kms->encoder;
0069     struct drm_crtc *crtc = (struct drm_crtc *)&kms->crtc;
0070     struct drm_panel *panel;
0071     struct drm_bridge *bridge;
0072     int ret;
0073 
0074     ret = drm_of_find_panel_or_bridge(ddev->dev->of_node, 0, 0,
0075                       &panel, &bridge);
0076     if (ret)
0077         return ret;
0078 
0079     if (!bridge) {
0080         dev_err(ddev->dev, "No bridge found %d.\n", ret);
0081         return -ENODEV;
0082     }
0083 
0084     encoder->possible_crtcs = drm_crtc_mask(crtc);
0085 
0086     ret = drm_encoder_init(&kms->base, encoder,
0087                    &dcss_kms_simple_encoder_funcs,
0088                    DRM_MODE_ENCODER_NONE, NULL);
0089     if (ret) {
0090         dev_err(ddev->dev, "Failed initializing encoder %d.\n", ret);
0091         return ret;
0092     }
0093 
0094     ret = drm_bridge_attach(encoder, bridge, NULL,
0095                 DRM_BRIDGE_ATTACH_NO_CONNECTOR);
0096     if (ret < 0)
0097         return ret;
0098 
0099     kms->connector = drm_bridge_connector_init(ddev, encoder);
0100     if (IS_ERR(kms->connector)) {
0101         dev_err(ddev->dev, "Unable to create bridge connector.\n");
0102         return PTR_ERR(kms->connector);
0103     }
0104 
0105     drm_connector_attach_encoder(kms->connector, encoder);
0106 
0107     return 0;
0108 }
0109 
0110 struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss)
0111 {
0112     struct dcss_kms_dev *kms;
0113     struct drm_device *drm;
0114     struct dcss_crtc *crtc;
0115     int ret;
0116 
0117     kms = devm_drm_dev_alloc(dcss->dev, &dcss_kms_driver,
0118                  struct dcss_kms_dev, base);
0119     if (IS_ERR(kms))
0120         return kms;
0121 
0122     drm = &kms->base;
0123     crtc = &kms->crtc;
0124 
0125     drm->dev_private = dcss;
0126 
0127     dcss_kms_mode_config_init(kms);
0128 
0129     ret = drm_vblank_init(drm, 1);
0130     if (ret)
0131         goto cleanup_mode_config;
0132 
0133     ret = dcss_kms_bridge_connector_init(kms);
0134     if (ret)
0135         goto cleanup_mode_config;
0136 
0137     ret = dcss_crtc_init(crtc, drm);
0138     if (ret)
0139         goto cleanup_mode_config;
0140 
0141     drm_mode_config_reset(drm);
0142 
0143     drm_kms_helper_poll_init(drm);
0144 
0145     ret = drm_dev_register(drm, 0);
0146     if (ret)
0147         goto cleanup_crtc;
0148 
0149     drm_fbdev_generic_setup(drm, 32);
0150 
0151     return kms;
0152 
0153 cleanup_crtc:
0154     drm_bridge_connector_disable_hpd(kms->connector);
0155     drm_kms_helper_poll_fini(drm);
0156     dcss_crtc_deinit(crtc, drm);
0157 
0158 cleanup_mode_config:
0159     drm_mode_config_cleanup(drm);
0160     drm->dev_private = NULL;
0161 
0162     return ERR_PTR(ret);
0163 }
0164 
0165 void dcss_kms_detach(struct dcss_kms_dev *kms)
0166 {
0167     struct drm_device *drm = &kms->base;
0168 
0169     drm_dev_unregister(drm);
0170     drm_bridge_connector_disable_hpd(kms->connector);
0171     drm_kms_helper_poll_fini(drm);
0172     drm_atomic_helper_shutdown(drm);
0173     drm_crtc_vblank_off(&kms->crtc.base);
0174     drm_mode_config_cleanup(drm);
0175     dcss_crtc_deinit(&kms->crtc, drm);
0176     drm->dev_private = NULL;
0177 }