Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.12 253 lines 6.2 kB view raw
1/* 2 * Copyright 2016 Linaro Ltd. 3 * Copyright 2016 ZTE Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 */ 10 11#include <linux/clk.h> 12#include <linux/component.h> 13#include <linux/list.h> 14#include <linux/module.h> 15#include <linux/of_graph.h> 16#include <linux/of_platform.h> 17#include <linux/spinlock.h> 18 19#include <drm/drm_atomic_helper.h> 20#include <drm/drm_crtc.h> 21#include <drm/drm_crtc_helper.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_of.h> 26#include <drm/drmP.h> 27 28#include "zx_drm_drv.h" 29#include "zx_vou.h" 30 31struct zx_drm_private { 32 struct drm_fbdev_cma *fbdev; 33}; 34 35static void zx_drm_fb_output_poll_changed(struct drm_device *drm) 36{ 37 struct zx_drm_private *priv = drm->dev_private; 38 39 drm_fbdev_cma_hotplug_event(priv->fbdev); 40} 41 42static const struct drm_mode_config_funcs zx_drm_mode_config_funcs = { 43 .fb_create = drm_fb_cma_create, 44 .output_poll_changed = zx_drm_fb_output_poll_changed, 45 .atomic_check = drm_atomic_helper_check, 46 .atomic_commit = drm_atomic_helper_commit, 47}; 48 49static void zx_drm_lastclose(struct drm_device *drm) 50{ 51 struct zx_drm_private *priv = drm->dev_private; 52 53 drm_fbdev_cma_restore_mode(priv->fbdev); 54} 55 56DEFINE_DRM_GEM_CMA_FOPS(zx_drm_fops); 57 58static struct drm_driver zx_drm_driver = { 59 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | 60 DRIVER_ATOMIC, 61 .lastclose = zx_drm_lastclose, 62 .gem_free_object = drm_gem_cma_free_object, 63 .gem_vm_ops = &drm_gem_cma_vm_ops, 64 .dumb_create = drm_gem_cma_dumb_create, 65 .dumb_map_offset = drm_gem_cma_dumb_map_offset, 66 .dumb_destroy = drm_gem_dumb_destroy, 67 .prime_handle_to_fd = drm_gem_prime_handle_to_fd, 68 .prime_fd_to_handle = drm_gem_prime_fd_to_handle, 69 .gem_prime_export = drm_gem_prime_export, 70 .gem_prime_import = drm_gem_prime_import, 71 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, 72 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, 73 .gem_prime_vmap = drm_gem_cma_prime_vmap, 74 .gem_prime_vunmap = drm_gem_cma_prime_vunmap, 75 .gem_prime_mmap = drm_gem_cma_prime_mmap, 76 .fops = &zx_drm_fops, 77 .name = "zx-vou", 78 .desc = "ZTE VOU Controller DRM", 79 .date = "20160811", 80 .major = 1, 81 .minor = 0, 82}; 83 84static int zx_drm_bind(struct device *dev) 85{ 86 struct drm_device *drm; 87 struct zx_drm_private *priv; 88 int ret; 89 90 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 91 if (!priv) 92 return -ENOMEM; 93 94 drm = drm_dev_alloc(&zx_drm_driver, dev); 95 if (IS_ERR(drm)) 96 return PTR_ERR(drm); 97 98 drm->dev_private = priv; 99 dev_set_drvdata(dev, drm); 100 101 drm_mode_config_init(drm); 102 drm->mode_config.min_width = 16; 103 drm->mode_config.min_height = 16; 104 drm->mode_config.max_width = 4096; 105 drm->mode_config.max_height = 4096; 106 drm->mode_config.funcs = &zx_drm_mode_config_funcs; 107 108 ret = component_bind_all(dev, drm); 109 if (ret) { 110 DRM_DEV_ERROR(dev, "failed to bind all components: %d\n", ret); 111 goto out_unregister; 112 } 113 114 ret = drm_vblank_init(drm, drm->mode_config.num_crtc); 115 if (ret < 0) { 116 DRM_DEV_ERROR(dev, "failed to init vblank: %d\n", ret); 117 goto out_unbind; 118 } 119 120 /* 121 * We will manage irq handler on our own. In this case, irq_enabled 122 * need to be true for using vblank core support. 123 */ 124 drm->irq_enabled = true; 125 126 drm_mode_config_reset(drm); 127 drm_kms_helper_poll_init(drm); 128 129 priv->fbdev = drm_fbdev_cma_init(drm, 32, 130 drm->mode_config.num_connector); 131 if (IS_ERR(priv->fbdev)) { 132 ret = PTR_ERR(priv->fbdev); 133 DRM_DEV_ERROR(dev, "failed to init cma fbdev: %d\n", ret); 134 priv->fbdev = NULL; 135 goto out_poll_fini; 136 } 137 138 ret = drm_dev_register(drm, 0); 139 if (ret) 140 goto out_fbdev_fini; 141 142 return 0; 143 144out_fbdev_fini: 145 if (priv->fbdev) { 146 drm_fbdev_cma_fini(priv->fbdev); 147 priv->fbdev = NULL; 148 } 149out_poll_fini: 150 drm_kms_helper_poll_fini(drm); 151 drm_mode_config_cleanup(drm); 152 drm_vblank_cleanup(drm); 153out_unbind: 154 component_unbind_all(dev, drm); 155out_unregister: 156 dev_set_drvdata(dev, NULL); 157 drm->dev_private = NULL; 158 drm_dev_unref(drm); 159 return ret; 160} 161 162static void zx_drm_unbind(struct device *dev) 163{ 164 struct drm_device *drm = dev_get_drvdata(dev); 165 struct zx_drm_private *priv = drm->dev_private; 166 167 drm_dev_unregister(drm); 168 if (priv->fbdev) { 169 drm_fbdev_cma_fini(priv->fbdev); 170 priv->fbdev = NULL; 171 } 172 drm_kms_helper_poll_fini(drm); 173 drm_mode_config_cleanup(drm); 174 drm_vblank_cleanup(drm); 175 component_unbind_all(dev, drm); 176 dev_set_drvdata(dev, NULL); 177 drm->dev_private = NULL; 178 drm_dev_unref(drm); 179} 180 181static const struct component_master_ops zx_drm_master_ops = { 182 .bind = zx_drm_bind, 183 .unbind = zx_drm_unbind, 184}; 185 186static int compare_of(struct device *dev, void *data) 187{ 188 return dev->of_node == data; 189} 190 191static int zx_drm_probe(struct platform_device *pdev) 192{ 193 struct device *dev = &pdev->dev; 194 struct device_node *parent = dev->of_node; 195 struct device_node *child; 196 struct component_match *match = NULL; 197 int ret; 198 199 ret = of_platform_populate(parent, NULL, NULL, dev); 200 if (ret) 201 return ret; 202 203 for_each_available_child_of_node(parent, child) { 204 component_match_add(dev, &match, compare_of, child); 205 of_node_put(child); 206 } 207 208 return component_master_add_with_match(dev, &zx_drm_master_ops, match); 209} 210 211static int zx_drm_remove(struct platform_device *pdev) 212{ 213 component_master_del(&pdev->dev, &zx_drm_master_ops); 214 return 0; 215} 216 217static const struct of_device_id zx_drm_of_match[] = { 218 { .compatible = "zte,zx296718-vou", }, 219 { /* end */ }, 220}; 221MODULE_DEVICE_TABLE(of, zx_drm_of_match); 222 223static struct platform_driver zx_drm_platform_driver = { 224 .probe = zx_drm_probe, 225 .remove = zx_drm_remove, 226 .driver = { 227 .name = "zx-drm", 228 .of_match_table = zx_drm_of_match, 229 }, 230}; 231 232static struct platform_driver *drivers[] = { 233 &zx_crtc_driver, 234 &zx_hdmi_driver, 235 &zx_tvenc_driver, 236 &zx_drm_platform_driver, 237}; 238 239static int zx_drm_init(void) 240{ 241 return platform_register_drivers(drivers, ARRAY_SIZE(drivers)); 242} 243module_init(zx_drm_init); 244 245static void zx_drm_exit(void) 246{ 247 platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); 248} 249module_exit(zx_drm_exit); 250 251MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); 252MODULE_DESCRIPTION("ZTE ZX VOU DRM driver"); 253MODULE_LICENSE("GPL v2");