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