0001
0002
0003
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 }