1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Hisilicon Kirin SoCs drm master driver 4 * 5 * Copyright (c) 2016 Linaro Limited. 6 * Copyright (c) 2014-2016 Hisilicon Limited. 7 * 8 * Author: 9 * Xinliang Liu <z.liuxinliang@hisilicon.com> 10 * Xinliang Liu <xinliang.liu@linaro.org> 11 * Xinwei Kong <kong.kongxinwei@hisilicon.com> 12 */ 13 14 #include <linux/of_platform.h> 15 #include <linux/component.h> 16 #include <linux/of_graph.h> 17 18 #include <drm/drmP.h> 19 #include <drm/drm_atomic_helper.h> 20 #include <drm/drm_fb_cma_helper.h> 21 #include <drm/drm_fb_helper.h> 22 #include <drm/drm_gem_cma_helper.h> 23 #include <drm/drm_gem_framebuffer_helper.h> 24 #include <drm/drm_of.h> 25 #include <drm/drm_probe_helper.h> 26 27 #include "kirin_drm_drv.h" 28 29 static struct kirin_dc_ops *dc_ops; 30 31 static int kirin_drm_kms_cleanup(struct drm_device *dev) 32 { 33 drm_kms_helper_poll_fini(dev); 34 dc_ops->cleanup(to_platform_device(dev->dev)); 35 drm_mode_config_cleanup(dev); 36 37 return 0; 38 } 39 40 static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = { 41 .fb_create = drm_gem_fb_create, 42 .atomic_check = drm_atomic_helper_check, 43 .atomic_commit = drm_atomic_helper_commit, 44 }; 45 46 static void kirin_drm_mode_config_init(struct drm_device *dev) 47 { 48 dev->mode_config.min_width = 0; 49 dev->mode_config.min_height = 0; 50 51 dev->mode_config.max_width = 2048; 52 dev->mode_config.max_height = 2048; 53 54 dev->mode_config.funcs = &kirin_drm_mode_config_funcs; 55 } 56 57 static int kirin_drm_kms_init(struct drm_device *dev) 58 { 59 int ret; 60 61 dev_set_drvdata(dev->dev, dev); 62 63 /* dev->mode_config initialization */ 64 drm_mode_config_init(dev); 65 kirin_drm_mode_config_init(dev); 66 67 /* display controller init */ 68 ret = dc_ops->init(to_platform_device(dev->dev)); 69 if (ret) 70 goto err_mode_config_cleanup; 71 72 /* bind and init sub drivers */ 73 ret = component_bind_all(dev->dev, dev); 74 if (ret) { 75 DRM_ERROR("failed to bind all component.\n"); 76 goto err_dc_cleanup; 77 } 78 79 /* vblank init */ 80 ret = drm_vblank_init(dev, dev->mode_config.num_crtc); 81 if (ret) { 82 DRM_ERROR("failed to initialize vblank.\n"); 83 goto err_unbind_all; 84 } 85 /* with irq_enabled = true, we can use the vblank feature. */ 86 dev->irq_enabled = true; 87 88 /* reset all the states of crtc/plane/encoder/connector */ 89 drm_mode_config_reset(dev); 90 91 /* init kms poll for handling hpd */ 92 drm_kms_helper_poll_init(dev); 93 94 return 0; 95 96 err_unbind_all: 97 component_unbind_all(dev->dev, dev); 98 err_dc_cleanup: 99 dc_ops->cleanup(to_platform_device(dev->dev)); 100 err_mode_config_cleanup: 101 drm_mode_config_cleanup(dev); 102 103 return ret; 104 } 105 106 DEFINE_DRM_GEM_CMA_FOPS(kirin_drm_fops); 107 108 static int kirin_gem_cma_dumb_create(struct drm_file *file, 109 struct drm_device *dev, 110 struct drm_mode_create_dumb *args) 111 { 112 return drm_gem_cma_dumb_create_internal(file, dev, args); 113 } 114 115 static struct drm_driver kirin_drm_driver = { 116 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | 117 DRIVER_ATOMIC, 118 .fops = &kirin_drm_fops, 119 120 .gem_free_object_unlocked = drm_gem_cma_free_object, 121 .gem_vm_ops = &drm_gem_cma_vm_ops, 122 .dumb_create = kirin_gem_cma_dumb_create, 123 124 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 125 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 126 .gem_prime_export = drm_gem_prime_export, 127 .gem_prime_import = drm_gem_prime_import, 128 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, 129 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, 130 .gem_prime_vmap = drm_gem_cma_prime_vmap, 131 .gem_prime_vunmap = drm_gem_cma_prime_vunmap, 132 .gem_prime_mmap = drm_gem_cma_prime_mmap, 133 134 .name = "kirin", 135 .desc = "Hisilicon Kirin SoCs' DRM Driver", 136 .date = "20150718", 137 .major = 1, 138 .minor = 0, 139 }; 140 141 static int compare_of(struct device *dev, void *data) 142 { 143 return dev->of_node == data; 144 } 145 146 static int kirin_drm_bind(struct device *dev) 147 { 148 struct drm_driver *driver = &kirin_drm_driver; 149 struct drm_device *drm_dev; 150 int ret; 151 152 drm_dev = drm_dev_alloc(driver, dev); 153 if (IS_ERR(drm_dev)) 154 return PTR_ERR(drm_dev); 155 156 ret = kirin_drm_kms_init(drm_dev); 157 if (ret) 158 goto err_drm_dev_put; 159 160 ret = drm_dev_register(drm_dev, 0); 161 if (ret) 162 goto err_kms_cleanup; 163 164 drm_fbdev_generic_setup(drm_dev, 32); 165 166 return 0; 167 168 err_kms_cleanup: 169 kirin_drm_kms_cleanup(drm_dev); 170 err_drm_dev_put: 171 drm_dev_put(drm_dev); 172 173 return ret; 174 } 175 176 static void kirin_drm_unbind(struct device *dev) 177 { 178 struct drm_device *drm_dev = dev_get_drvdata(dev); 179 180 drm_dev_unregister(drm_dev); 181 kirin_drm_kms_cleanup(drm_dev); 182 drm_dev_put(drm_dev); 183 } 184 185 static const struct component_master_ops kirin_drm_ops = { 186 .bind = kirin_drm_bind, 187 .unbind = kirin_drm_unbind, 188 }; 189 190 static int kirin_drm_platform_probe(struct platform_device *pdev) 191 { 192 struct device *dev = &pdev->dev; 193 struct device_node *np = dev->of_node; 194 struct component_match *match = NULL; 195 struct device_node *remote; 196 197 dc_ops = (struct kirin_dc_ops *)of_device_get_match_data(dev); 198 if (!dc_ops) { 199 DRM_ERROR("failed to get dt id data\n"); 200 return -EINVAL; 201 } 202 203 remote = of_graph_get_remote_node(np, 0, 0); 204 if (!remote) 205 return -ENODEV; 206 207 drm_of_component_match_add(dev, &match, compare_of, remote); 208 of_node_put(remote); 209 210 return component_master_add_with_match(dev, &kirin_drm_ops, match); 211 212 return 0; 213 } 214 215 static int kirin_drm_platform_remove(struct platform_device *pdev) 216 { 217 component_master_del(&pdev->dev, &kirin_drm_ops); 218 dc_ops = NULL; 219 return 0; 220 } 221 222 static const struct of_device_id kirin_drm_dt_ids[] = { 223 { .compatible = "hisilicon,hi6220-ade", 224 .data = &ade_dc_ops, 225 }, 226 { /* end node */ }, 227 }; 228 MODULE_DEVICE_TABLE(of, kirin_drm_dt_ids); 229 230 static struct platform_driver kirin_drm_platform_driver = { 231 .probe = kirin_drm_platform_probe, 232 .remove = kirin_drm_platform_remove, 233 .driver = { 234 .name = "kirin-drm", 235 .of_match_table = kirin_drm_dt_ids, 236 }, 237 }; 238 239 module_platform_driver(kirin_drm_platform_driver); 240 241 MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>"); 242 MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>"); 243 MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>"); 244 MODULE_DESCRIPTION("hisilicon Kirin SoCs' DRM master driver"); 245 MODULE_LICENSE("GPL v2"); 246