Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.16-rc6 268 lines 7.4 kB view raw
1/* 2 * Copyright (C) 2016 Noralf Trønnes 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 */ 9 10#include <drm/drm_atomic.h> 11#include <drm/drm_atomic_helper.h> 12#include <drm/drm_crtc_helper.h> 13#include <drm/drm_fb_helper.h> 14#include <drm/drm_gem_framebuffer_helper.h> 15#include <drm/tinydrm/tinydrm.h> 16#include <linux/device.h> 17#include <linux/dma-buf.h> 18 19/** 20 * DOC: overview 21 * 22 * This library provides driver helpers for very simple display hardware. 23 * 24 * It is based on &drm_simple_display_pipe coupled with a &drm_connector which 25 * has only one fixed &drm_display_mode. The framebuffers are backed by the 26 * cma helper and have support for framebuffer flushing (dirty). 27 * fbdev support is also included. 28 * 29 */ 30 31/** 32 * DOC: core 33 * 34 * The driver allocates &tinydrm_device, initializes it using 35 * devm_tinydrm_init(), sets up the pipeline using tinydrm_display_pipe_init() 36 * and registers the DRM device using devm_tinydrm_register(). 37 */ 38 39/** 40 * tinydrm_gem_cma_prime_import_sg_table - Produce a CMA GEM object from 41 * another driver's scatter/gather table of pinned pages 42 * @drm: DRM device to import into 43 * @attach: DMA-BUF attachment 44 * @sgt: Scatter/gather table of pinned pages 45 * 46 * This function imports a scatter/gather table exported via DMA-BUF by 47 * another driver using drm_gem_cma_prime_import_sg_table(). It sets the 48 * kernel virtual address on the CMA object. Drivers should use this as their 49 * &drm_driver->gem_prime_import_sg_table callback if they need the virtual 50 * address. tinydrm_gem_cma_free_object() should be used in combination with 51 * this function. 52 * 53 * Returns: 54 * A pointer to a newly created GEM object or an ERR_PTR-encoded negative 55 * error code on failure. 56 */ 57struct drm_gem_object * 58tinydrm_gem_cma_prime_import_sg_table(struct drm_device *drm, 59 struct dma_buf_attachment *attach, 60 struct sg_table *sgt) 61{ 62 struct drm_gem_cma_object *cma_obj; 63 struct drm_gem_object *obj; 64 void *vaddr; 65 66 vaddr = dma_buf_vmap(attach->dmabuf); 67 if (!vaddr) { 68 DRM_ERROR("Failed to vmap PRIME buffer\n"); 69 return ERR_PTR(-ENOMEM); 70 } 71 72 obj = drm_gem_cma_prime_import_sg_table(drm, attach, sgt); 73 if (IS_ERR(obj)) { 74 dma_buf_vunmap(attach->dmabuf, vaddr); 75 return obj; 76 } 77 78 cma_obj = to_drm_gem_cma_obj(obj); 79 cma_obj->vaddr = vaddr; 80 81 return obj; 82} 83EXPORT_SYMBOL(tinydrm_gem_cma_prime_import_sg_table); 84 85/** 86 * tinydrm_gem_cma_free_object - Free resources associated with a CMA GEM 87 * object 88 * @gem_obj: GEM object to free 89 * 90 * This function frees the backing memory of the CMA GEM object, cleans up the 91 * GEM object state and frees the memory used to store the object itself using 92 * drm_gem_cma_free_object(). It also handles PRIME buffers which has the kernel 93 * virtual address set by tinydrm_gem_cma_prime_import_sg_table(). Drivers 94 * can use this as their &drm_driver->gem_free_object callback. 95 */ 96void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj) 97{ 98 if (gem_obj->import_attach) { 99 struct drm_gem_cma_object *cma_obj; 100 101 cma_obj = to_drm_gem_cma_obj(gem_obj); 102 dma_buf_vunmap(gem_obj->import_attach->dmabuf, cma_obj->vaddr); 103 cma_obj->vaddr = NULL; 104 } 105 106 drm_gem_cma_free_object(gem_obj); 107} 108EXPORT_SYMBOL_GPL(tinydrm_gem_cma_free_object); 109 110static struct drm_framebuffer * 111tinydrm_fb_create(struct drm_device *drm, struct drm_file *file_priv, 112 const struct drm_mode_fb_cmd2 *mode_cmd) 113{ 114 struct tinydrm_device *tdev = drm->dev_private; 115 116 return drm_gem_fb_create_with_funcs(drm, file_priv, mode_cmd, 117 tdev->fb_funcs); 118} 119 120static const struct drm_mode_config_funcs tinydrm_mode_config_funcs = { 121 .fb_create = tinydrm_fb_create, 122 .atomic_check = drm_atomic_helper_check, 123 .atomic_commit = drm_atomic_helper_commit, 124}; 125 126static int tinydrm_init(struct device *parent, struct tinydrm_device *tdev, 127 const struct drm_framebuffer_funcs *fb_funcs, 128 struct drm_driver *driver) 129{ 130 struct drm_device *drm; 131 132 mutex_init(&tdev->dirty_lock); 133 tdev->fb_funcs = fb_funcs; 134 135 /* 136 * We don't embed drm_device, because that prevent us from using 137 * devm_kzalloc() to allocate tinydrm_device in the driver since 138 * drm_dev_unref() frees the structure. The devm_ functions provide 139 * for easy error handling. 140 */ 141 drm = drm_dev_alloc(driver, parent); 142 if (IS_ERR(drm)) 143 return PTR_ERR(drm); 144 145 tdev->drm = drm; 146 drm->dev_private = tdev; 147 drm_mode_config_init(drm); 148 drm->mode_config.funcs = &tinydrm_mode_config_funcs; 149 150 return 0; 151} 152 153static void tinydrm_fini(struct tinydrm_device *tdev) 154{ 155 drm_mode_config_cleanup(tdev->drm); 156 mutex_destroy(&tdev->dirty_lock); 157 tdev->drm->dev_private = NULL; 158 drm_dev_unref(tdev->drm); 159} 160 161static void devm_tinydrm_release(void *data) 162{ 163 tinydrm_fini(data); 164} 165 166/** 167 * devm_tinydrm_init - Initialize tinydrm device 168 * @parent: Parent device object 169 * @tdev: tinydrm device 170 * @fb_funcs: Framebuffer functions 171 * @driver: DRM driver 172 * 173 * This function initializes @tdev, the underlying DRM device and it's 174 * mode_config. Resources will be automatically freed on driver detach (devres) 175 * using drm_mode_config_cleanup() and drm_dev_unref(). 176 * 177 * Returns: 178 * Zero on success, negative error code on failure. 179 */ 180int devm_tinydrm_init(struct device *parent, struct tinydrm_device *tdev, 181 const struct drm_framebuffer_funcs *fb_funcs, 182 struct drm_driver *driver) 183{ 184 int ret; 185 186 ret = tinydrm_init(parent, tdev, fb_funcs, driver); 187 if (ret) 188 return ret; 189 190 ret = devm_add_action(parent, devm_tinydrm_release, tdev); 191 if (ret) 192 tinydrm_fini(tdev); 193 194 return ret; 195} 196EXPORT_SYMBOL(devm_tinydrm_init); 197 198static int tinydrm_register(struct tinydrm_device *tdev) 199{ 200 struct drm_device *drm = tdev->drm; 201 int ret; 202 203 ret = drm_dev_register(tdev->drm, 0); 204 if (ret) 205 return ret; 206 207 ret = drm_fb_cma_fbdev_init_with_funcs(drm, 0, 0, tdev->fb_funcs); 208 if (ret) 209 DRM_ERROR("Failed to initialize fbdev: %d\n", ret); 210 211 return 0; 212} 213 214static void tinydrm_unregister(struct tinydrm_device *tdev) 215{ 216 drm_atomic_helper_shutdown(tdev->drm); 217 drm_fb_cma_fbdev_fini(tdev->drm); 218 drm_dev_unregister(tdev->drm); 219} 220 221static void devm_tinydrm_register_release(void *data) 222{ 223 tinydrm_unregister(data); 224} 225 226/** 227 * devm_tinydrm_register - Register tinydrm device 228 * @tdev: tinydrm device 229 * 230 * This function registers the underlying DRM device and fbdev. 231 * These resources will be automatically unregistered on driver detach (devres) 232 * and the display pipeline will be disabled. 233 * 234 * Returns: 235 * Zero on success, negative error code on failure. 236 */ 237int devm_tinydrm_register(struct tinydrm_device *tdev) 238{ 239 struct device *dev = tdev->drm->dev; 240 int ret; 241 242 ret = tinydrm_register(tdev); 243 if (ret) 244 return ret; 245 246 ret = devm_add_action(dev, devm_tinydrm_register_release, tdev); 247 if (ret) 248 tinydrm_unregister(tdev); 249 250 return ret; 251} 252EXPORT_SYMBOL(devm_tinydrm_register); 253 254/** 255 * tinydrm_shutdown - Shutdown tinydrm 256 * @tdev: tinydrm device 257 * 258 * This function makes sure that the display pipeline is disabled. 259 * Used by drivers in their shutdown callback to turn off the display 260 * on machine shutdown and reboot. 261 */ 262void tinydrm_shutdown(struct tinydrm_device *tdev) 263{ 264 drm_atomic_helper_shutdown(tdev->drm); 265} 266EXPORT_SYMBOL(tinydrm_shutdown); 267 268MODULE_LICENSE("GPL");