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/module.h> 17 #include <linux/of_graph.h> 18 #include <linux/platform_device.h> 19 20 #include <drm/drm_atomic_helper.h> 21 #include <drm/drm_drv.h> 22 #include <drm/drm_fb_cma_helper.h> 23 #include <drm/drm_fb_helper.h> 24 #include <drm/drm_gem_cma_helper.h> 25 #include <drm/drm_gem_framebuffer_helper.h> 26 #include <drm/drm_of.h> 27 #include <drm/drm_probe_helper.h> 28 #include <drm/drm_vblank.h> 29 30 #include "kirin_drm_drv.h" 31 32 static struct kirin_dc_ops *dc_ops; 33 34 static int kirin_drm_kms_cleanup(struct drm_device *dev) 35 { 36 drm_kms_helper_poll_fini(dev); 37 dc_ops->cleanup(to_platform_device(dev->dev)); 38 drm_mode_config_cleanup(dev); 39 40 return 0; 41 } 42 43 static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = { 44 .fb_create = drm_gem_fb_create, 45 .atomic_check = drm_atomic_helper_check, 46 .atomic_commit = drm_atomic_helper_commit, 47 }; 48 49 static void kirin_drm_mode_config_init(struct drm_device *dev) 50 { 51 dev->mode_config.min_width = 0; 52 dev->mode_config.min_height = 0; 53 54 dev->mode_config.max_width = 2048; 55 dev->mode_config.max_height = 2048; 56 57 dev->mode_config.funcs = &kirin_drm_mode_config_funcs; 58 } 59 60 static int kirin_drm_kms_init(struct drm_device *dev) 61 { 62 int ret; 63 64 dev_set_drvdata(dev->dev, dev); 65 66 /* dev->mode_config initialization */ 67 drm_mode_config_init(dev); 68 kirin_drm_mode_config_init(dev); 69 70 /* display controller init */ 71 ret = dc_ops->init(to_platform_device(dev->dev)); 72 if (ret) 73 goto err_mode_config_cleanup; 74 75 /* bind and init sub drivers */ 76 ret = component_bind_all(dev->dev, dev); 77 if (ret) { 78 DRM_ERROR("failed to bind all component.\n"); 79 goto err_dc_cleanup; 80 } 81 82 /* vblank init */ 83 ret = drm_vblank_init(dev, dev->mode_config.num_crtc); 84 if (ret) { 85 DRM_ERROR("failed to initialize vblank.\n"); 86 goto err_unbind_all; 87 } 88 /* with irq_enabled = true, we can use the vblank feature. */ 89 dev->irq_enabled = true; 90 91 /* reset all the states of crtc/plane/encoder/connector */ 92 drm_mode_config_reset(dev); 93 94 /* init kms poll for handling hpd */ 95 drm_kms_helper_poll_init(dev); 96 97 return 0; 98 99 err_unbind_all: 100 component_unbind_all(dev->dev, dev); 101 err_dc_cleanup: 102 dc_ops->cleanup(to_platform_device(dev->dev)); 103 err_mode_config_cleanup: 104 drm_mode_config_cleanup(dev); 105 106 return ret; 107 } 108 109 DEFINE_DRM_GEM_CMA_FOPS(kirin_drm_fops); 110 111 static int kirin_gem_cma_dumb_create(struct drm_file *file, 112 struct drm_device *dev, 113 struct drm_mode_create_dumb *args) 114 { 115 return drm_gem_cma_dumb_create_internal(file, dev, args); 116 } 117 118 static struct drm_driver kirin_drm_driver = { 119 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, 120 .fops = &kirin_drm_fops, 121 122 .gem_free_object_unlocked = drm_gem_cma_free_object, 123 .gem_vm_ops = &drm_gem_cma_vm_ops, 124 .dumb_create = kirin_gem_cma_dumb_create, 125 126 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 127 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 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