Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v5.0 197 lines 5.1 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 39static struct drm_framebuffer * 40tinydrm_fb_create(struct drm_device *drm, struct drm_file *file_priv, 41 const struct drm_mode_fb_cmd2 *mode_cmd) 42{ 43 struct tinydrm_device *tdev = drm->dev_private; 44 45 return drm_gem_fb_create_with_funcs(drm, file_priv, mode_cmd, 46 tdev->fb_funcs); 47} 48 49static const struct drm_mode_config_funcs tinydrm_mode_config_funcs = { 50 .fb_create = tinydrm_fb_create, 51 .atomic_check = drm_atomic_helper_check, 52 .atomic_commit = drm_atomic_helper_commit, 53}; 54 55static int tinydrm_init(struct device *parent, struct tinydrm_device *tdev, 56 const struct drm_framebuffer_funcs *fb_funcs, 57 struct drm_driver *driver) 58{ 59 struct drm_device *drm; 60 61 mutex_init(&tdev->dirty_lock); 62 tdev->fb_funcs = fb_funcs; 63 64 /* 65 * We don't embed drm_device, because that prevent us from using 66 * devm_kzalloc() to allocate tinydrm_device in the driver since 67 * drm_dev_put() frees the structure. The devm_ functions provide 68 * for easy error handling. 69 */ 70 drm = drm_dev_alloc(driver, parent); 71 if (IS_ERR(drm)) 72 return PTR_ERR(drm); 73 74 tdev->drm = drm; 75 drm->dev_private = tdev; 76 drm_mode_config_init(drm); 77 drm->mode_config.funcs = &tinydrm_mode_config_funcs; 78 drm->mode_config.allow_fb_modifiers = true; 79 80 return 0; 81} 82 83static void tinydrm_fini(struct tinydrm_device *tdev) 84{ 85 drm_mode_config_cleanup(tdev->drm); 86 mutex_destroy(&tdev->dirty_lock); 87 tdev->drm->dev_private = NULL; 88 drm_dev_put(tdev->drm); 89} 90 91static void devm_tinydrm_release(void *data) 92{ 93 tinydrm_fini(data); 94} 95 96/** 97 * devm_tinydrm_init - Initialize tinydrm device 98 * @parent: Parent device object 99 * @tdev: tinydrm device 100 * @fb_funcs: Framebuffer functions 101 * @driver: DRM driver 102 * 103 * This function initializes @tdev, the underlying DRM device and it's 104 * mode_config. Resources will be automatically freed on driver detach (devres) 105 * using drm_mode_config_cleanup() and drm_dev_put(). 106 * 107 * Returns: 108 * Zero on success, negative error code on failure. 109 */ 110int devm_tinydrm_init(struct device *parent, struct tinydrm_device *tdev, 111 const struct drm_framebuffer_funcs *fb_funcs, 112 struct drm_driver *driver) 113{ 114 int ret; 115 116 ret = tinydrm_init(parent, tdev, fb_funcs, driver); 117 if (ret) 118 return ret; 119 120 ret = devm_add_action(parent, devm_tinydrm_release, tdev); 121 if (ret) 122 tinydrm_fini(tdev); 123 124 return ret; 125} 126EXPORT_SYMBOL(devm_tinydrm_init); 127 128static int tinydrm_register(struct tinydrm_device *tdev) 129{ 130 struct drm_device *drm = tdev->drm; 131 int ret; 132 133 ret = drm_dev_register(tdev->drm, 0); 134 if (ret) 135 return ret; 136 137 ret = drm_fbdev_generic_setup(drm, 0); 138 if (ret) 139 DRM_ERROR("Failed to initialize fbdev: %d\n", ret); 140 141 return 0; 142} 143 144static void tinydrm_unregister(struct tinydrm_device *tdev) 145{ 146 drm_atomic_helper_shutdown(tdev->drm); 147 drm_dev_unregister(tdev->drm); 148} 149 150static void devm_tinydrm_register_release(void *data) 151{ 152 tinydrm_unregister(data); 153} 154 155/** 156 * devm_tinydrm_register - Register tinydrm device 157 * @tdev: tinydrm device 158 * 159 * This function registers the underlying DRM device and fbdev. 160 * These resources will be automatically unregistered on driver detach (devres) 161 * and the display pipeline will be disabled. 162 * 163 * Returns: 164 * Zero on success, negative error code on failure. 165 */ 166int devm_tinydrm_register(struct tinydrm_device *tdev) 167{ 168 struct device *dev = tdev->drm->dev; 169 int ret; 170 171 ret = tinydrm_register(tdev); 172 if (ret) 173 return ret; 174 175 ret = devm_add_action(dev, devm_tinydrm_register_release, tdev); 176 if (ret) 177 tinydrm_unregister(tdev); 178 179 return ret; 180} 181EXPORT_SYMBOL(devm_tinydrm_register); 182 183/** 184 * tinydrm_shutdown - Shutdown tinydrm 185 * @tdev: tinydrm device 186 * 187 * This function makes sure that the display pipeline is disabled. 188 * Used by drivers in their shutdown callback to turn off the display 189 * on machine shutdown and reboot. 190 */ 191void tinydrm_shutdown(struct tinydrm_device *tdev) 192{ 193 drm_atomic_helper_shutdown(tdev->drm); 194} 195EXPORT_SYMBOL(tinydrm_shutdown); 196 197MODULE_LICENSE("GPL");