Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2020 Unisoc Inc.
0004  */
0005 
0006 #include <linux/component.h>
0007 #include <linux/dma-mapping.h>
0008 #include <linux/module.h>
0009 #include <linux/mutex.h>
0010 #include <linux/of_graph.h>
0011 #include <linux/of_platform.h>
0012 
0013 #include <drm/drm_atomic_helper.h>
0014 #include <drm/drm_crtc_helper.h>
0015 #include <drm/drm_drv.h>
0016 #include <drm/drm_gem_cma_helper.h>
0017 #include <drm/drm_gem_framebuffer_helper.h>
0018 #include <drm/drm_of.h>
0019 #include <drm/drm_probe_helper.h>
0020 #include <drm/drm_vblank.h>
0021 
0022 #include "sprd_drm.h"
0023 
0024 #define DRIVER_NAME "sprd"
0025 #define DRIVER_DESC "Spreadtrum SoCs' DRM Driver"
0026 #define DRIVER_DATE "20200201"
0027 #define DRIVER_MAJOR    1
0028 #define DRIVER_MINOR    0
0029 
0030 static const struct drm_mode_config_helper_funcs sprd_drm_mode_config_helper = {
0031     .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
0032 };
0033 
0034 static const struct drm_mode_config_funcs sprd_drm_mode_config_funcs = {
0035     .fb_create = drm_gem_fb_create,
0036     .atomic_check = drm_atomic_helper_check,
0037     .atomic_commit = drm_atomic_helper_commit,
0038 };
0039 
0040 static void sprd_drm_mode_config_init(struct drm_device *drm)
0041 {
0042     drm->mode_config.min_width = 0;
0043     drm->mode_config.min_height = 0;
0044     drm->mode_config.max_width = 8192;
0045     drm->mode_config.max_height = 8192;
0046 
0047     drm->mode_config.funcs = &sprd_drm_mode_config_funcs;
0048     drm->mode_config.helper_private = &sprd_drm_mode_config_helper;
0049 }
0050 
0051 DEFINE_DRM_GEM_CMA_FOPS(sprd_drm_fops);
0052 
0053 static struct drm_driver sprd_drm_drv = {
0054     .driver_features    = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
0055     .fops           = &sprd_drm_fops,
0056 
0057     /* GEM Operations */
0058     DRM_GEM_CMA_DRIVER_OPS,
0059 
0060     .name           = DRIVER_NAME,
0061     .desc           = DRIVER_DESC,
0062     .date           = DRIVER_DATE,
0063     .major          = DRIVER_MAJOR,
0064     .minor          = DRIVER_MINOR,
0065 };
0066 
0067 static int sprd_drm_bind(struct device *dev)
0068 {
0069     struct platform_device *pdev = to_platform_device(dev);
0070     struct drm_device *drm;
0071     struct sprd_drm *sprd;
0072     int ret;
0073 
0074     sprd = devm_drm_dev_alloc(dev, &sprd_drm_drv, struct sprd_drm, drm);
0075     if (IS_ERR(sprd))
0076         return PTR_ERR(sprd);
0077 
0078     drm = &sprd->drm;
0079     platform_set_drvdata(pdev, drm);
0080 
0081     ret = drmm_mode_config_init(drm);
0082     if (ret)
0083         return ret;
0084 
0085     sprd_drm_mode_config_init(drm);
0086 
0087     /* bind and init sub drivers */
0088     ret = component_bind_all(drm->dev, drm);
0089     if (ret) {
0090         drm_err(drm, "failed to bind all component.\n");
0091         return ret;
0092     }
0093 
0094     /* vblank init */
0095     ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
0096     if (ret) {
0097         drm_err(drm, "failed to initialize vblank.\n");
0098         goto err_unbind_all;
0099     }
0100 
0101     /* reset all the states of crtc/plane/encoder/connector */
0102     drm_mode_config_reset(drm);
0103 
0104     /* init kms poll for handling hpd */
0105     drm_kms_helper_poll_init(drm);
0106 
0107     ret = drm_dev_register(drm, 0);
0108     if (ret < 0)
0109         goto err_kms_helper_poll_fini;
0110 
0111     return 0;
0112 
0113 err_kms_helper_poll_fini:
0114     drm_kms_helper_poll_fini(drm);
0115 err_unbind_all:
0116     component_unbind_all(drm->dev, drm);
0117     return ret;
0118 }
0119 
0120 static void sprd_drm_unbind(struct device *dev)
0121 {
0122     struct drm_device *drm = dev_get_drvdata(dev);
0123 
0124     drm_dev_unregister(drm);
0125 
0126     drm_kms_helper_poll_fini(drm);
0127 
0128     component_unbind_all(drm->dev, drm);
0129 }
0130 
0131 static const struct component_master_ops drm_component_ops = {
0132     .bind = sprd_drm_bind,
0133     .unbind = sprd_drm_unbind,
0134 };
0135 
0136 static int sprd_drm_probe(struct platform_device *pdev)
0137 {
0138     return drm_of_component_probe(&pdev->dev, component_compare_of, &drm_component_ops);
0139 }
0140 
0141 static int sprd_drm_remove(struct platform_device *pdev)
0142 {
0143     component_master_del(&pdev->dev, &drm_component_ops);
0144     return 0;
0145 }
0146 
0147 static void sprd_drm_shutdown(struct platform_device *pdev)
0148 {
0149     struct drm_device *drm = platform_get_drvdata(pdev);
0150 
0151     if (!drm) {
0152         dev_warn(&pdev->dev, "drm device is not available, no shutdown\n");
0153         return;
0154     }
0155 
0156     drm_atomic_helper_shutdown(drm);
0157 }
0158 
0159 static const struct of_device_id drm_match_table[] = {
0160     { .compatible = "sprd,display-subsystem", },
0161     { /* sentinel */ },
0162 };
0163 MODULE_DEVICE_TABLE(of, drm_match_table);
0164 
0165 static struct platform_driver sprd_drm_driver = {
0166     .probe = sprd_drm_probe,
0167     .remove = sprd_drm_remove,
0168     .shutdown = sprd_drm_shutdown,
0169     .driver = {
0170         .name = "sprd-drm-drv",
0171         .of_match_table = drm_match_table,
0172     },
0173 };
0174 
0175 static struct platform_driver *sprd_drm_drivers[]  = {
0176     &sprd_drm_driver,
0177     &sprd_dpu_driver,
0178     &sprd_dsi_driver,
0179 };
0180 
0181 static int __init sprd_drm_init(void)
0182 {
0183     if (drm_firmware_drivers_only())
0184         return -ENODEV;
0185 
0186     return platform_register_drivers(sprd_drm_drivers,
0187                     ARRAY_SIZE(sprd_drm_drivers));
0188 }
0189 
0190 static void __exit sprd_drm_exit(void)
0191 {
0192     platform_unregister_drivers(sprd_drm_drivers,
0193                     ARRAY_SIZE(sprd_drm_drivers));
0194 }
0195 
0196 module_init(sprd_drm_init);
0197 module_exit(sprd_drm_exit);
0198 
0199 MODULE_AUTHOR("Leon He <leon.he@unisoc.com>");
0200 MODULE_AUTHOR("Kevin Tang <kevin.tang@unisoc.com>");
0201 MODULE_DESCRIPTION("Unisoc DRM KMS Master Driver");
0202 MODULE_LICENSE("GPL v2");