drm/amd/display: Fix Dynamic bpp issue with 8K30 with Navi 1X
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / display / dc / dcn20 / dcn20_dwb.c
1 /*
2  * Copyright 2012-17 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
26
27 #include "reg_helper.h"
28 #include "resource.h"
29 #include "dwb.h"
30 #include "dcn20_dwb.h"
31
32
33 #define REG(reg)\
34         dwbc20->dwbc_regs->reg
35
36 #define CTX \
37         dwbc20->base.ctx
38
39 #define DC_LOGGER \
40         dwbc20->base.ctx->logger
41 #undef FN
42 #define FN(reg_name, field_name) \
43         dwbc20->dwbc_shift->field_name, dwbc20->dwbc_mask->field_name
44
45 enum dwb_outside_pix_strategy {
46         DWB_OUTSIDE_PIX_STRATEGY_BLACK = 0,
47         DWB_OUTSIDE_PIX_STRATEGY_EDGE  = 1
48 };
49
50 static bool dwb2_get_caps(struct dwbc *dwbc, struct dwb_caps *caps)
51 {
52         struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc);
53         if (caps) {
54                 caps->adapter_id = 0;   /* we only support 1 adapter currently */
55                 caps->hw_version = DCN_VERSION_2_0;
56                 caps->num_pipes = 1;
57                 memset(&caps->reserved, 0, sizeof(caps->reserved));
58                 memset(&caps->reserved2, 0, sizeof(caps->reserved2));
59                 caps->sw_version = dwb_ver_1_0;
60                 caps->caps.support_dwb = true;
61                 caps->caps.support_ogam = false;
62                 caps->caps.support_wbscl = false;
63                 caps->caps.support_ocsc = false;
64                 DC_LOG_DWB("%s SUPPORTED! inst = %d", __func__, dwbc20->base.inst);
65                 return true;
66         } else {
67                 DC_LOG_DWB("%s NOT SUPPORTED! inst = %d", __func__, dwbc20->base.inst);
68                 return false;
69         }
70 }
71
72 void dwb2_config_dwb_cnv(struct dwbc *dwbc, struct dc_dwb_params *params)
73 {
74         struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc);
75         DC_LOG_DWB("%s inst = %d", __func__, dwbc20->base.inst);
76
77         /* Set DWB source size */
78         REG_UPDATE_2(CNV_SOURCE_SIZE, CNV_SOURCE_WIDTH, params->cnv_params.src_width,
79                         CNV_SOURCE_HEIGHT, params->cnv_params.src_height);
80
81         /* source size is not equal the source size, then enable cropping. */
82         if (params->cnv_params.crop_en) {
83                 REG_UPDATE(CNV_MODE, CNV_WINDOW_CROP_EN, 1);
84                 REG_UPDATE(CNV_WINDOW_START, CNV_WINDOW_START_X, params->cnv_params.crop_x);
85                 REG_UPDATE(CNV_WINDOW_START, CNV_WINDOW_START_Y, params->cnv_params.crop_y);
86                 REG_UPDATE(CNV_WINDOW_SIZE,  CNV_WINDOW_WIDTH,   params->cnv_params.crop_width);
87                 REG_UPDATE(CNV_WINDOW_SIZE,  CNV_WINDOW_HEIGHT,  params->cnv_params.crop_height);
88         } else {
89                 REG_UPDATE(CNV_MODE, CNV_WINDOW_CROP_EN, 0);
90         }
91
92         /* Set CAPTURE_RATE */
93         REG_UPDATE(CNV_MODE, CNV_FRAME_CAPTURE_RATE, params->capture_rate);
94
95         /* Set CNV output pixel depth */
96         REG_UPDATE(CNV_MODE, CNV_OUT_BPC, params->cnv_params.cnv_out_bpc);
97 }
98
99 static bool dwb2_enable(struct dwbc *dwbc, struct dc_dwb_params *params)
100 {
101         struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc);
102
103         /* Only chroma scaling (sub-sampling) is supported in DCN2 */
104 if ((params->cnv_params.src_width  != params->dest_width) ||
105                 (params->cnv_params.src_height != params->dest_height)) {
106
107                 DC_LOG_DWB("%s inst = %d, FAILED!LUMA SCALING NOT SUPPORTED", __func__, dwbc20->base.inst);
108                 return false;
109         }
110         DC_LOG_DWB("%s inst = %d, ENABLED", __func__, dwbc20->base.inst);
111
112         /* disable power gating */
113         //REG_UPDATE_5(WB_EC_CONFIG, DISPCLK_R_WB_GATE_DIS, 1,
114         //                       DISPCLK_G_WB_GATE_DIS, 1, DISPCLK_G_WBSCL_GATE_DIS, 1,
115         //                       WB_LB_LS_DIS, 1, WB_LUT_LS_DIS, 1);
116
117         /* Set WB_ENABLE (not double buffered; capture not enabled) */
118         REG_UPDATE(WB_ENABLE, WB_ENABLE, 1);
119
120         /* Set CNV parameters */
121         dwb2_config_dwb_cnv(dwbc, params);
122
123         /* Set scaling parameters */
124         dwb2_set_scaler(dwbc, params);
125
126         /* Enable DWB capture enable (double buffered) */
127         REG_UPDATE(CNV_MODE, CNV_FRAME_CAPTURE_EN, DWB_FRAME_CAPTURE_ENABLE);
128
129         // disable warmup
130         REG_UPDATE(WB_WARM_UP_MODE_CTL1, GMC_WARM_UP_ENABLE, 0);
131
132         return true;
133 }
134
135 bool dwb2_disable(struct dwbc *dwbc)
136 {
137         struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc);
138         DC_LOG_DWB("%s inst = %d, Disabled", __func__, dwbc20->base.inst);
139
140         /* disable CNV */
141         REG_UPDATE(CNV_MODE, CNV_FRAME_CAPTURE_EN, DWB_FRAME_CAPTURE_DISABLE);
142
143         /* disable WB */
144         REG_UPDATE(WB_ENABLE, WB_ENABLE, 0);
145
146         /* soft reset */
147         REG_UPDATE(WB_SOFT_RESET, WB_SOFT_RESET, 1);
148         REG_UPDATE(WB_SOFT_RESET, WB_SOFT_RESET, 0);
149
150         /* enable power gating */
151         //REG_UPDATE_5(WB_EC_CONFIG, DISPCLK_R_WB_GATE_DIS, 0,
152         //                       DISPCLK_G_WB_GATE_DIS, 0, DISPCLK_G_WBSCL_GATE_DIS, 0,
153         //                       WB_LB_LS_DIS, 0, WB_LUT_LS_DIS, 0);
154
155         return true;
156 }
157
158 static bool dwb2_update(struct dwbc *dwbc, struct dc_dwb_params *params)
159 {
160         struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc);
161         unsigned int pre_locked;
162
163         /* Only chroma scaling (sub-sampling) is supported in DCN2 */
164         if ((params->cnv_params.src_width != params->dest_width) ||
165                         (params->cnv_params.src_height != params->dest_height)) {
166                 DC_LOG_DWB("%s inst = %d, FAILED!LUMA SCALING NOT SUPPORTED", __func__, dwbc20->base.inst);
167                 return false;
168         }
169         DC_LOG_DWB("%s inst = %d, scaling", __func__, dwbc20->base.inst);
170
171         /*
172          * Check if the caller has already locked CNV registers.
173          * If so: assume the caller will unlock, so don't touch the lock.
174          * If not: lock them for this update, then unlock after the
175          * update is complete.
176          */
177         REG_GET(CNV_UPDATE, CNV_UPDATE_LOCK, &pre_locked);
178
179         if (pre_locked == 0) {
180                 /* Lock DWB registers */
181                 REG_UPDATE(CNV_UPDATE, CNV_UPDATE_LOCK, 1);
182         }
183
184         /* Set CNV parameters */
185         dwb2_config_dwb_cnv(dwbc, params);
186
187         /* Set scaling parameters */
188         dwb2_set_scaler(dwbc, params);
189
190         if (pre_locked == 0) {
191                 /* Unlock DWB registers */
192                 REG_UPDATE(CNV_UPDATE, CNV_UPDATE_LOCK, 0);
193         }
194
195         return true;
196 }
197
198 bool dwb2_is_enabled(struct dwbc *dwbc)
199 {
200         struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc);
201         unsigned int wb_enabled = 0;
202         unsigned int cnv_frame_capture_en = 0;
203
204         REG_GET(WB_ENABLE, WB_ENABLE, &wb_enabled);
205         REG_GET(CNV_MODE, CNV_FRAME_CAPTURE_EN, &cnv_frame_capture_en);
206
207         return ((wb_enabled != 0) && (cnv_frame_capture_en != 0));
208 }
209
210 void dwb2_set_stereo(struct dwbc *dwbc,
211                 struct dwb_stereo_params *stereo_params)
212 {
213         struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc);
214         DC_LOG_DWB("%s inst = %d, enabled =%d", __func__,\
215                 dwbc20->base.inst, stereo_params->stereo_enabled);
216
217         if (stereo_params->stereo_enabled) {
218                 REG_UPDATE(CNV_MODE, CNV_STEREO_TYPE,     stereo_params->stereo_type);
219                 REG_UPDATE(CNV_MODE, CNV_EYE_SELECTION,   stereo_params->stereo_eye_select);
220                 REG_UPDATE(CNV_MODE, CNV_STEREO_POLARITY, stereo_params->stereo_polarity);
221         } else {
222                 REG_UPDATE(CNV_MODE, CNV_EYE_SELECTION, 0);
223         }
224 }
225
226 void dwb2_set_new_content(struct dwbc *dwbc,
227                                                 bool is_new_content)
228 {
229         struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc);
230         DC_LOG_DWB("%s inst = %d", __func__, dwbc20->base.inst);
231
232         REG_UPDATE(CNV_MODE, CNV_NEW_CONTENT, is_new_content);
233 }
234
235 static void dwb2_set_warmup(struct dwbc *dwbc,
236                 struct dwb_warmup_params *warmup_params)
237 {
238         struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc);
239         DC_LOG_DWB("%s inst = %d", __func__, dwbc20->base.inst);
240
241         REG_UPDATE(WB_WARM_UP_MODE_CTL1, GMC_WARM_UP_ENABLE, warmup_params->warmup_en);
242         REG_UPDATE(WB_WARM_UP_MODE_CTL1, WIDTH_WARMUP, warmup_params->warmup_width);
243         REG_UPDATE(WB_WARM_UP_MODE_CTL1, HEIGHT_WARMUP, warmup_params->warmup_height);
244
245         REG_UPDATE(WB_WARM_UP_MODE_CTL2, DATA_VALUE_WARMUP, warmup_params->warmup_data);
246         REG_UPDATE(WB_WARM_UP_MODE_CTL2, MODE_WARMUP, warmup_params->warmup_mode);
247         REG_UPDATE(WB_WARM_UP_MODE_CTL2, DATA_DEPTH_WARMUP, warmup_params->warmup_depth);
248 }
249
250 void dwb2_set_scaler(struct dwbc *dwbc, struct dc_dwb_params *params)
251 {
252         struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc);
253         DC_LOG_DWB("%s inst = %d", __func__, dwbc20->base.inst);
254
255         /* Program scaling mode */
256         REG_UPDATE_2(WBSCL_MODE, WBSCL_MODE, params->out_format,
257                         WBSCL_OUT_BIT_DEPTH, params->output_depth);
258
259         if (params->out_format != dwb_scaler_mode_bypass444) {
260                 /* Program output size */
261                 REG_UPDATE(WBSCL_DEST_SIZE, WBSCL_DEST_WIDTH,   params->dest_width);
262                 REG_UPDATE(WBSCL_DEST_SIZE, WBSCL_DEST_HEIGHT,  params->dest_height);
263
264                 /* Program round offsets */
265                 REG_UPDATE(WBSCL_ROUND_OFFSET, WBSCL_ROUND_OFFSET_Y_RGB, 0x40);
266                 REG_UPDATE(WBSCL_ROUND_OFFSET, WBSCL_ROUND_OFFSET_CBCR,  0x200);
267
268                 /* Program clamp values */
269                 REG_UPDATE(WBSCL_CLAMP_Y_RGB,   WBSCL_CLAMP_UPPER_Y_RGB,        0x3fe);
270                 REG_UPDATE(WBSCL_CLAMP_Y_RGB,   WBSCL_CLAMP_LOWER_Y_RGB,        0x1);
271                 REG_UPDATE(WBSCL_CLAMP_CBCR,    WBSCL_CLAMP_UPPER_CBCR,         0x3fe);
272                 REG_UPDATE(WBSCL_CLAMP_CBCR,    WBSCL_CLAMP_LOWER_CBCR,         0x1);
273
274                 /* Program outside pixel strategy to use edge pixels */
275                 REG_UPDATE(WBSCL_OUTSIDE_PIX_STRATEGY, WBSCL_OUTSIDE_PIX_STRATEGY, DWB_OUTSIDE_PIX_STRATEGY_EDGE);
276
277                 if (params->cnv_params.crop_en) {
278                         /* horizontal scale */
279                         dwb_program_horz_scalar(dwbc20, params->cnv_params.crop_width,
280                                                         params->dest_width,
281                                                         params->scaler_taps);
282
283                         /* vertical scale */
284                         dwb_program_vert_scalar(dwbc20, params->cnv_params.crop_height,
285                                                         params->dest_height,
286                                                         params->scaler_taps,
287                                                         params->subsample_position);
288                 } else {
289                         /* horizontal scale */
290                         dwb_program_horz_scalar(dwbc20, params->cnv_params.src_width,
291                                                         params->dest_width,
292                                                         params->scaler_taps);
293
294                         /* vertical scale */
295                         dwb_program_vert_scalar(dwbc20, params->cnv_params.src_height,
296                                                         params->dest_height,
297                                                         params->scaler_taps,
298                                                         params->subsample_position);
299                 }
300         }
301
302 }
303
304 const struct dwbc_funcs dcn20_dwbc_funcs = {
305         .get_caps               = dwb2_get_caps,
306         .enable                 = dwb2_enable,
307         .disable                = dwb2_disable,
308         .update                 = dwb2_update,
309         .is_enabled             = dwb2_is_enabled,
310         .set_stereo             = dwb2_set_stereo,
311         .set_new_content        = dwb2_set_new_content,
312         .set_warmup             = dwb2_set_warmup,
313         .dwb_set_scaler         = dwb2_set_scaler,
314 };
315
316 void dcn20_dwbc_construct(struct dcn20_dwbc *dwbc20,
317                 struct dc_context *ctx,
318                 const struct dcn20_dwbc_registers *dwbc_regs,
319                 const struct dcn20_dwbc_shift *dwbc_shift,
320                 const struct dcn20_dwbc_mask *dwbc_mask,
321                 int inst)
322 {
323         dwbc20->base.ctx = ctx;
324
325         dwbc20->base.inst = inst;
326         dwbc20->base.funcs = &dcn20_dwbc_funcs;
327
328         dwbc20->dwbc_regs = dwbc_regs;
329         dwbc20->dwbc_shift = dwbc_shift;
330         dwbc20->dwbc_mask = dwbc_mask;
331 }
332