Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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");