1 | /* |
2 | * Copyright 2022 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 "dcn32_optc.h" |
27 | |
28 | #include "dcn30/dcn30_optc.h" |
29 | #include "dcn31/dcn31_optc.h" |
30 | #include "reg_helper.h" |
31 | #include "dc.h" |
32 | #include "dcn_calc_math.h" |
33 | #include "dc_dmub_srv.h" |
34 | |
35 | #define REG(reg)\ |
36 | optc1->tg_regs->reg |
37 | |
38 | #define CTX \ |
39 | optc1->base.ctx |
40 | |
41 | #undef FN |
42 | #define FN(reg_name, field_name) \ |
43 | optc1->tg_shift->field_name, optc1->tg_mask->field_name |
44 | |
45 | static void optc32_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, |
46 | struct dc_crtc_timing *timing) |
47 | { |
48 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
49 | uint32_t memory_mask = 0; |
50 | int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right; |
51 | int mpcc_hactive = h_active / opp_cnt; |
52 | /* Each memory instance is 2048x(32x2) bits to support half line of 4096 */ |
53 | int odm_mem_count = (h_active + 2047) / 2048; |
54 | |
55 | /* |
56 | * display <= 4k : 2 memories + 2 pipes |
57 | * 4k < display <= 8k : 4 memories + 2 pipes |
58 | * 8k < display <= 12k : 6 memories + 4 pipes |
59 | */ |
60 | if (opp_cnt == 4) { |
61 | if (odm_mem_count <= 2) |
62 | memory_mask = 0x3; |
63 | else if (odm_mem_count <= 4) |
64 | memory_mask = 0xf; |
65 | else |
66 | memory_mask = 0x3f; |
67 | } else { |
68 | if (odm_mem_count <= 2) |
69 | memory_mask = 0x1 << (opp_id[0] * 2) | 0x1 << (opp_id[1] * 2); |
70 | else if (odm_mem_count <= 4) |
71 | memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2); |
72 | else |
73 | memory_mask = 0x77; |
74 | } |
75 | |
76 | REG_SET(OPTC_MEMORY_CONFIG, 0, |
77 | OPTC_MEM_SEL, memory_mask); |
78 | |
79 | if (opp_cnt == 2) { |
80 | REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, |
81 | OPTC_NUM_OF_INPUT_SEGMENT, 1, |
82 | OPTC_SEG0_SRC_SEL, opp_id[0], |
83 | OPTC_SEG1_SRC_SEL, opp_id[1]); |
84 | } else if (opp_cnt == 4) { |
85 | REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, |
86 | OPTC_NUM_OF_INPUT_SEGMENT, 3, |
87 | OPTC_SEG0_SRC_SEL, opp_id[0], |
88 | OPTC_SEG1_SRC_SEL, opp_id[1], |
89 | OPTC_SEG2_SRC_SEL, opp_id[2], |
90 | OPTC_SEG3_SRC_SEL, opp_id[3]); |
91 | } |
92 | |
93 | REG_UPDATE(OPTC_WIDTH_CONTROL, |
94 | OPTC_SEGMENT_WIDTH, mpcc_hactive); |
95 | |
96 | REG_UPDATE(OTG_H_TIMING_CNTL, |
97 | OTG_H_TIMING_DIV_MODE, opp_cnt - 1); |
98 | optc1->opp_count = opp_cnt; |
99 | } |
100 | |
101 | void optc32_get_odm_combine_segments(struct timing_generator *tg, int *odm_combine_segments) |
102 | { |
103 | struct optc *optc1 = DCN10TG_FROM_TG(tg); |
104 | int segments; |
105 | |
106 | REG_GET(OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, &segments); |
107 | |
108 | switch (segments) { |
109 | case 0: |
110 | *odm_combine_segments = 1; |
111 | break; |
112 | case 1: |
113 | *odm_combine_segments = 2; |
114 | break; |
115 | case 3: |
116 | *odm_combine_segments = 4; |
117 | break; |
118 | /* 2 is reserved */ |
119 | case 2: |
120 | default: |
121 | *odm_combine_segments = -1; |
122 | } |
123 | } |
124 | |
125 | void optc32_set_h_timing_div_manual_mode(struct timing_generator *optc, bool manual_mode) |
126 | { |
127 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
128 | |
129 | REG_UPDATE(OTG_H_TIMING_CNTL, |
130 | OTG_H_TIMING_DIV_MODE_MANUAL, manual_mode ? 1 : 0); |
131 | } |
132 | /** |
133 | * optc32_enable_crtc() - Enable CRTC - call ASIC Control Object to enable Timing generator. |
134 | * |
135 | * @optc: timing_generator instance. |
136 | * |
137 | * Return: If CRTC is enabled, return true. |
138 | */ |
139 | static bool optc32_enable_crtc(struct timing_generator *optc) |
140 | { |
141 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
142 | |
143 | /* opp instance for OTG, 1 to 1 mapping and odm will adjust */ |
144 | REG_UPDATE(OPTC_DATA_SOURCE_SELECT, |
145 | OPTC_SEG0_SRC_SEL, optc->inst); |
146 | |
147 | /* VTG enable first is for HW workaround */ |
148 | REG_UPDATE(CONTROL, |
149 | VTG0_ENABLE, 1); |
150 | |
151 | REG_SEQ_START(); |
152 | |
153 | /* Enable CRTC */ |
154 | REG_UPDATE_2(OTG_CONTROL, |
155 | OTG_DISABLE_POINT_CNTL, 2, |
156 | OTG_MASTER_EN, 1); |
157 | |
158 | REG_SEQ_SUBMIT(); |
159 | REG_SEQ_WAIT_DONE(); |
160 | |
161 | return true; |
162 | } |
163 | |
164 | /* disable_crtc */ |
165 | static bool optc32_disable_crtc(struct timing_generator *optc) |
166 | { |
167 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
168 | |
169 | /* disable otg request until end of the first line |
170 | * in the vertical blank region |
171 | */ |
172 | REG_UPDATE(OTG_CONTROL, |
173 | OTG_MASTER_EN, 0); |
174 | |
175 | REG_UPDATE(CONTROL, |
176 | VTG0_ENABLE, 0); |
177 | |
178 | /* CRTC disabled, so disable clock. */ |
179 | REG_WAIT(OTG_CLOCK_CONTROL, |
180 | OTG_BUSY, 0, |
181 | 1, 150000); |
182 | |
183 | return true; |
184 | } |
185 | |
186 | static void optc32_phantom_crtc_post_enable(struct timing_generator *optc) |
187 | { |
188 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
189 | |
190 | /* Disable immediately. */ |
191 | REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 0, OTG_MASTER_EN, 0); |
192 | |
193 | /* CRTC disabled, so disable clock. */ |
194 | REG_WAIT(OTG_CLOCK_CONTROL, OTG_BUSY, 0, 1, 100000); |
195 | } |
196 | |
197 | static void optc32_disable_phantom_otg(struct timing_generator *optc) |
198 | { |
199 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
200 | |
201 | REG_UPDATE(OTG_CONTROL, OTG_MASTER_EN, 0); |
202 | } |
203 | |
204 | void optc32_set_odm_bypass(struct timing_generator *optc, |
205 | const struct dc_crtc_timing *dc_crtc_timing) |
206 | { |
207 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
208 | enum h_timing_div_mode h_div = H_TIMING_NO_DIV; |
209 | |
210 | REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, |
211 | OPTC_NUM_OF_INPUT_SEGMENT, 0, |
212 | OPTC_SEG0_SRC_SEL, optc->inst, |
213 | OPTC_SEG1_SRC_SEL, 0xf, |
214 | OPTC_SEG2_SRC_SEL, 0xf, |
215 | OPTC_SEG3_SRC_SEL, 0xf |
216 | ); |
217 | |
218 | h_div = optc1_is_two_pixels_per_containter(timing: dc_crtc_timing); |
219 | REG_UPDATE(OTG_H_TIMING_CNTL, |
220 | OTG_H_TIMING_DIV_MODE, h_div); |
221 | |
222 | REG_SET(OPTC_MEMORY_CONFIG, 0, |
223 | OPTC_MEM_SEL, 0); |
224 | optc1->opp_count = 1; |
225 | } |
226 | |
227 | static void optc32_setup_manual_trigger(struct timing_generator *optc) |
228 | { |
229 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
230 | struct dc *dc = optc->ctx->dc; |
231 | |
232 | if (dc->caps.dmub_caps.mclk_sw && !dc->debug.disable_fams) |
233 | dc_dmub_srv_set_drr_manual_trigger_cmd(dc, tg_inst: optc->inst); |
234 | else { |
235 | /* |
236 | * MIN_MASK_EN is gone and MASK is now always enabled. |
237 | * |
238 | * To get it to it work with manual trigger we need to make sure |
239 | * we program the correct bit. |
240 | */ |
241 | REG_UPDATE_4(OTG_V_TOTAL_CONTROL, |
242 | OTG_V_TOTAL_MIN_SEL, 1, |
243 | OTG_V_TOTAL_MAX_SEL, 1, |
244 | OTG_FORCE_LOCK_ON_EVENT, 0, |
245 | OTG_SET_V_TOTAL_MIN_MASK, (1 << 1)); /* TRIGA */ |
246 | |
247 | // Setup manual flow control for EOF via TRIG_A |
248 | optc->funcs->setup_manual_trigger(optc); |
249 | } |
250 | } |
251 | |
252 | static void optc32_set_drr( |
253 | struct timing_generator *optc, |
254 | const struct drr_params *params) |
255 | { |
256 | struct optc *optc1 = DCN10TG_FROM_TG(optc); |
257 | |
258 | if (params != NULL && |
259 | params->vertical_total_max > 0 && |
260 | params->vertical_total_min > 0) { |
261 | |
262 | if (params->vertical_total_mid != 0) { |
263 | |
264 | REG_SET(OTG_V_TOTAL_MID, 0, |
265 | OTG_V_TOTAL_MID, params->vertical_total_mid - 1); |
266 | |
267 | REG_UPDATE_2(OTG_V_TOTAL_CONTROL, |
268 | OTG_VTOTAL_MID_REPLACING_MAX_EN, 1, |
269 | OTG_VTOTAL_MID_FRAME_NUM, |
270 | (uint8_t)params->vertical_total_mid_frame_num); |
271 | |
272 | } |
273 | |
274 | optc->funcs->set_vtotal_min_max(optc, params->vertical_total_min - 1, params->vertical_total_max - 1); |
275 | } |
276 | |
277 | optc32_setup_manual_trigger(optc); |
278 | } |
279 | |
280 | static struct timing_generator_funcs dcn32_tg_funcs = { |
281 | .validate_timing = optc1_validate_timing, |
282 | .program_timing = optc1_program_timing, |
283 | .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, |
284 | .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, |
285 | .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, |
286 | .program_global_sync = optc1_program_global_sync, |
287 | .enable_crtc = optc32_enable_crtc, |
288 | .disable_crtc = optc32_disable_crtc, |
289 | .phantom_crtc_post_enable = optc32_phantom_crtc_post_enable, |
290 | .disable_phantom_crtc = optc32_disable_phantom_otg, |
291 | /* used by enable_timing_synchronization. Not need for FPGA */ |
292 | .is_counter_moving = optc1_is_counter_moving, |
293 | .get_position = optc1_get_position, |
294 | .get_frame_count = optc1_get_vblank_counter, |
295 | .get_scanoutpos = optc1_get_crtc_scanoutpos, |
296 | .get_otg_active_size = optc1_get_otg_active_size, |
297 | .set_early_control = optc1_set_early_control, |
298 | /* used by enable_timing_synchronization. Not need for FPGA */ |
299 | .wait_for_state = optc1_wait_for_state, |
300 | .set_blank_color = optc3_program_blank_color, |
301 | .did_triggered_reset_occur = optc1_did_triggered_reset_occur, |
302 | .triplebuffer_lock = optc3_triplebuffer_lock, |
303 | .triplebuffer_unlock = optc2_triplebuffer_unlock, |
304 | .enable_reset_trigger = optc1_enable_reset_trigger, |
305 | .enable_crtc_reset = optc1_enable_crtc_reset, |
306 | .disable_reset_trigger = optc1_disable_reset_trigger, |
307 | .lock = optc3_lock, |
308 | .unlock = optc1_unlock, |
309 | .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable, |
310 | .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, |
311 | .enable_optc_clock = optc1_enable_optc_clock, |
312 | .set_drr = optc32_set_drr, |
313 | .get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal, |
314 | .set_vtotal_min_max = optc3_set_vtotal_min_max, |
315 | .set_static_screen_control = optc1_set_static_screen_control, |
316 | .program_stereo = optc1_program_stereo, |
317 | .is_stereo_left_eye = optc1_is_stereo_left_eye, |
318 | .tg_init = optc3_tg_init, |
319 | .is_tg_enabled = optc1_is_tg_enabled, |
320 | .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, |
321 | .clear_optc_underflow = optc1_clear_optc_underflow, |
322 | .setup_global_swap_lock = NULL, |
323 | .get_crc = optc1_get_crc, |
324 | .configure_crc = optc1_configure_crc, |
325 | .set_dsc_config = optc3_set_dsc_config, |
326 | .get_dsc_status = optc2_get_dsc_status, |
327 | .set_dwb_source = NULL, |
328 | .set_odm_bypass = optc32_set_odm_bypass, |
329 | .set_odm_combine = optc32_set_odm_combine, |
330 | .get_odm_combine_segments = optc32_get_odm_combine_segments, |
331 | .set_h_timing_div_manual_mode = optc32_set_h_timing_div_manual_mode, |
332 | .get_optc_source = optc2_get_optc_source, |
333 | .set_out_mux = optc3_set_out_mux, |
334 | .set_drr_trigger_window = optc3_set_drr_trigger_window, |
335 | .set_vtotal_change_limit = optc3_set_vtotal_change_limit, |
336 | .set_gsl = optc2_set_gsl, |
337 | .set_gsl_source_select = optc2_set_gsl_source_select, |
338 | .set_vtg_params = optc1_set_vtg_params, |
339 | .program_manual_trigger = optc2_program_manual_trigger, |
340 | .setup_manual_trigger = optc2_setup_manual_trigger, |
341 | .get_hw_timing = optc1_get_hw_timing, |
342 | }; |
343 | |
344 | void dcn32_timing_generator_init(struct optc *optc1) |
345 | { |
346 | optc1->base.funcs = &dcn32_tg_funcs; |
347 | |
348 | optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; |
349 | optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; |
350 | |
351 | optc1->min_h_blank = 32; |
352 | optc1->min_v_blank = 3; |
353 | optc1->min_v_blank_interlace = 5; |
354 | optc1->min_h_sync_width = 4; |
355 | optc1->min_v_sync_width = 1; |
356 | } |
357 | |
358 | |