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, src_width: params->cnv_params.crop_width, |
280 | dest_width: params->dest_width, |
281 | num_taps: params->scaler_taps); |
282 | |
283 | /* vertical scale */ |
284 | dwb_program_vert_scalar(dwbc20, src_height: params->cnv_params.crop_height, |
285 | dest_height: params->dest_height, |
286 | num_taps: params->scaler_taps, |
287 | subsample_position: params->subsample_position); |
288 | } else { |
289 | /* horizontal scale */ |
290 | dwb_program_horz_scalar(dwbc20, src_width: params->cnv_params.src_width, |
291 | dest_width: params->dest_width, |
292 | num_taps: params->scaler_taps); |
293 | |
294 | /* vertical scale */ |
295 | dwb_program_vert_scalar(dwbc20, src_height: params->cnv_params.src_height, |
296 | dest_height: params->dest_height, |
297 | num_taps: params->scaler_taps, |
298 | subsample_position: params->subsample_position); |
299 | } |
300 | } |
301 | |
302 | } |
303 | |
304 | static 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 | |
333 | |