Commit | Line | Data |
---|---|---|
2d78b3a1 HW |
1 | /* |
2 | * Copyright 2012-15 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 | #include "reg_helper.h" | |
27 | #include "dcn20_optc.h" | |
28 | #include "dc.h" | |
29 | ||
30 | #define REG(reg)\ | |
31 | optc1->tg_regs->reg | |
32 | ||
33 | #define CTX \ | |
34 | optc1->base.ctx | |
35 | ||
36 | #undef FN | |
37 | #define FN(reg_name, field_name) \ | |
38 | optc1->tg_shift->field_name, optc1->tg_mask->field_name | |
39 | ||
40 | /** | |
41 | * Enable CRTC | |
42 | * Enable CRTC - call ASIC Control Object to enable Timing generator. | |
43 | */ | |
44 | bool optc2_enable_crtc(struct timing_generator *optc) | |
45 | { | |
46 | /* TODO FPGA wait for answer | |
47 | * OTG_MASTER_UPDATE_MODE != CRTC_MASTER_UPDATE_MODE | |
48 | * OTG_MASTER_UPDATE_LOCK != CRTC_MASTER_UPDATE_LOCK | |
49 | */ | |
50 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
51 | ||
52 | /* opp instance for OTG. For DCN1.0, ODM is remoed. | |
53 | * OPP and OPTC should 1:1 mapping | |
54 | */ | |
55 | REG_UPDATE(OPTC_DATA_SOURCE_SELECT, | |
56 | OPTC_SEG0_SRC_SEL, optc->inst); | |
57 | ||
58 | /* VTG enable first is for HW workaround */ | |
59 | REG_UPDATE(CONTROL, | |
60 | VTG0_ENABLE, 1); | |
61 | ||
62 | /* Enable CRTC */ | |
63 | REG_UPDATE_2(OTG_CONTROL, | |
64 | OTG_DISABLE_POINT_CNTL, 3, | |
65 | OTG_MASTER_EN, 1); | |
66 | ||
67 | return true; | |
68 | } | |
69 | ||
70 | /** | |
71 | * DRR double buffering control to select buffer point | |
72 | * for V_TOTAL, H_TOTAL, VTOTAL_MIN, VTOTAL_MAX, VTOTAL_MIN_SEL and VTOTAL_MAX_SEL registers | |
73 | * Options: anytime, start of frame, dp start of frame (range timing) | |
74 | */ | |
75 | void optc2_set_timing_db_mode(struct timing_generator *optc, bool enable) | |
76 | { | |
77 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
78 | ||
79 | uint32_t blank_data_double_buffer_enable = enable ? 1 : 0; | |
80 | ||
81 | REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL, | |
82 | OTG_RANGE_TIMING_DBUF_UPDATE_MODE, blank_data_double_buffer_enable); | |
83 | } | |
84 | ||
85 | /** | |
86 | *For the below, I'm not sure how your GSL parameters are stored in your env, | |
87 | * so I will assume a gsl_params struct for now | |
88 | */ | |
89 | void optc2_set_gsl(struct timing_generator *optc, | |
90 | const struct gsl_params *params) | |
91 | { | |
92 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
93 | ||
94 | /** | |
95 | * There are (MAX_OPTC+1)/2 gsl groups available for use. | |
96 | * In each group (assign an OTG to a group by setting OTG_GSLX_EN = 1, | |
97 | * set one of the OTGs to be the master (OTG_GSL_MASTER_EN = 1) and the rest are slaves. | |
98 | */ | |
99 | REG_UPDATE_5(OTG_GSL_CONTROL, | |
100 | OTG_GSL0_EN, params->gsl0_en, | |
101 | OTG_GSL1_EN, params->gsl1_en, | |
102 | OTG_GSL2_EN, params->gsl2_en, | |
103 | OTG_GSL_MASTER_EN, params->gsl_master_en, | |
104 | OTG_GSL_MASTER_MODE, params->gsl_master_mode); | |
105 | } | |
106 | ||
107 | ||
108 | /* Use the gsl allow flip as the master update lock */ | |
109 | void optc2_use_gsl_as_master_update_lock(struct timing_generator *optc, | |
110 | const struct gsl_params *params) | |
111 | { | |
112 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
113 | ||
114 | REG_UPDATE(OTG_GSL_CONTROL, | |
115 | OTG_MASTER_UPDATE_LOCK_GSL_EN, params->master_update_lock_gsl_en); | |
116 | } | |
117 | ||
118 | /* You can control the GSL timing by limiting GSL to a window (X,Y) */ | |
119 | void optc2_set_gsl_window(struct timing_generator *optc, | |
120 | const struct gsl_params *params) | |
121 | { | |
122 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
123 | ||
124 | REG_SET_2(OTG_GSL_WINDOW_X, 0, | |
125 | OTG_GSL_WINDOW_START_X, params->gsl_window_start_x, | |
126 | OTG_GSL_WINDOW_END_X, params->gsl_window_end_x); | |
127 | REG_SET_2(OTG_GSL_WINDOW_Y, 0, | |
128 | OTG_GSL_WINDOW_START_Y, params->gsl_window_start_y, | |
129 | OTG_GSL_WINDOW_END_Y, params->gsl_window_end_y); | |
130 | } | |
131 | ||
132 | /** | |
133 | * Vupdate keepout can be set to a window to block the update lock for that pipe from changing. | |
134 | * Start offset begins with vstartup and goes for x number of clocks, | |
135 | * end offset starts from end of vupdate to x number of clocks. | |
136 | */ | |
137 | void optc2_set_vupdate_keepout(struct timing_generator *optc, | |
138 | const struct vupdate_keepout_params *params) | |
139 | { | |
140 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
141 | ||
142 | REG_SET_3(OTG_VUPDATE_KEEPOUT, 0, | |
143 | MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, params->start_offset, | |
144 | MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, params->end_offset, | |
145 | OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, params->enable); | |
146 | } | |
147 | ||
148 | void optc2_set_gsl_source_select( | |
149 | struct timing_generator *optc, | |
150 | int group_idx, | |
151 | uint32_t gsl_ready_signal) | |
152 | { | |
153 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
154 | ||
155 | switch (group_idx) { | |
156 | case 1: | |
157 | REG_UPDATE(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, gsl_ready_signal); | |
158 | break; | |
159 | case 2: | |
160 | REG_UPDATE(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, gsl_ready_signal); | |
161 | break; | |
162 | case 3: | |
163 | REG_UPDATE(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, gsl_ready_signal); | |
164 | break; | |
165 | default: | |
166 | break; | |
167 | } | |
168 | } | |
169 | ||
97bda032 HW |
170 | #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT |
171 | /* DSC encoder frame start controls: x = h position, line_num = # of lines from vstartup */ | |
172 | void optc2_set_dsc_encoder_frame_start(struct timing_generator *optc, | |
173 | int x_position, | |
174 | int line_num) | |
175 | { | |
176 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
177 | ||
178 | REG_SET_2(OTG_DSC_START_POSITION, 0, | |
179 | OTG_DSC_START_POSITION_X, x_position, | |
180 | OTG_DSC_START_POSITION_LINE_NUM, line_num); | |
181 | } | |
182 | ||
183 | /* Set DSC-related configuration. | |
184 | * dsc_mode: 0 disables DSC, other values enable DSC in specified format | |
185 | * sc_bytes_per_pixel: Bytes per pixel in u3.28 format | |
186 | * dsc_slice_width: Slice width in pixels | |
187 | */ | |
188 | void optc2_set_dsc_config(struct timing_generator *optc, | |
189 | enum optc_dsc_mode dsc_mode, | |
190 | uint32_t dsc_bytes_per_pixel, | |
191 | uint32_t dsc_slice_width) | |
192 | { | |
193 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
9e14d4f1 | 194 | uint32_t data_format = 0; |
195 | /* skip if dsc mode is not changed */ | |
196 | data_format = dm_read_reg(CTX, REG(OPTC_DATA_FORMAT_CONTROL)); | |
197 | ||
198 | data_format = data_format & 0x30; /* bit5:4 */ | |
199 | data_format = data_format >> 4; | |
200 | ||
201 | if (data_format == dsc_mode) | |
202 | return; | |
97bda032 HW |
203 | |
204 | REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, | |
205 | OPTC_DSC_MODE, dsc_mode); | |
206 | ||
207 | REG_SET(OPTC_BYTES_PER_PIXEL, 0, | |
208 | OPTC_DSC_BYTES_PER_PIXEL, dsc_bytes_per_pixel); | |
209 | ||
210 | REG_UPDATE(OPTC_WIDTH_CONTROL, | |
211 | OPTC_DSC_SLICE_WIDTH, dsc_slice_width); | |
212 | } | |
213 | #endif | |
2d78b3a1 HW |
214 | |
215 | /** | |
216 | * PTI i think is already done somewhere else for 2ka | |
217 | * (opp?, please double check. | |
218 | * OPTC side only has 1 register to set for PTI_ENABLE) | |
219 | */ | |
220 | ||
221 | void optc2_set_odm_bypass(struct timing_generator *optc, | |
222 | const struct dc_crtc_timing *dc_crtc_timing) | |
223 | { | |
224 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
225 | uint32_t h_div_2 = 0; | |
226 | ||
227 | optc1->comb_opp_id = 0xf; | |
228 | REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, | |
229 | OPTC_NUM_OF_INPUT_SEGMENT, 0, | |
230 | OPTC_SEG0_SRC_SEL, optc->inst, | |
231 | OPTC_SEG1_SRC_SEL, 0xf); | |
232 | REG_WRITE(OTG_H_TIMING_CNTL, 0); | |
233 | ||
234 | h_div_2 = optc1_is_two_pixels_per_containter(dc_crtc_timing); | |
235 | REG_UPDATE(OTG_H_TIMING_CNTL, | |
236 | OTG_H_TIMING_DIV_BY2, h_div_2); | |
237 | REG_SET(OPTC_MEMORY_CONFIG, 0, | |
238 | OPTC_MEM_SEL, 0); | |
239 | } | |
240 | ||
fbc9ca67 IB |
241 | void optc2_set_odm_combine(struct timing_generator *optc, int combine_opp_id, |
242 | int mpcc_hactive, enum dc_pixel_encoding pixel_encoding) | |
2d78b3a1 HW |
243 | { |
244 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
245 | /* 2 pieces of memory required for up to 5120 displays, 4 for up to 8192 */ | |
246 | int memory_mask = mpcc_hactive <= 2560 ? 0x3 : 0xf; | |
fbc9ca67 | 247 | uint32_t data_fmt = 0; |
2d78b3a1 HW |
248 | |
249 | /* TODO: In pseudocode but does not affect maximus, delete comment if we dont need on asic | |
250 | * REG_SET(OTG_GLOBAL_CONTROL2, 0, GLOBAL_UPDATE_LOCK_EN, 1); | |
251 | * Program OTG register MASTER_UPDATE_LOCK_DB_X/Y to the position before DP frame start | |
252 | * REG_SET_2(OTG_GLOBAL_CONTROL1, 0, | |
253 | * MASTER_UPDATE_LOCK_DB_X, 160, | |
254 | * MASTER_UPDATE_LOCK_DB_Y, 240); | |
255 | */ | |
256 | if (REG(OPTC_MEMORY_CONFIG)) | |
257 | REG_SET(OPTC_MEMORY_CONFIG, 0, | |
258 | OPTC_MEM_SEL, memory_mask << (optc->inst * 4)); | |
259 | ||
fbc9ca67 IB |
260 | if (pixel_encoding == PIXEL_ENCODING_YCBCR422) |
261 | data_fmt = 1; | |
262 | else if (pixel_encoding == PIXEL_ENCODING_YCBCR420) | |
263 | data_fmt = 2; | |
264 | ||
ce768985 | 265 | REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, data_fmt); |
fbc9ca67 | 266 | |
2d78b3a1 HW |
267 | REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, |
268 | OPTC_NUM_OF_INPUT_SEGMENT, 1, | |
269 | OPTC_SEG0_SRC_SEL, optc->inst, | |
270 | OPTC_SEG1_SRC_SEL, combine_opp_id); | |
271 | ||
272 | REG_UPDATE(OPTC_WIDTH_CONTROL, | |
273 | OPTC_SEGMENT_WIDTH, mpcc_hactive); | |
274 | ||
275 | REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_BY2, 1); | |
276 | optc1->comb_opp_id = combine_opp_id; | |
277 | } | |
278 | ||
279 | void optc2_get_optc_source(struct timing_generator *optc, | |
280 | uint32_t *num_of_src_opp, | |
281 | uint32_t *src_opp_id_0, | |
282 | uint32_t *src_opp_id_1) | |
283 | { | |
284 | uint32_t num_of_input_segments; | |
285 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
286 | ||
287 | REG_GET_3(OPTC_DATA_SOURCE_SELECT, | |
288 | OPTC_NUM_OF_INPUT_SEGMENT, &num_of_input_segments, | |
289 | OPTC_SEG0_SRC_SEL, src_opp_id_0, | |
290 | OPTC_SEG1_SRC_SEL, src_opp_id_1); | |
291 | ||
292 | if (num_of_input_segments == 1) | |
293 | *num_of_src_opp = 2; | |
294 | else | |
295 | *num_of_src_opp = 1; | |
296 | } | |
297 | ||
298 | void optc2_set_dwb_source(struct timing_generator *optc, | |
299 | uint32_t dwb_pipe_inst) | |
300 | { | |
301 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
302 | ||
303 | if (dwb_pipe_inst == 0) | |
304 | REG_UPDATE(DWB_SOURCE_SELECT, | |
305 | OPTC_DWB0_SOURCE_SELECT, optc->inst); | |
306 | else if (dwb_pipe_inst == 1) | |
307 | REG_UPDATE(DWB_SOURCE_SELECT, | |
308 | OPTC_DWB1_SOURCE_SELECT, optc->inst); | |
309 | } | |
310 | ||
311 | void optc2_triplebuffer_lock(struct timing_generator *optc) | |
312 | { | |
313 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
314 | ||
315 | REG_SET(OTG_GLOBAL_CONTROL0, 0, | |
316 | OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); | |
317 | ||
318 | REG_SET(OTG_VUPDATE_KEEPOUT, 0, | |
319 | OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1); | |
320 | ||
321 | REG_SET(OTG_MASTER_UPDATE_LOCK, 0, | |
322 | OTG_MASTER_UPDATE_LOCK, 1); | |
323 | ||
324 | if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) | |
325 | REG_WAIT(OTG_MASTER_UPDATE_LOCK, | |
326 | UPDATE_LOCK_STATUS, 1, | |
327 | 1, 10); | |
328 | } | |
329 | ||
330 | void optc2_triplebuffer_unlock(struct timing_generator *optc) | |
331 | { | |
332 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
333 | ||
334 | REG_SET(OTG_MASTER_UPDATE_LOCK, 0, | |
335 | OTG_MASTER_UPDATE_LOCK, 0); | |
336 | ||
337 | REG_SET(OTG_VUPDATE_KEEPOUT, 0, | |
338 | OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 0); | |
339 | ||
340 | } | |
341 | ||
6c5be4ac WL |
342 | |
343 | void optc2_setup_global_lock(struct timing_generator *optc) | |
344 | { | |
345 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
346 | uint32_t v_blank_start = 0; | |
347 | uint32_t h_blank_start = 0, h_total = 0; | |
348 | ||
349 | REG_SET(OTG_GLOBAL_CONTROL1, 0, MASTER_UPDATE_LOCK_DB_EN, 1); | |
350 | ||
351 | REG_SET(OTG_GLOBAL_CONTROL2, 0, DIG_UPDATE_LOCATION, 20); | |
352 | ||
353 | REG_GET(OTG_V_BLANK_START_END, OTG_V_BLANK_START, &v_blank_start); | |
354 | ||
355 | REG_GET(OTG_H_BLANK_START_END, OTG_H_BLANK_START, &h_blank_start); | |
356 | ||
357 | REG_GET(OTG_H_TOTAL, OTG_H_TOTAL, &h_total); | |
358 | REG_UPDATE_2(OTG_GLOBAL_CONTROL1, | |
359 | MASTER_UPDATE_LOCK_DB_X, | |
360 | h_blank_start - 200 - 1, | |
361 | MASTER_UPDATE_LOCK_DB_Y, | |
362 | v_blank_start - 1); | |
363 | } | |
364 | ||
365 | void optc2_lock_global(struct timing_generator *optc) | |
366 | { | |
367 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
368 | ||
369 | REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 1); | |
370 | ||
371 | REG_SET(OTG_GLOBAL_CONTROL0, 0, | |
372 | OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); | |
373 | REG_SET(OTG_MASTER_UPDATE_LOCK, 0, | |
374 | OTG_MASTER_UPDATE_LOCK, 1); | |
375 | ||
376 | /* Should be fast, status does not update on maximus */ | |
377 | if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) | |
378 | REG_WAIT(OTG_MASTER_UPDATE_LOCK, | |
379 | UPDATE_LOCK_STATUS, 1, | |
380 | 1, 10); | |
381 | } | |
382 | ||
383 | void optc2_lock(struct timing_generator *optc) | |
384 | { | |
385 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
386 | ||
387 | REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 0); | |
388 | ||
389 | REG_SET(OTG_GLOBAL_CONTROL0, 0, | |
390 | OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); | |
391 | REG_SET(OTG_MASTER_UPDATE_LOCK, 0, | |
392 | OTG_MASTER_UPDATE_LOCK, 1); | |
393 | ||
394 | /* Should be fast, status does not update on maximus */ | |
395 | if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) | |
396 | REG_WAIT(OTG_MASTER_UPDATE_LOCK, | |
397 | UPDATE_LOCK_STATUS, 1, | |
398 | 1, 10); | |
399 | } | |
400 | ||
db5378c1 | 401 | void optc2_lock_doublebuffer_enable(struct timing_generator *optc) |
2d78b3a1 HW |
402 | { |
403 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
404 | uint32_t v_blank_start = 0; | |
db5378c1 | 405 | uint32_t h_blank_start = 0; |
2d78b3a1 | 406 | |
db5378c1 WL |
407 | REG_UPDATE(OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, 1); |
408 | ||
409 | REG_UPDATE_2(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 1, | |
410 | DIG_UPDATE_LOCATION, 20); | |
2d78b3a1 HW |
411 | |
412 | REG_GET(OTG_V_BLANK_START_END, OTG_V_BLANK_START, &v_blank_start); | |
413 | ||
414 | REG_GET(OTG_H_BLANK_START_END, OTG_H_BLANK_START, &h_blank_start); | |
415 | ||
2d78b3a1 HW |
416 | REG_UPDATE_2(OTG_GLOBAL_CONTROL1, |
417 | MASTER_UPDATE_LOCK_DB_X, | |
db5378c1 | 418 | h_blank_start - 200 - 1, |
2d78b3a1 HW |
419 | MASTER_UPDATE_LOCK_DB_Y, |
420 | v_blank_start - 1); | |
421 | } | |
422 | ||
db5378c1 | 423 | void optc2_lock_doublebuffer_disable(struct timing_generator *optc) |
2d78b3a1 HW |
424 | { |
425 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
426 | ||
db5378c1 WL |
427 | REG_UPDATE_2(OTG_GLOBAL_CONTROL1, |
428 | MASTER_UPDATE_LOCK_DB_X, | |
429 | 0, | |
430 | MASTER_UPDATE_LOCK_DB_Y, | |
431 | 0); | |
2d78b3a1 | 432 | |
db5378c1 WL |
433 | REG_UPDATE_2(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 0, |
434 | DIG_UPDATE_LOCATION, 0); | |
2d78b3a1 | 435 | |
db5378c1 | 436 | REG_UPDATE(OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, 0); |
2d78b3a1 HW |
437 | } |
438 | ||
ae8f4258 EB |
439 | void optc2_setup_manual_trigger(struct timing_generator *optc) |
440 | { | |
441 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
442 | ||
443 | REG_SET(OTG_MANUAL_FLOW_CONTROL, 0, | |
444 | MANUAL_FLOW_CONTROL, 1); | |
445 | ||
446 | REG_SET(OTG_GLOBAL_CONTROL2, 0, | |
447 | MANUAL_FLOW_CONTROL_SEL, optc->inst); | |
448 | ||
449 | REG_SET_8(OTG_TRIGA_CNTL, 0, | |
450 | OTG_TRIGA_SOURCE_SELECT, 22, | |
451 | OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst, | |
452 | OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1, | |
453 | OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0, | |
454 | OTG_TRIGA_POLARITY_SELECT, 0, | |
455 | OTG_TRIGA_FREQUENCY_SELECT, 0, | |
456 | OTG_TRIGA_DELAY, 0, | |
457 | OTG_TRIGA_CLEAR, 1); | |
458 | } | |
459 | ||
460 | void optc2_program_manual_trigger(struct timing_generator *optc) | |
461 | { | |
462 | struct optc *optc1 = DCN10TG_FROM_TG(optc); | |
463 | ||
464 | REG_SET(OTG_TRIGA_MANUAL_TRIG, 0, | |
465 | OTG_TRIGA_MANUAL_TRIG, 1); | |
466 | } | |
467 | ||
2d78b3a1 HW |
468 | static struct timing_generator_funcs dcn20_tg_funcs = { |
469 | .validate_timing = optc1_validate_timing, | |
470 | .program_timing = optc1_program_timing, | |
471 | .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, | |
472 | .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, | |
473 | .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, | |
474 | .program_global_sync = optc1_program_global_sync, | |
475 | .enable_crtc = optc2_enable_crtc, | |
476 | .disable_crtc = optc1_disable_crtc, | |
477 | /* used by enable_timing_synchronization. Not need for FPGA */ | |
478 | .is_counter_moving = optc1_is_counter_moving, | |
479 | .get_position = optc1_get_position, | |
480 | .get_frame_count = optc1_get_vblank_counter, | |
481 | .get_scanoutpos = optc1_get_crtc_scanoutpos, | |
482 | .get_otg_active_size = optc1_get_otg_active_size, | |
483 | .set_early_control = optc1_set_early_control, | |
484 | /* used by enable_timing_synchronization. Not need for FPGA */ | |
485 | .wait_for_state = optc1_wait_for_state, | |
486 | .set_blank = optc1_set_blank, | |
487 | .is_blanked = optc1_is_blanked, | |
488 | .set_blank_color = optc1_program_blank_color, | |
489 | .enable_reset_trigger = optc1_enable_reset_trigger, | |
490 | .enable_crtc_reset = optc1_enable_crtc_reset, | |
491 | .did_triggered_reset_occur = optc1_did_triggered_reset_occur, | |
492 | .triplebuffer_lock = optc2_triplebuffer_lock, | |
493 | .triplebuffer_unlock = optc2_triplebuffer_unlock, | |
494 | .disable_reset_trigger = optc1_disable_reset_trigger, | |
6c5be4ac | 495 | .lock = optc2_lock, |
2d78b3a1 | 496 | .unlock = optc1_unlock, |
6c5be4ac WL |
497 | .lock_global = optc2_lock_global, |
498 | .setup_global_lock = optc2_setup_global_lock, | |
db5378c1 WL |
499 | .lock_doublebuffer_enable = optc2_lock_doublebuffer_enable, |
500 | .lock_doublebuffer_disable = optc2_lock_doublebuffer_disable, | |
2d78b3a1 HW |
501 | .enable_optc_clock = optc1_enable_optc_clock, |
502 | .set_drr = optc1_set_drr, | |
503 | .set_static_screen_control = optc1_set_static_screen_control, | |
504 | .program_stereo = optc1_program_stereo, | |
505 | .is_stereo_left_eye = optc1_is_stereo_left_eye, | |
506 | .set_blank_data_double_buffer = optc1_set_blank_data_double_buffer, | |
507 | .tg_init = optc1_tg_init, | |
508 | .is_tg_enabled = optc1_is_tg_enabled, | |
509 | .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, | |
510 | .clear_optc_underflow = optc1_clear_optc_underflow, | |
511 | .setup_global_swap_lock = NULL, | |
512 | .get_crc = optc1_get_crc, | |
513 | .configure_crc = optc1_configure_crc, | |
97bda032 HW |
514 | #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT |
515 | .set_dsc_config = optc2_set_dsc_config, | |
516 | #endif | |
2d78b3a1 HW |
517 | .set_dwb_source = optc2_set_dwb_source, |
518 | .set_odm_bypass = optc2_set_odm_bypass, | |
519 | .set_odm_combine = optc2_set_odm_combine, | |
520 | .get_optc_source = optc2_get_optc_source, | |
521 | .set_gsl = optc2_set_gsl, | |
522 | .set_gsl_source_select = optc2_set_gsl_source_select, | |
3972c350 | 523 | .set_vtg_params = optc1_set_vtg_params, |
ae8f4258 EB |
524 | .program_manual_trigger = optc2_program_manual_trigger, |
525 | .setup_manual_trigger = optc2_setup_manual_trigger | |
2d78b3a1 HW |
526 | }; |
527 | ||
528 | void dcn20_timing_generator_init(struct optc *optc1) | |
529 | { | |
530 | optc1->base.funcs = &dcn20_tg_funcs; | |
531 | ||
532 | optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; | |
533 | optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; | |
534 | ||
535 | optc1->min_h_blank = 32; | |
536 | optc1->min_v_blank = 3; | |
537 | optc1->min_v_blank_interlace = 5; | |
09fc26c1 | 538 | optc1->min_h_sync_width = 4;// Minimum HSYNC = 8 pixels asked By HW in the first place for no actual reason. Oculus Rift S will not light up with 8 as it's hsyncWidth is 6. Changing it to 4 to fix that issue. |
2d78b3a1 HW |
539 | optc1->min_v_sync_width = 1; |
540 | optc1->comb_opp_id = 0xf; | |
541 | } | |
542 |