1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020 Unisoc Inc. 4 */ 5 6 #include <linux/component.h> 7 #include <linux/dma-mapping.h> 8 #include <linux/module.h> 9 #include <linux/mutex.h> 10 #include <linux/of_graph.h> 11 #include <linux/platform_device.h> 12 13 #include <drm/drm_atomic_helper.h> 14 #include <drm/drm_drv.h> 15 #include <drm/drm_gem_dma_helper.h> 16 #include <drm/drm_gem_framebuffer_helper.h> 17 #include <drm/drm_of.h> 18 #include <drm/drm_probe_helper.h> 19 #include <drm/drm_vblank.h> 20 21 #include "sprd_drm.h" 22 23 #define DRIVER_NAME "sprd" 24 #define DRIVER_DESC "Spreadtrum SoCs' DRM Driver" 25 #define DRIVER_MAJOR 1 26 #define DRIVER_MINOR 0 27 28 static const struct drm_mode_config_helper_funcs sprd_drm_mode_config_helper = { 29 .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, 30 }; 31 32 static const struct drm_mode_config_funcs sprd_drm_mode_config_funcs = { 33 .fb_create = drm_gem_fb_create, 34 .atomic_check = drm_atomic_helper_check, 35 .atomic_commit = drm_atomic_helper_commit, 36 }; 37 38 static void sprd_drm_mode_config_init(struct drm_device *drm) 39 { 40 drm->mode_config.min_width = 0; 41 drm->mode_config.min_height = 0; 42 drm->mode_config.max_width = 8192; 43 drm->mode_config.max_height = 8192; 44 45 drm->mode_config.funcs = &sprd_drm_mode_config_funcs; 46 drm->mode_config.helper_private = &sprd_drm_mode_config_helper; 47 } 48 49 DEFINE_DRM_GEM_DMA_FOPS(sprd_drm_fops); 50 51 static struct drm_driver sprd_drm_drv = { 52 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, 53 .fops = &sprd_drm_fops, 54 55 /* GEM Operations */ 56 DRM_GEM_DMA_DRIVER_OPS, 57 58 .name = DRIVER_NAME, 59 .desc = DRIVER_DESC, 60 .major = DRIVER_MAJOR, 61 .minor = DRIVER_MINOR, 62 }; 63 64 static int sprd_drm_bind(struct device *dev) 65 { 66 struct platform_device *pdev = to_platform_device(dev); 67 struct drm_device *drm; 68 struct sprd_drm *sprd; 69 int ret; 70 71 sprd = devm_drm_dev_alloc(dev, &sprd_drm_drv, struct sprd_drm, drm); 72 if (IS_ERR(sprd)) 73 return PTR_ERR(sprd); 74 75 drm = &sprd->drm; 76 platform_set_drvdata(pdev, drm); 77 78 ret = drmm_mode_config_init(drm); 79 if (ret) 80 return ret; 81 82 sprd_drm_mode_config_init(drm); 83 84 /* bind and init sub drivers */ 85 ret = component_bind_all(drm->dev, drm); 86 if (ret) { 87 drm_err(drm, "failed to bind all component.\n"); 88 return ret; 89 } 90 91 /* vblank init */ 92 ret = drm_vblank_init(drm, drm->mode_config.num_crtc); 93 if (ret) { 94 drm_err(drm, "failed to initialize vblank.\n"); 95 goto err_unbind_all; 96 } 97 98 /* reset all the states of crtc/plane/encoder/connector */ 99 drm_mode_config_reset(drm); 100 101 /* init kms poll for handling hpd */ 102 drm_kms_helper_poll_init(drm); 103 104 ret = drm_dev_register(drm, 0); 105 if (ret < 0) 106 goto err_kms_helper_poll_fini; 107 108 return 0; 109 110 err_kms_helper_poll_fini: 111 drm_kms_helper_poll_fini(drm); 112 err_unbind_all: 113 component_unbind_all(drm->dev, drm); 114 return ret; 115 } 116 117 static void sprd_drm_unbind(struct device *dev) 118 { 119 struct drm_device *drm = dev_get_drvdata(dev); 120 121 drm_dev_unregister(drm); 122 123 drm_kms_helper_poll_fini(drm); 124 125 component_unbind_all(drm->dev, drm); 126 } 127 128 static const struct component_master_ops drm_component_ops = { 129 .bind = sprd_drm_bind, 130 .unbind = sprd_drm_unbind, 131 }; 132 133 static int sprd_drm_probe(struct platform_device *pdev) 134 { 135 return drm_of_component_probe(&pdev->dev, component_compare_of, &drm_component_ops); 136 } 137 138 static void sprd_drm_remove(struct platform_device *pdev) 139 { 140 component_master_del(&pdev->dev, &drm_component_ops); 141 } 142 143 static void sprd_drm_shutdown(struct platform_device *pdev) 144 { 145 struct drm_device *drm = platform_get_drvdata(pdev); 146 147 if (!drm) { 148 dev_warn(&pdev->dev, "drm device is not available, no shutdown\n"); 149 return; 150 } 151 152 drm_atomic_helper_shutdown(drm); 153 } 154 155 static const struct of_device_id drm_match_table[] = { 156 { .compatible = "sprd,display-subsystem", }, 157 { /* sentinel */ }, 158 }; 159 MODULE_DEVICE_TABLE(of, drm_match_table); 160 161 static struct platform_driver sprd_drm_driver = { 162 .probe = sprd_drm_probe, 163 .remove = sprd_drm_remove, 164 .shutdown = sprd_drm_shutdown, 165 .driver = { 166 .name = "sprd-drm-drv", 167 .of_match_table = drm_match_table, 168 }, 169 }; 170 171 static struct platform_driver *sprd_drm_drivers[] = { 172 &sprd_drm_driver, 173 &sprd_dpu_driver, 174 &sprd_dsi_driver, 175 }; 176 177 static int __init sprd_drm_init(void) 178 { 179 if (drm_firmware_drivers_only()) 180 return -ENODEV; 181 182 return platform_register_drivers(sprd_drm_drivers, 183 ARRAY_SIZE(sprd_drm_drivers)); 184 } 185 186 static void __exit sprd_drm_exit(void) 187 { 188 platform_unregister_drivers(sprd_drm_drivers, 189 ARRAY_SIZE(sprd_drm_drivers)); 190 } 191 192 module_init(sprd_drm_init); 193 module_exit(sprd_drm_exit); 194 195 MODULE_AUTHOR("Leon He <leon.he@unisoc.com>"); 196 MODULE_AUTHOR("Kevin Tang <kevin.tang@unisoc.com>"); 197 MODULE_DESCRIPTION("Unisoc DRM KMS Master Driver"); 198 MODULE_LICENSE("GPL v2"); 199