blob: d28ffdd2b9298113770621310de332c79774f6f7 [file] [log] [blame]
Daniel Vetterf1e2f662016-09-21 10:59:28 +02001/*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include <drm/drmP.h>
24#include <drm/drm_crtc.h>
25#include <drm/drm_color_mgmt.h>
26
27#include "drm_crtc_internal.h"
28
Daniel Vettera6acccf2016-09-21 10:59:29 +020029/**
30 * DOC: overview
31 *
32 * Color management or color space adjustments is supported through a set of 5
33 * properties on the &drm_crtc object. They are set up by calling
34 * drm_crtc_enable_color_mgmt().
35 *
36 * "DEGAMMA_LUT”:
37 * Blob property to set the degamma lookup table (LUT) mapping pixel data
38 * from the framebuffer before it is given to the transformation matrix.
39 * The data is interpreted as an array of struct &drm_color_lut elements.
40 * Hardware might choose not to use the full precision of the LUT elements
41 * nor use all the elements of the LUT (for example the hardware might
42 * choose to interpolate between LUT[0] and LUT[4]).
43 *
44 * “DEGAMMA_LUT_SIZE”:
45 * Unsinged range property to give the size of the lookup table to be set
46 * on the DEGAMMA_LUT property (the size depends on the underlying
47 * hardware). If drivers support multiple LUT sizes then they should
48 * publish the largest size, and sub-sample smaller sized LUTs (e.g. for
49 * split-gamma modes) appropriately.
50 *
51 * “CTM”:
52 * Blob property to set the current transformation matrix (CTM) apply to
53 * pixel data after the lookup through the degamma LUT and before the
54 * lookup through the gamma LUT. The data is interpreted as a struct
55 * &drm_color_ctm.
56 *
57 * “GAMMA_LUT”:
58 * Blob property to set the gamma lookup table (LUT) mapping pixel data
59 * after the transformation matrix to data sent to the connector. The
60 * data is interpreted as an array of struct &drm_color_lut elements.
61 * Hardware might choose not to use the full precision of the LUT elements
62 * nor use all the elements of the LUT (for example the hardware might
63 * choose to interpolate between LUT[0] and LUT[4]).
64 *
65 * “GAMMA_LUT_SIZE”:
66 * Unsigned range property to give the size of the lookup table to be set
67 * on the GAMMA_LUT property (the size depends on the underlying hardware).
68 * If drivers support multiple LUT sizes then they should publish the
69 * largest size, and sub-sample smaller sized LUTs (e.g. for split-gamma
70 * modes) appropriately.
71 *
72 * There is also support for a legacy gamma table, which is set up by calling
73 * drm_mode_crtc_set_gamma_size(). Drivers which support both should use
74 * drm_atomic_helper_legacy_gamma_set() to alias the legacy gamma ramp with the
75 * "GAMMA_LUT" property above.
76 */
Daniel Vetterf1e2f662016-09-21 10:59:28 +020077
78/**
79 * drm_crtc_enable_color_mgmt - enable color management properties
80 * @crtc: DRM CRTC
81 * @degamma_lut_size: the size of the degamma lut (before CSC)
82 * @has_ctm: whether to attach ctm_property for CSC matrix
83 * @gamma_lut_size: the size of the gamma lut (after CSC)
84 *
85 * This function lets the driver enable the color correction
86 * properties on a CRTC. This includes 3 degamma, csc and gamma
87 * properties that userspace can set and 2 size properties to inform
88 * the userspace of the lut sizes. Each of the properties are
89 * optional. The gamma and degamma properties are only attached if
90 * their size is not 0 and ctm_property is only attached if has_ctm is
91 * true.
92 */
93void drm_crtc_enable_color_mgmt(struct drm_crtc *crtc,
94 uint degamma_lut_size,
95 bool has_ctm,
96 uint gamma_lut_size)
97{
98 struct drm_device *dev = crtc->dev;
99 struct drm_mode_config *config = &dev->mode_config;
100
101 if (degamma_lut_size) {
102 drm_object_attach_property(&crtc->base,
103 config->degamma_lut_property, 0);
104 drm_object_attach_property(&crtc->base,
105 config->degamma_lut_size_property,
106 degamma_lut_size);
107 }
108
109 if (has_ctm)
110 drm_object_attach_property(&crtc->base,
111 config->ctm_property, 0);
112
113 if (gamma_lut_size) {
114 drm_object_attach_property(&crtc->base,
115 config->gamma_lut_property, 0);
116 drm_object_attach_property(&crtc->base,
117 config->gamma_lut_size_property,
118 gamma_lut_size);
119 }
120}
121EXPORT_SYMBOL(drm_crtc_enable_color_mgmt);
122
123/**
124 * drm_mode_crtc_set_gamma_size - set the gamma table size
125 * @crtc: CRTC to set the gamma table size for
126 * @gamma_size: size of the gamma table
127 *
128 * Drivers which support gamma tables should set this to the supported gamma
129 * table size when initializing the CRTC. Currently the drm core only supports a
130 * fixed gamma table size.
131 *
132 * Returns:
133 * Zero on success, negative errno on failure.
134 */
135int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
136 int gamma_size)
137{
138 uint16_t *r_base, *g_base, *b_base;
139 int i;
140
141 crtc->gamma_size = gamma_size;
142
143 crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3,
144 GFP_KERNEL);
145 if (!crtc->gamma_store) {
146 crtc->gamma_size = 0;
147 return -ENOMEM;
148 }
149
150 r_base = crtc->gamma_store;
151 g_base = r_base + gamma_size;
152 b_base = g_base + gamma_size;
153 for (i = 0; i < gamma_size; i++) {
154 r_base[i] = i << 8;
155 g_base[i] = i << 8;
156 b_base[i] = i << 8;
157 }
158
159
160 return 0;
161}
162EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
163
164/**
165 * drm_mode_gamma_set_ioctl - set the gamma table
166 * @dev: DRM device
167 * @data: ioctl data
168 * @file_priv: DRM file info
169 *
170 * Set the gamma table of a CRTC to the one passed in by the user. Userspace can
171 * inquire the required gamma table size through drm_mode_gamma_get_ioctl.
172 *
173 * Called by the user via ioctl.
174 *
175 * Returns:
176 * Zero on success, negative errno on failure.
177 */
178int drm_mode_gamma_set_ioctl(struct drm_device *dev,
179 void *data, struct drm_file *file_priv)
180{
181 struct drm_mode_crtc_lut *crtc_lut = data;
182 struct drm_crtc *crtc;
183 void *r_base, *g_base, *b_base;
184 int size;
185 int ret = 0;
186
187 if (!drm_core_check_feature(dev, DRIVER_MODESET))
188 return -EINVAL;
189
190 drm_modeset_lock_all(dev);
191 crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
192 if (!crtc) {
193 ret = -ENOENT;
194 goto out;
195 }
196
197 if (crtc->funcs->gamma_set == NULL) {
198 ret = -ENOSYS;
199 goto out;
200 }
201
202 /* memcpy into gamma store */
203 if (crtc_lut->gamma_size != crtc->gamma_size) {
204 ret = -EINVAL;
205 goto out;
206 }
207
208 size = crtc_lut->gamma_size * (sizeof(uint16_t));
209 r_base = crtc->gamma_store;
210 if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) {
211 ret = -EFAULT;
212 goto out;
213 }
214
215 g_base = r_base + size;
216 if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) {
217 ret = -EFAULT;
218 goto out;
219 }
220
221 b_base = g_base + size;
222 if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) {
223 ret = -EFAULT;
224 goto out;
225 }
226
227 ret = crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size);
228
229out:
230 drm_modeset_unlock_all(dev);
231 return ret;
232
233}
234
235/**
236 * drm_mode_gamma_get_ioctl - get the gamma table
237 * @dev: DRM device
238 * @data: ioctl data
239 * @file_priv: DRM file info
240 *
241 * Copy the current gamma table into the storage provided. This also provides
242 * the gamma table size the driver expects, which can be used to size the
243 * allocated storage.
244 *
245 * Called by the user via ioctl.
246 *
247 * Returns:
248 * Zero on success, negative errno on failure.
249 */
250int drm_mode_gamma_get_ioctl(struct drm_device *dev,
251 void *data, struct drm_file *file_priv)
252{
253 struct drm_mode_crtc_lut *crtc_lut = data;
254 struct drm_crtc *crtc;
255 void *r_base, *g_base, *b_base;
256 int size;
257 int ret = 0;
258
259 if (!drm_core_check_feature(dev, DRIVER_MODESET))
260 return -EINVAL;
261
262 drm_modeset_lock_all(dev);
263 crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
264 if (!crtc) {
265 ret = -ENOENT;
266 goto out;
267 }
268
269 /* memcpy into gamma store */
270 if (crtc_lut->gamma_size != crtc->gamma_size) {
271 ret = -EINVAL;
272 goto out;
273 }
274
275 size = crtc_lut->gamma_size * (sizeof(uint16_t));
276 r_base = crtc->gamma_store;
277 if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) {
278 ret = -EFAULT;
279 goto out;
280 }
281
282 g_base = r_base + size;
283 if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) {
284 ret = -EFAULT;
285 goto out;
286 }
287
288 b_base = g_base + size;
289 if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) {
290 ret = -EFAULT;
291 goto out;
292 }
293out:
294 drm_modeset_unlock_all(dev);
295 return ret;
296}