OSDN Git Service

clk: at91: fix masterck name
[uclinux-h8/linux.git] / drivers / gpu / drm / amd / display / amdgpu_dm / amdgpu_dm_color.c
1 /*
2  * Copyright 2018 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Authors: AMD
23  *
24  */
25 #include "amdgpu.h"
26 #include "amdgpu_mode.h"
27 #include "amdgpu_dm.h"
28 #include "dc.h"
29 #include "modules/color/color_gamma.h"
30
31 #define MAX_DRM_LUT_VALUE 0xFFFF
32
33 /*
34  * Initialize the color module.
35  *
36  * We're not using the full color module, only certain components.
37  * Only call setup functions for components that we need.
38  */
39 void amdgpu_dm_init_color_mod(void)
40 {
41         setup_x_points_distribution();
42 }
43
44
45 /*
46  * Return true if the given lut is a linear mapping of values, i.e. it acts
47  * like a bypass LUT.
48  *
49  * It is considered linear if the lut represents:
50  * f(a) = (0xFF00/MAX_COLOR_LUT_ENTRIES-1)a; for integer a in
51  *                                           [0, MAX_COLOR_LUT_ENTRIES)
52  */
53 static bool __is_lut_linear(struct drm_color_lut *lut, uint32_t size)
54 {
55         int i;
56         uint32_t expected;
57         int delta;
58
59         for (i = 0; i < size; i++) {
60                 /* All color values should equal */
61                 if ((lut[i].red != lut[i].green) || (lut[i].green != lut[i].blue))
62                         return false;
63
64                 expected = i * MAX_DRM_LUT_VALUE / (size-1);
65
66                 /* Allow a +/-1 error. */
67                 delta = lut[i].red - expected;
68                 if (delta < -1 || 1 < delta)
69                         return false;
70         }
71         return true;
72 }
73
74 /**
75  * Convert the drm_color_lut to dc_gamma. The conversion depends on the size
76  * of the lut - whether or not it's legacy.
77  */
78 static void __drm_lut_to_dc_gamma(struct drm_color_lut *lut,
79                                   struct dc_gamma *gamma,
80                                   bool is_legacy)
81 {
82         uint32_t r, g, b;
83         int i;
84
85         if (is_legacy) {
86                 for (i = 0; i < MAX_COLOR_LEGACY_LUT_ENTRIES; i++) {
87                         r = drm_color_lut_extract(lut[i].red, 16);
88                         g = drm_color_lut_extract(lut[i].green, 16);
89                         b = drm_color_lut_extract(lut[i].blue, 16);
90
91                         gamma->entries.red[i] = dc_fixpt_from_int(r);
92                         gamma->entries.green[i] = dc_fixpt_from_int(g);
93                         gamma->entries.blue[i] = dc_fixpt_from_int(b);
94                 }
95                 return;
96         }
97
98         /* else */
99         for (i = 0; i < MAX_COLOR_LUT_ENTRIES; i++) {
100                 r = drm_color_lut_extract(lut[i].red, 16);
101                 g = drm_color_lut_extract(lut[i].green, 16);
102                 b = drm_color_lut_extract(lut[i].blue, 16);
103
104                 gamma->entries.red[i] = dc_fixpt_from_fraction(r, MAX_DRM_LUT_VALUE);
105                 gamma->entries.green[i] = dc_fixpt_from_fraction(g, MAX_DRM_LUT_VALUE);
106                 gamma->entries.blue[i] = dc_fixpt_from_fraction(b, MAX_DRM_LUT_VALUE);
107         }
108 }
109
110 /**
111  * amdgpu_dm_set_regamma_lut: Set regamma lut for the given CRTC.
112  * @crtc: amdgpu_dm crtc state
113  *
114  * Update the underlying dc_stream_state's output transfer function (OTF) in
115  * preparation for hardware commit. If no lut is specified by user, we default
116  * to SRGB.
117  *
118  * RETURNS:
119  * 0 on success, -ENOMEM if memory cannot be allocated to calculate the OTF.
120  */
121 int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc)
122 {
123         struct drm_property_blob *blob = crtc->base.gamma_lut;
124         struct dc_stream_state *stream = crtc->stream;
125         struct amdgpu_device *adev = (struct amdgpu_device *)
126                 crtc->base.state->dev->dev_private;
127         struct drm_color_lut *lut;
128         uint32_t lut_size;
129         struct dc_gamma *gamma;
130         enum dc_transfer_func_type old_type = stream->out_transfer_func->type;
131
132         bool ret;
133
134         if (!blob) {
135                 /* By default, use the SRGB predefined curve.*/
136                 stream->out_transfer_func->type = TF_TYPE_PREDEFINED;
137                 stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB;
138                 return 0;
139         }
140
141         lut = (struct drm_color_lut *)blob->data;
142         lut_size = blob->length / sizeof(struct drm_color_lut);
143
144         gamma = dc_create_gamma();
145         if (!gamma)
146                 return -ENOMEM;
147
148         gamma->num_entries = lut_size;
149         if (gamma->num_entries == MAX_COLOR_LEGACY_LUT_ENTRIES)
150                 gamma->type = GAMMA_RGB_256;
151         else if (gamma->num_entries == MAX_COLOR_LUT_ENTRIES)
152                 gamma->type = GAMMA_CS_TFM_1D;
153         else {
154                 /* Invalid lut size */
155                 dc_gamma_release(&gamma);
156                 return -EINVAL;
157         }
158
159         /* Convert drm_lut into dc_gamma */
160         __drm_lut_to_dc_gamma(lut, gamma, gamma->type == GAMMA_RGB_256);
161
162         /* Call color module to translate into something DC understands. Namely
163          * a transfer function.
164          */
165         stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
166         ret = mod_color_calculate_regamma_params(stream->out_transfer_func,
167                                                  gamma, true, adev->asic_type <= CHIP_RAVEN, NULL);
168         dc_gamma_release(&gamma);
169         if (!ret) {
170                 stream->out_transfer_func->type = old_type;
171                 DRM_ERROR("Out of memory when calculating regamma params\n");
172                 return -ENOMEM;
173         }
174
175         return 0;
176 }
177
178 /**
179  * amdgpu_dm_set_ctm: Set the color transform matrix for the given CRTC.
180  * @crtc: amdgpu_dm crtc state
181  *
182  * Update the underlying dc_stream_state's gamut remap matrix in preparation
183  * for hardware commit. If no matrix is specified by user, gamut remap will be
184  * disabled.
185  */
186 void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc)
187 {
188
189         struct drm_property_blob *blob = crtc->base.ctm;
190         struct dc_stream_state *stream = crtc->stream;
191         struct drm_color_ctm *ctm;
192         int64_t val;
193         int i;
194
195         if (!blob) {
196                 stream->gamut_remap_matrix.enable_remap = false;
197                 return;
198         }
199
200         stream->gamut_remap_matrix.enable_remap = true;
201         ctm = (struct drm_color_ctm *)blob->data;
202         /*
203          * DRM gives a 3x3 matrix, but DC wants 3x4. Assuming we're operating
204          * with homogeneous coordinates, augment the matrix with 0's.
205          *
206          * The format provided is S31.32, using signed-magnitude representation.
207          * Our fixed31_32 is also S31.32, but is using 2's complement. We have
208          * to convert from signed-magnitude to 2's complement.
209          */
210         for (i = 0; i < 12; i++) {
211                 /* Skip 4th element */
212                 if (i % 4 == 3) {
213                         stream->gamut_remap_matrix.matrix[i] = dc_fixpt_zero;
214                         continue;
215                 }
216
217                 /* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */
218                 val = ctm->matrix[i - (i/4)];
219                 /* If negative, convert to 2's complement. */
220                 if (val & (1ULL << 63))
221                         val = -(val & ~(1ULL << 63));
222
223                 stream->gamut_remap_matrix.matrix[i].value = val;
224         }
225 }
226
227
228 /**
229  * amdgpu_dm_set_degamma_lut: Set degamma lut for the given CRTC.
230  * @crtc: amdgpu_dm crtc state
231  *
232  * Update the underlying dc_stream_state's input transfer function (ITF) in
233  * preparation for hardware commit. If no lut is specified by user, we default
234  * to SRGB degamma.
235  *
236  * We support degamma bypass, predefined SRGB, and custom degamma
237  *
238  * RETURNS:
239  * 0 on success
240  * -EINVAL if crtc_state has a degamma_lut of invalid size
241  * -ENOMEM if gamma allocation fails
242  */
243 int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state,
244                               struct dc_plane_state *dc_plane_state)
245 {
246         struct drm_property_blob *blob = crtc_state->degamma_lut;
247         struct drm_color_lut *lut;
248         uint32_t lut_size;
249         struct dc_gamma *gamma;
250         bool ret;
251
252         if (!blob) {
253                 /* Default to SRGB */
254                 dc_plane_state->in_transfer_func->type = TF_TYPE_PREDEFINED;
255                 dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_SRGB;
256                 return 0;
257         }
258
259         lut = (struct drm_color_lut *)blob->data;
260         if (__is_lut_linear(lut, MAX_COLOR_LUT_ENTRIES)) {
261                 dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS;
262                 dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR;
263                 return 0;
264         }
265
266         gamma = dc_create_gamma();
267         if (!gamma)
268                 return -ENOMEM;
269
270         lut_size = blob->length / sizeof(struct drm_color_lut);
271         gamma->num_entries = lut_size;
272         if (gamma->num_entries == MAX_COLOR_LUT_ENTRIES)
273                 gamma->type = GAMMA_CUSTOM;
274         else {
275                 dc_gamma_release(&gamma);
276                 return -EINVAL;
277         }
278
279         __drm_lut_to_dc_gamma(lut, gamma, false);
280
281         dc_plane_state->in_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
282         ret = mod_color_calculate_degamma_params(dc_plane_state->in_transfer_func, gamma, true);
283         dc_gamma_release(&gamma);
284         if (!ret) {
285                 dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS;
286                 DRM_ERROR("Out of memory when calculating degamma params\n");
287                 return -ENOMEM;
288         }
289
290         return 0;
291 }
292