Line data Source code
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 "dm_services.h"
27 :
28 : #include "dce/dce_12_0_offset.h"
29 : #include "dce/dce_12_0_sh_mask.h"
30 : #include "soc15_hw_ip.h"
31 : #include "vega10_ip_offset.h"
32 :
33 : #include "dc_types.h"
34 : #include "dc_bios_types.h"
35 :
36 : #include "include/grph_object_id.h"
37 : #include "include/logger_interface.h"
38 : #include "dce120_timing_generator.h"
39 :
40 : #include "timing_generator.h"
41 :
42 : #define CRTC_REG_UPDATE_N(reg_name, n, ...) \
43 : generic_reg_update_soc15(tg110->base.ctx, tg110->offsets.crtc, reg_name, n, __VA_ARGS__)
44 :
45 : #define CRTC_REG_SET_N(reg_name, n, ...) \
46 : generic_reg_set_soc15(tg110->base.ctx, tg110->offsets.crtc, reg_name, n, __VA_ARGS__)
47 :
48 : #define CRTC_REG_UPDATE(reg, field, val) \
49 : CRTC_REG_UPDATE_N(reg, 1, FD(reg##__##field), val)
50 :
51 : #define CRTC_REG_UPDATE_2(reg, field1, val1, field2, val2) \
52 : CRTC_REG_UPDATE_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
53 :
54 : #define CRTC_REG_UPDATE_3(reg, field1, val1, field2, val2, field3, val3) \
55 : CRTC_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
56 :
57 : #define CRTC_REG_UPDATE_4(reg, field1, val1, field2, val2, field3, val3, field4, val4) \
58 : CRTC_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3, FD(reg##__##field4), val4)
59 :
60 : #define CRTC_REG_UPDATE_5(reg, field1, val1, field2, val2, field3, val3, field4, val4, field5, val5) \
61 : CRTC_REG_UPDATE_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3, FD(reg##__##field4), val4, FD(reg##__##field5), val5)
62 :
63 : #define CRTC_REG_SET(reg, field, val) \
64 : CRTC_REG_SET_N(reg, 1, FD(reg##__##field), val)
65 :
66 : #define CRTC_REG_SET_2(reg, field1, val1, field2, val2) \
67 : CRTC_REG_SET_N(reg, 2, FD(reg##__##field1), val1, FD(reg##__##field2), val2)
68 :
69 : #define CRTC_REG_SET_3(reg, field1, val1, field2, val2, field3, val3) \
70 : CRTC_REG_SET_N(reg, 3, FD(reg##__##field1), val1, FD(reg##__##field2), val2, FD(reg##__##field3), val3)
71 :
72 : /*
73 : *****************************************************************************
74 : * Function: is_in_vertical_blank
75 : *
76 : * @brief
77 : * check the current status of CRTC to check if we are in Vertical Blank
78 : * regioneased" state
79 : *
80 : * @return
81 : * true if currently in blank region, false otherwise
82 : *
83 : *****************************************************************************
84 : */
85 : static bool dce120_timing_generator_is_in_vertical_blank(
86 : struct timing_generator *tg)
87 : {
88 0 : uint32_t field = 0;
89 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
90 0 : uint32_t value = dm_read_reg_soc15(
91 : tg->ctx,
92 : mmCRTC0_CRTC_STATUS,
93 : tg110->offsets.crtc);
94 :
95 0 : field = get_reg_field_value(value, CRTC0_CRTC_STATUS, CRTC_V_BLANK);
96 : return field == 1;
97 : }
98 :
99 :
100 : /* determine if given timing can be supported by TG */
101 0 : static bool dce120_timing_generator_validate_timing(
102 : struct timing_generator *tg,
103 : const struct dc_crtc_timing *timing,
104 : enum signal_type signal)
105 : {
106 0 : uint32_t interlace_factor = timing->flags.INTERLACE ? 2 : 1;
107 0 : uint32_t v_blank =
108 0 : (timing->v_total - timing->v_addressable -
109 0 : timing->v_border_top - timing->v_border_bottom) *
110 : interlace_factor;
111 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
112 :
113 0 : if (!dce110_timing_generator_validate_timing(
114 : tg,
115 : timing,
116 : signal))
117 : return false;
118 :
119 :
120 0 : if (v_blank < tg110->min_v_blank ||
121 0 : timing->h_sync_width < tg110->min_h_sync_width ||
122 0 : timing->v_sync_width < tg110->min_v_sync_width)
123 : return false;
124 :
125 0 : return true;
126 : }
127 :
128 0 : static bool dce120_tg_validate_timing(struct timing_generator *tg,
129 : const struct dc_crtc_timing *timing)
130 : {
131 0 : return dce120_timing_generator_validate_timing(tg, timing, SIGNAL_TYPE_NONE);
132 : }
133 :
134 : /******** HW programming ************/
135 : /* Disable/Enable Timing Generator */
136 0 : static bool dce120_timing_generator_enable_crtc(struct timing_generator *tg)
137 : {
138 : enum bp_result result;
139 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
140 :
141 : /* Set MASTER_UPDATE_MODE to 0
142 : * This is needed for DRR, and also suggested to be default value by Syed.*/
143 :
144 0 : CRTC_REG_UPDATE(CRTC0_CRTC_MASTER_UPDATE_MODE,
145 : MASTER_UPDATE_MODE, 0);
146 :
147 0 : CRTC_REG_UPDATE(CRTC0_CRTC_MASTER_UPDATE_LOCK,
148 : UNDERFLOW_UPDATE_LOCK, 0);
149 :
150 : /* TODO API for AtomFirmware didn't change*/
151 0 : result = tg->bp->funcs->enable_crtc(tg->bp, tg110->controller_id, true);
152 :
153 0 : return result == BP_RESULT_OK;
154 : }
155 :
156 0 : static void dce120_timing_generator_set_early_control(
157 : struct timing_generator *tg,
158 : uint32_t early_cntl)
159 : {
160 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
161 :
162 0 : CRTC_REG_UPDATE(CRTC0_CRTC_CONTROL,
163 : CRTC_HBLANK_EARLY_CONTROL, early_cntl);
164 0 : }
165 :
166 : /**************** TG current status ******************/
167 :
168 : /* return the current frame counter. Used by Linux kernel DRM */
169 0 : static uint32_t dce120_timing_generator_get_vblank_counter(
170 : struct timing_generator *tg)
171 : {
172 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
173 0 : uint32_t value = dm_read_reg_soc15(
174 : tg->ctx,
175 : mmCRTC0_CRTC_STATUS_FRAME_COUNT,
176 : tg110->offsets.crtc);
177 0 : uint32_t field = get_reg_field_value(
178 : value, CRTC0_CRTC_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT);
179 :
180 0 : return field;
181 : }
182 :
183 : /* Get current H and V position */
184 0 : static void dce120_timing_generator_get_crtc_position(
185 : struct timing_generator *tg,
186 : struct crtc_position *position)
187 : {
188 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
189 0 : uint32_t value = dm_read_reg_soc15(
190 : tg->ctx,
191 : mmCRTC0_CRTC_STATUS_POSITION,
192 : tg110->offsets.crtc);
193 :
194 0 : position->horizontal_count = get_reg_field_value(value,
195 : CRTC0_CRTC_STATUS_POSITION, CRTC_HORZ_COUNT);
196 :
197 0 : position->vertical_count = get_reg_field_value(value,
198 : CRTC0_CRTC_STATUS_POSITION, CRTC_VERT_COUNT);
199 :
200 0 : value = dm_read_reg_soc15(
201 : tg->ctx,
202 : mmCRTC0_CRTC_NOM_VERT_POSITION,
203 : tg110->offsets.crtc);
204 :
205 0 : position->nominal_vcount = get_reg_field_value(value,
206 : CRTC0_CRTC_NOM_VERT_POSITION, CRTC_VERT_COUNT_NOM);
207 0 : }
208 :
209 : /* wait until TG is in beginning of vertical blank region */
210 0 : static void dce120_timing_generator_wait_for_vblank(struct timing_generator *tg)
211 : {
212 : /* We want to catch beginning of VBlank here, so if the first try are
213 : * in VBlank, we might be very close to Active, in this case wait for
214 : * another frame
215 : */
216 0 : while (dce120_timing_generator_is_in_vertical_blank(tg)) {
217 0 : if (!tg->funcs->is_counter_moving(tg)) {
218 : /* error - no point to wait if counter is not moving */
219 : break;
220 : }
221 : }
222 :
223 0 : while (!dce120_timing_generator_is_in_vertical_blank(tg)) {
224 0 : if (!tg->funcs->is_counter_moving(tg)) {
225 : /* error - no point to wait if counter is not moving */
226 : break;
227 : }
228 : }
229 0 : }
230 :
231 : /* wait until TG is in beginning of active region */
232 0 : static void dce120_timing_generator_wait_for_vactive(struct timing_generator *tg)
233 : {
234 0 : while (dce120_timing_generator_is_in_vertical_blank(tg)) {
235 0 : if (!tg->funcs->is_counter_moving(tg)) {
236 : /* error - no point to wait if counter is not moving */
237 : break;
238 : }
239 : }
240 0 : }
241 :
242 : /*********** Timing Generator Synchronization routines ****/
243 :
244 : /* Setups Global Swap Lock group, TimingServer or TimingClient*/
245 0 : static void dce120_timing_generator_setup_global_swap_lock(
246 : struct timing_generator *tg,
247 : const struct dcp_gsl_params *gsl_params)
248 : {
249 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
250 0 : uint32_t value_crtc_vtotal =
251 0 : dm_read_reg_soc15(tg->ctx,
252 : mmCRTC0_CRTC_V_TOTAL,
253 : tg110->offsets.crtc);
254 : /* Checkpoint relative to end of frame */
255 0 : uint32_t check_point =
256 : get_reg_field_value(value_crtc_vtotal,
257 : CRTC0_CRTC_V_TOTAL,
258 : CRTC_V_TOTAL);
259 :
260 :
261 0 : dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_GSL_WINDOW, tg110->offsets.crtc, 0);
262 :
263 0 : CRTC_REG_UPDATE_N(DCP0_DCP_GSL_CONTROL, 6,
264 : /* This pipe will belong to GSL Group zero. */
265 : FD(DCP0_DCP_GSL_CONTROL__DCP_GSL0_EN), 1,
266 : FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_MASTER_EN), gsl_params->gsl_master == tg->inst,
267 : FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_FORCE_DELAY), HFLIP_READY_DELAY,
268 : /* Keep signal low (pending high) during 6 lines.
269 : * Also defines minimum interval before re-checking signal. */
270 : FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_CHECK_DELAY), HFLIP_CHECK_DELAY,
271 : /* DCP_GSL_PURPOSE_SURFACE_FLIP */
272 : FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_SYNC_SOURCE), 0,
273 : FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_DELAY_SURFACE_UPDATE_PENDING), 1);
274 :
275 0 : CRTC_REG_SET_2(
276 : CRTC0_CRTC_GSL_CONTROL,
277 : CRTC_GSL_CHECK_LINE_NUM, check_point - FLIP_READY_BACK_LOOKUP,
278 : CRTC_GSL_FORCE_DELAY, VFLIP_READY_DELAY);
279 0 : }
280 :
281 : /* Clear all the register writes done by setup_global_swap_lock */
282 0 : static void dce120_timing_generator_tear_down_global_swap_lock(
283 : struct timing_generator *tg)
284 : {
285 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
286 :
287 : /* Settig HW default values from reg specs */
288 0 : CRTC_REG_SET_N(DCP0_DCP_GSL_CONTROL, 6,
289 : FD(DCP0_DCP_GSL_CONTROL__DCP_GSL0_EN), 0,
290 : FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_MASTER_EN), 0,
291 : FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_FORCE_DELAY), HFLIP_READY_DELAY,
292 : FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_HSYNC_FLIP_CHECK_DELAY), HFLIP_CHECK_DELAY,
293 : /* DCP_GSL_PURPOSE_SURFACE_FLIP */
294 : FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_SYNC_SOURCE), 0,
295 : FD(DCP0_DCP_GSL_CONTROL__DCP_GSL_DELAY_SURFACE_UPDATE_PENDING), 0);
296 :
297 0 : CRTC_REG_SET_2(CRTC0_CRTC_GSL_CONTROL,
298 : CRTC_GSL_CHECK_LINE_NUM, 0,
299 : CRTC_GSL_FORCE_DELAY, 0x2); /*TODO Why this value here ?*/
300 0 : }
301 :
302 : /* Reset slave controllers on master VSync */
303 0 : static void dce120_timing_generator_enable_reset_trigger(
304 : struct timing_generator *tg,
305 : int source)
306 : {
307 0 : enum trigger_source_select trig_src_select = TRIGGER_SOURCE_SELECT_LOGIC_ZERO;
308 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
309 0 : uint32_t rising_edge = 0;
310 0 : uint32_t falling_edge = 0;
311 : /* Setup trigger edge */
312 0 : uint32_t pol_value = dm_read_reg_soc15(
313 : tg->ctx,
314 : mmCRTC0_CRTC_V_SYNC_A_CNTL,
315 : tg110->offsets.crtc);
316 :
317 : /* Register spec has reversed definition:
318 : * 0 for positive, 1 for negative */
319 0 : if (get_reg_field_value(pol_value,
320 : CRTC0_CRTC_V_SYNC_A_CNTL,
321 : CRTC_V_SYNC_A_POL) == 0) {
322 : rising_edge = 1;
323 : } else {
324 0 : falling_edge = 1;
325 : }
326 :
327 : /* TODO What about other sources ?*/
328 0 : trig_src_select = TRIGGER_SOURCE_SELECT_GSL_GROUP0;
329 :
330 0 : CRTC_REG_UPDATE_N(CRTC0_CRTC_TRIGB_CNTL, 7,
331 : FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_SOURCE_SELECT), trig_src_select,
332 : FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_POLARITY_SELECT), TRIGGER_POLARITY_SELECT_LOGIC_ZERO,
333 : FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_RISING_EDGE_DETECT_CNTL), rising_edge,
334 : FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_FALLING_EDGE_DETECT_CNTL), falling_edge,
335 : /* send every signal */
336 : FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_FREQUENCY_SELECT), 0,
337 : /* no delay */
338 : FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_DELAY), 0,
339 : /* clear trigger status */
340 : FD(CRTC0_CRTC_TRIGB_CNTL__CRTC_TRIGB_CLEAR), 1);
341 :
342 0 : CRTC_REG_UPDATE_3(
343 : CRTC0_CRTC_FORCE_COUNT_NOW_CNTL,
344 : CRTC_FORCE_COUNT_NOW_MODE, 2,
345 : CRTC_FORCE_COUNT_NOW_TRIG_SEL, 1,
346 : CRTC_FORCE_COUNT_NOW_CLEAR, 1);
347 0 : }
348 :
349 : /* disabling trigger-reset */
350 0 : static void dce120_timing_generator_disable_reset_trigger(
351 : struct timing_generator *tg)
352 : {
353 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
354 :
355 0 : CRTC_REG_UPDATE_2(
356 : CRTC0_CRTC_FORCE_COUNT_NOW_CNTL,
357 : CRTC_FORCE_COUNT_NOW_MODE, 0,
358 : CRTC_FORCE_COUNT_NOW_CLEAR, 1);
359 :
360 0 : CRTC_REG_UPDATE_3(
361 : CRTC0_CRTC_TRIGB_CNTL,
362 : CRTC_TRIGB_SOURCE_SELECT, TRIGGER_SOURCE_SELECT_LOGIC_ZERO,
363 : CRTC_TRIGB_POLARITY_SELECT, TRIGGER_POLARITY_SELECT_LOGIC_ZERO,
364 : /* clear trigger status */
365 : CRTC_TRIGB_CLEAR, 1);
366 :
367 0 : }
368 :
369 : /* Checks whether CRTC triggered reset occurred */
370 0 : static bool dce120_timing_generator_did_triggered_reset_occur(
371 : struct timing_generator *tg)
372 : {
373 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
374 0 : uint32_t value = dm_read_reg_soc15(
375 : tg->ctx,
376 : mmCRTC0_CRTC_FORCE_COUNT_NOW_CNTL,
377 : tg110->offsets.crtc);
378 :
379 0 : return get_reg_field_value(value,
380 : CRTC0_CRTC_FORCE_COUNT_NOW_CNTL,
381 0 : CRTC_FORCE_COUNT_NOW_OCCURRED) != 0;
382 : }
383 :
384 :
385 : /******** Stuff to move to other virtual HW objects *****************/
386 : /* Move to enable accelerated mode */
387 0 : static void dce120_timing_generator_disable_vga(struct timing_generator *tg)
388 : {
389 0 : uint32_t offset = 0;
390 0 : uint32_t value = 0;
391 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
392 :
393 0 : switch (tg110->controller_id) {
394 : case CONTROLLER_ID_D0:
395 : offset = 0;
396 : break;
397 : case CONTROLLER_ID_D1:
398 : offset = mmD2VGA_CONTROL - mmD1VGA_CONTROL;
399 : break;
400 : case CONTROLLER_ID_D2:
401 : offset = mmD3VGA_CONTROL - mmD1VGA_CONTROL;
402 : break;
403 : case CONTROLLER_ID_D3:
404 : offset = mmD4VGA_CONTROL - mmD1VGA_CONTROL;
405 : break;
406 : case CONTROLLER_ID_D4:
407 : offset = mmD5VGA_CONTROL - mmD1VGA_CONTROL;
408 : break;
409 : case CONTROLLER_ID_D5:
410 : offset = mmD6VGA_CONTROL - mmD1VGA_CONTROL;
411 : break;
412 : default:
413 : break;
414 : }
415 :
416 0 : value = dm_read_reg_soc15(tg->ctx, mmD1VGA_CONTROL, offset);
417 :
418 0 : set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_MODE_ENABLE);
419 0 : set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_TIMING_SELECT);
420 0 : set_reg_field_value(
421 : value, 0, D1VGA_CONTROL, D1VGA_SYNC_POLARITY_SELECT);
422 0 : set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_OVERSCAN_COLOR_EN);
423 :
424 0 : dm_write_reg_soc15(tg->ctx, mmD1VGA_CONTROL, offset, value);
425 0 : }
426 : /* TODO: Should we move it to transform */
427 : /* Fully program CRTC timing in timing generator */
428 0 : static void dce120_timing_generator_program_blanking(
429 : struct timing_generator *tg,
430 : const struct dc_crtc_timing *timing)
431 : {
432 0 : uint32_t tmp1 = 0;
433 0 : uint32_t tmp2 = 0;
434 0 : uint32_t vsync_offset = timing->v_border_bottom +
435 0 : timing->v_front_porch;
436 0 : uint32_t v_sync_start = timing->v_addressable + vsync_offset;
437 :
438 0 : uint32_t hsync_offset = timing->h_border_right +
439 0 : timing->h_front_porch;
440 0 : uint32_t h_sync_start = timing->h_addressable + hsync_offset;
441 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
442 :
443 0 : CRTC_REG_UPDATE(
444 : CRTC0_CRTC_H_TOTAL,
445 : CRTC_H_TOTAL,
446 : timing->h_total - 1);
447 :
448 0 : CRTC_REG_UPDATE(
449 : CRTC0_CRTC_V_TOTAL,
450 : CRTC_V_TOTAL,
451 : timing->v_total - 1);
452 :
453 : /* In case of V_TOTAL_CONTROL is on, make sure V_TOTAL_MAX and
454 : * V_TOTAL_MIN are equal to V_TOTAL.
455 : */
456 0 : CRTC_REG_UPDATE(
457 : CRTC0_CRTC_V_TOTAL_MAX,
458 : CRTC_V_TOTAL_MAX,
459 : timing->v_total - 1);
460 :
461 0 : CRTC_REG_UPDATE(
462 : CRTC0_CRTC_V_TOTAL_MIN,
463 : CRTC_V_TOTAL_MIN,
464 : timing->v_total - 1);
465 :
466 0 : tmp1 = timing->h_total -
467 0 : (h_sync_start + timing->h_border_left);
468 0 : tmp2 = tmp1 + timing->h_addressable +
469 0 : timing->h_border_left + timing->h_border_right;
470 :
471 0 : CRTC_REG_UPDATE_2(
472 : CRTC0_CRTC_H_BLANK_START_END,
473 : CRTC_H_BLANK_END, tmp1,
474 : CRTC_H_BLANK_START, tmp2);
475 :
476 0 : tmp1 = timing->v_total - (v_sync_start + timing->v_border_top);
477 0 : tmp2 = tmp1 + timing->v_addressable + timing->v_border_top +
478 0 : timing->v_border_bottom;
479 :
480 0 : CRTC_REG_UPDATE_2(
481 : CRTC0_CRTC_V_BLANK_START_END,
482 : CRTC_V_BLANK_END, tmp1,
483 : CRTC_V_BLANK_START, tmp2);
484 0 : }
485 :
486 : /* TODO: Should we move it to opp? */
487 : /* Combine with below and move YUV/RGB color conversion to SW layer */
488 0 : static void dce120_timing_generator_program_blank_color(
489 : struct timing_generator *tg,
490 : const struct tg_color *black_color)
491 : {
492 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
493 :
494 0 : CRTC_REG_UPDATE_3(
495 : CRTC0_CRTC_BLACK_COLOR,
496 : CRTC_BLACK_COLOR_B_CB, black_color->color_b_cb,
497 : CRTC_BLACK_COLOR_G_Y, black_color->color_g_y,
498 : CRTC_BLACK_COLOR_R_CR, black_color->color_r_cr);
499 0 : }
500 : /* Combine with above and move YUV/RGB color conversion to SW layer */
501 0 : static void dce120_timing_generator_set_overscan_color_black(
502 : struct timing_generator *tg,
503 : const struct tg_color *color)
504 : {
505 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
506 0 : uint32_t value = 0;
507 0 : CRTC_REG_SET_3(
508 : CRTC0_CRTC_OVERSCAN_COLOR,
509 : CRTC_OVERSCAN_COLOR_BLUE, color->color_b_cb,
510 : CRTC_OVERSCAN_COLOR_GREEN, color->color_g_y,
511 : CRTC_OVERSCAN_COLOR_RED, color->color_r_cr);
512 :
513 0 : value = dm_read_reg_soc15(
514 : tg->ctx,
515 : mmCRTC0_CRTC_OVERSCAN_COLOR,
516 : tg110->offsets.crtc);
517 :
518 0 : dm_write_reg_soc15(
519 : tg->ctx,
520 : mmCRTC0_CRTC_BLACK_COLOR,
521 : tg110->offsets.crtc,
522 : value);
523 :
524 : /* This is desirable to have a constant DAC output voltage during the
525 : * blank time that is higher than the 0 volt reference level that the
526 : * DAC outputs when the NBLANK signal
527 : * is asserted low, such as for output to an analog TV. */
528 0 : dm_write_reg_soc15(
529 : tg->ctx,
530 : mmCRTC0_CRTC_BLANK_DATA_COLOR,
531 : tg110->offsets.crtc,
532 : value);
533 :
534 : /* TO DO we have to program EXT registers and we need to know LB DATA
535 : * format because it is used when more 10 , i.e. 12 bits per color
536 : *
537 : * m_mmDxCRTC_OVERSCAN_COLOR_EXT
538 : * m_mmDxCRTC_BLACK_COLOR_EXT
539 : * m_mmDxCRTC_BLANK_DATA_COLOR_EXT
540 : */
541 0 : }
542 :
543 0 : static void dce120_timing_generator_set_drr(
544 : struct timing_generator *tg,
545 : const struct drr_params *params)
546 : {
547 :
548 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
549 :
550 0 : if (params != NULL &&
551 0 : params->vertical_total_max > 0 &&
552 0 : params->vertical_total_min > 0) {
553 :
554 0 : CRTC_REG_UPDATE(
555 : CRTC0_CRTC_V_TOTAL_MIN,
556 : CRTC_V_TOTAL_MIN, params->vertical_total_min - 1);
557 0 : CRTC_REG_UPDATE(
558 : CRTC0_CRTC_V_TOTAL_MAX,
559 : CRTC_V_TOTAL_MAX, params->vertical_total_max - 1);
560 0 : CRTC_REG_SET_N(CRTC0_CRTC_V_TOTAL_CONTROL, 6,
561 : FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_V_TOTAL_MIN_SEL), 1,
562 : FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_V_TOTAL_MAX_SEL), 1,
563 : FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_FORCE_LOCK_ON_EVENT), 0,
564 : FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_FORCE_LOCK_TO_MASTER_VSYNC), 0,
565 : FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_SET_V_TOTAL_MIN_MASK_EN), 0,
566 : FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_SET_V_TOTAL_MIN_MASK), 0);
567 0 : CRTC_REG_UPDATE(
568 : CRTC0_CRTC_STATIC_SCREEN_CONTROL,
569 : CRTC_STATIC_SCREEN_EVENT_MASK,
570 : 0x180);
571 :
572 : } else {
573 0 : CRTC_REG_SET_N(CRTC0_CRTC_V_TOTAL_CONTROL, 5,
574 : FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_V_TOTAL_MIN_SEL), 0,
575 : FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_V_TOTAL_MAX_SEL), 0,
576 : FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_FORCE_LOCK_ON_EVENT), 0,
577 : FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_FORCE_LOCK_TO_MASTER_VSYNC), 0,
578 : FD(CRTC0_CRTC_V_TOTAL_CONTROL__CRTC_SET_V_TOTAL_MIN_MASK), 0);
579 0 : CRTC_REG_UPDATE(
580 : CRTC0_CRTC_V_TOTAL_MIN,
581 : CRTC_V_TOTAL_MIN, 0);
582 0 : CRTC_REG_UPDATE(
583 : CRTC0_CRTC_V_TOTAL_MAX,
584 : CRTC_V_TOTAL_MAX, 0);
585 0 : CRTC_REG_UPDATE(
586 : CRTC0_CRTC_STATIC_SCREEN_CONTROL,
587 : CRTC_STATIC_SCREEN_EVENT_MASK,
588 : 0);
589 : }
590 0 : }
591 :
592 0 : static void dce120_timing_generator_get_crtc_scanoutpos(
593 : struct timing_generator *tg,
594 : uint32_t *v_blank_start,
595 : uint32_t *v_blank_end,
596 : uint32_t *h_position,
597 : uint32_t *v_position)
598 : {
599 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
600 : struct crtc_position position;
601 :
602 0 : uint32_t v_blank_start_end = dm_read_reg_soc15(
603 : tg->ctx,
604 : mmCRTC0_CRTC_V_BLANK_START_END,
605 : tg110->offsets.crtc);
606 :
607 0 : *v_blank_start = get_reg_field_value(v_blank_start_end,
608 : CRTC0_CRTC_V_BLANK_START_END,
609 : CRTC_V_BLANK_START);
610 0 : *v_blank_end = get_reg_field_value(v_blank_start_end,
611 : CRTC0_CRTC_V_BLANK_START_END,
612 : CRTC_V_BLANK_END);
613 :
614 0 : dce120_timing_generator_get_crtc_position(
615 : tg, &position);
616 :
617 0 : *h_position = position.horizontal_count;
618 0 : *v_position = position.vertical_count;
619 0 : }
620 :
621 0 : static void dce120_timing_generator_enable_advanced_request(
622 : struct timing_generator *tg,
623 : bool enable,
624 : const struct dc_crtc_timing *timing)
625 : {
626 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
627 0 : uint32_t v_sync_width_and_b_porch =
628 0 : timing->v_total - timing->v_addressable -
629 0 : timing->v_border_bottom - timing->v_front_porch;
630 0 : uint32_t value = dm_read_reg_soc15(
631 : tg->ctx,
632 : mmCRTC0_CRTC_START_LINE_CONTROL,
633 : tg110->offsets.crtc);
634 :
635 0 : set_reg_field_value(
636 : value,
637 : enable ? 0 : 1,
638 : CRTC0_CRTC_START_LINE_CONTROL,
639 : CRTC_LEGACY_REQUESTOR_EN);
640 :
641 : /* Program advanced line position acc.to the best case from fetching data perspective to hide MC latency
642 : * and prefilling Line Buffer in V Blank (to 10 lines as LB can store max 10 lines)
643 : */
644 0 : if (v_sync_width_and_b_porch > 10)
645 0 : v_sync_width_and_b_porch = 10;
646 :
647 0 : set_reg_field_value(
648 : value,
649 : v_sync_width_and_b_porch,
650 : CRTC0_CRTC_START_LINE_CONTROL,
651 : CRTC_ADVANCED_START_LINE_POSITION);
652 :
653 0 : dm_write_reg_soc15(tg->ctx,
654 : mmCRTC0_CRTC_START_LINE_CONTROL,
655 : tg110->offsets.crtc,
656 : value);
657 0 : }
658 :
659 0 : static void dce120_tg_program_blank_color(struct timing_generator *tg,
660 : const struct tg_color *black_color)
661 : {
662 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
663 0 : uint32_t value = 0;
664 :
665 0 : CRTC_REG_UPDATE_3(
666 : CRTC0_CRTC_BLACK_COLOR,
667 : CRTC_BLACK_COLOR_B_CB, black_color->color_b_cb,
668 : CRTC_BLACK_COLOR_G_Y, black_color->color_g_y,
669 : CRTC_BLACK_COLOR_R_CR, black_color->color_r_cr);
670 :
671 0 : value = dm_read_reg_soc15(
672 : tg->ctx,
673 : mmCRTC0_CRTC_BLACK_COLOR,
674 : tg110->offsets.crtc);
675 0 : dm_write_reg_soc15(
676 : tg->ctx,
677 : mmCRTC0_CRTC_BLANK_DATA_COLOR,
678 : tg110->offsets.crtc,
679 : value);
680 0 : }
681 :
682 0 : static void dce120_tg_set_overscan_color(struct timing_generator *tg,
683 : const struct tg_color *overscan_color)
684 : {
685 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
686 :
687 0 : CRTC_REG_SET_3(
688 : CRTC0_CRTC_OVERSCAN_COLOR,
689 : CRTC_OVERSCAN_COLOR_BLUE, overscan_color->color_b_cb,
690 : CRTC_OVERSCAN_COLOR_GREEN, overscan_color->color_g_y,
691 : CRTC_OVERSCAN_COLOR_RED, overscan_color->color_r_cr);
692 0 : }
693 :
694 0 : static void dce120_tg_program_timing(struct timing_generator *tg,
695 : const struct dc_crtc_timing *timing,
696 : int vready_offset,
697 : int vstartup_start,
698 : int vupdate_offset,
699 : int vupdate_width,
700 : const enum signal_type signal,
701 : bool use_vbios)
702 : {
703 0 : if (use_vbios)
704 0 : dce110_timing_generator_program_timing_generator(tg, timing);
705 : else
706 0 : dce120_timing_generator_program_blanking(tg, timing);
707 0 : }
708 :
709 0 : static bool dce120_tg_is_blanked(struct timing_generator *tg)
710 : {
711 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
712 0 : uint32_t value = dm_read_reg_soc15(
713 : tg->ctx,
714 : mmCRTC0_CRTC_BLANK_CONTROL,
715 : tg110->offsets.crtc);
716 :
717 0 : if (get_reg_field_value(
718 : value,
719 : CRTC0_CRTC_BLANK_CONTROL,
720 0 : CRTC_BLANK_DATA_EN) == 1 &&
721 0 : get_reg_field_value(
722 : value,
723 : CRTC0_CRTC_BLANK_CONTROL,
724 : CRTC_CURRENT_BLANK_STATE) == 1)
725 : return true;
726 :
727 : return false;
728 : }
729 :
730 0 : static void dce120_tg_set_blank(struct timing_generator *tg,
731 : bool enable_blanking)
732 : {
733 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
734 :
735 0 : CRTC_REG_SET(
736 : CRTC0_CRTC_DOUBLE_BUFFER_CONTROL,
737 : CRTC_BLANK_DATA_DOUBLE_BUFFER_EN, 1);
738 :
739 0 : if (enable_blanking)
740 0 : CRTC_REG_SET(CRTC0_CRTC_BLANK_CONTROL, CRTC_BLANK_DATA_EN, 1);
741 : else
742 0 : dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_BLANK_CONTROL,
743 : tg110->offsets.crtc, 0);
744 0 : }
745 :
746 : bool dce120_tg_validate_timing(struct timing_generator *tg,
747 : const struct dc_crtc_timing *timing);
748 :
749 0 : static void dce120_tg_wait_for_state(struct timing_generator *tg,
750 : enum crtc_state state)
751 : {
752 0 : switch (state) {
753 : case CRTC_STATE_VBLANK:
754 0 : dce120_timing_generator_wait_for_vblank(tg);
755 0 : break;
756 :
757 : case CRTC_STATE_VACTIVE:
758 0 : dce120_timing_generator_wait_for_vactive(tg);
759 0 : break;
760 :
761 : default:
762 : break;
763 : }
764 0 : }
765 :
766 0 : static void dce120_tg_set_colors(struct timing_generator *tg,
767 : const struct tg_color *blank_color,
768 : const struct tg_color *overscan_color)
769 : {
770 0 : if (blank_color != NULL)
771 0 : dce120_tg_program_blank_color(tg, blank_color);
772 :
773 0 : if (overscan_color != NULL)
774 0 : dce120_tg_set_overscan_color(tg, overscan_color);
775 0 : }
776 :
777 0 : static void dce120_timing_generator_set_static_screen_control(
778 : struct timing_generator *tg,
779 : uint32_t event_triggers,
780 : uint32_t num_frames)
781 : {
782 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
783 :
784 : // By register spec, it only takes 8 bit value
785 0 : if (num_frames > 0xFF)
786 0 : num_frames = 0xFF;
787 :
788 0 : CRTC_REG_UPDATE_2(CRTC0_CRTC_STATIC_SCREEN_CONTROL,
789 : CRTC_STATIC_SCREEN_EVENT_MASK, event_triggers,
790 : CRTC_STATIC_SCREEN_FRAME_COUNT, num_frames);
791 0 : }
792 :
793 0 : static void dce120_timing_generator_set_test_pattern(
794 : struct timing_generator *tg,
795 : /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode'
796 : * because this is not DP-specific (which is probably somewhere in DP
797 : * encoder) */
798 : enum controller_dp_test_pattern test_pattern,
799 : enum dc_color_depth color_depth)
800 : {
801 0 : struct dc_context *ctx = tg->ctx;
802 : uint32_t value;
803 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
804 : enum test_pattern_color_format bit_depth;
805 : enum test_pattern_dyn_range dyn_range;
806 : enum test_pattern_mode mode;
807 : /* color ramp generator mixes 16-bits color */
808 0 : uint32_t src_bpc = 16;
809 : /* requested bpc */
810 : uint32_t dst_bpc;
811 : uint32_t index;
812 : /* RGB values of the color bars.
813 : * Produce two RGB colors: RGB0 - white (all Fs)
814 : * and RGB1 - black (all 0s)
815 : * (three RGB components for two colors)
816 : */
817 0 : uint16_t src_color[6] = {0xFFFF, 0xFFFF, 0xFFFF, 0x0000,
818 : 0x0000, 0x0000};
819 : /* dest color (converted to the specified color format) */
820 : uint16_t dst_color[6];
821 : uint32_t inc_base;
822 :
823 : /* translate to bit depth */
824 : switch (color_depth) {
825 : case COLOR_DEPTH_666:
826 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_6;
827 : break;
828 : case COLOR_DEPTH_888:
829 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8;
830 : break;
831 : case COLOR_DEPTH_101010:
832 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_10;
833 : break;
834 : case COLOR_DEPTH_121212:
835 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_12;
836 : break;
837 : default:
838 : bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8;
839 : break;
840 : }
841 :
842 0 : switch (test_pattern) {
843 : case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES:
844 : case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA:
845 : {
846 0 : dyn_range = (test_pattern ==
847 : CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA ?
848 0 : TEST_PATTERN_DYN_RANGE_CEA :
849 : TEST_PATTERN_DYN_RANGE_VESA);
850 0 : mode = TEST_PATTERN_MODE_COLORSQUARES_RGB;
851 :
852 0 : CRTC_REG_UPDATE_2(CRTC0_CRTC_TEST_PATTERN_PARAMETERS,
853 : CRTC_TEST_PATTERN_VRES, 6,
854 : CRTC_TEST_PATTERN_HRES, 6);
855 :
856 0 : CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL,
857 : CRTC_TEST_PATTERN_EN, 1,
858 : CRTC_TEST_PATTERN_MODE, mode,
859 : CRTC_TEST_PATTERN_DYNAMIC_RANGE, dyn_range,
860 : CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth);
861 : }
862 0 : break;
863 :
864 : case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS:
865 : case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS:
866 : {
867 0 : mode = (test_pattern ==
868 : CONTROLLER_DP_TEST_PATTERN_VERTICALBARS ?
869 0 : TEST_PATTERN_MODE_VERTICALBARS :
870 : TEST_PATTERN_MODE_HORIZONTALBARS);
871 :
872 : switch (bit_depth) {
873 : case TEST_PATTERN_COLOR_FORMAT_BPC_6:
874 : dst_bpc = 6;
875 : break;
876 : case TEST_PATTERN_COLOR_FORMAT_BPC_8:
877 : dst_bpc = 8;
878 : break;
879 : case TEST_PATTERN_COLOR_FORMAT_BPC_10:
880 : dst_bpc = 10;
881 : break;
882 : default:
883 : dst_bpc = 8;
884 : break;
885 : }
886 :
887 : /* adjust color to the required colorFormat */
888 0 : for (index = 0; index < 6; index++) {
889 : /* dst = 2^dstBpc * src / 2^srcBpc = src >>
890 : * (srcBpc - dstBpc);
891 : */
892 0 : dst_color[index] =
893 0 : src_color[index] >> (src_bpc - dst_bpc);
894 : /* CRTC_TEST_PATTERN_DATA has 16 bits,
895 : * lowest 6 are hardwired to ZERO
896 : * color bits should be left aligned aligned to MSB
897 : * XXXXXXXXXX000000 for 10 bit,
898 : * XXXXXXXX00000000 for 8 bit and XXXXXX0000000000 for 6
899 : */
900 0 : dst_color[index] <<= (16 - dst_bpc);
901 : }
902 :
903 0 : dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_PARAMETERS, tg110->offsets.crtc, 0);
904 :
905 : /* We have to write the mask before data, similar to pipeline.
906 : * For example, for 8 bpc, if we want RGB0 to be magenta,
907 : * and RGB1 to be cyan,
908 : * we need to make 7 writes:
909 : * MASK DATA
910 : * 000001 00000000 00000000 set mask to R0
911 : * 000010 11111111 00000000 R0 255, 0xFF00, set mask to G0
912 : * 000100 00000000 00000000 G0 0, 0x0000, set mask to B0
913 : * 001000 11111111 00000000 B0 255, 0xFF00, set mask to R1
914 : * 010000 00000000 00000000 R1 0, 0x0000, set mask to G1
915 : * 100000 11111111 00000000 G1 255, 0xFF00, set mask to B1
916 : * 100000 11111111 00000000 B1 255, 0xFF00
917 : *
918 : * we will make a loop of 6 in which we prepare the mask,
919 : * then write, then prepare the color for next write.
920 : * first iteration will write mask only,
921 : * but each next iteration color prepared in
922 : * previous iteration will be written within new mask,
923 : * the last component will written separately,
924 : * mask is not changing between 6th and 7th write
925 : * and color will be prepared by last iteration
926 : */
927 :
928 : /* write color, color values mask in CRTC_TEST_PATTERN_MASK
929 : * is B1, G1, R1, B0, G0, R0
930 : */
931 0 : value = 0;
932 0 : for (index = 0; index < 6; index++) {
933 : /* prepare color mask, first write PATTERN_DATA
934 : * will have all zeros
935 : */
936 0 : set_reg_field_value(
937 : value,
938 : (1 << index),
939 : CRTC0_CRTC_TEST_PATTERN_COLOR,
940 : CRTC_TEST_PATTERN_MASK);
941 : /* write color component */
942 0 : dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value);
943 : /* prepare next color component,
944 : * will be written in the next iteration
945 : */
946 0 : set_reg_field_value(
947 : value,
948 : dst_color[index],
949 : CRTC0_CRTC_TEST_PATTERN_COLOR,
950 : CRTC_TEST_PATTERN_DATA);
951 : }
952 : /* write last color component,
953 : * it's been already prepared in the loop
954 : */
955 0 : dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value);
956 :
957 : /* enable test pattern */
958 0 : CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL,
959 : CRTC_TEST_PATTERN_EN, 1,
960 : CRTC_TEST_PATTERN_MODE, mode,
961 : CRTC_TEST_PATTERN_DYNAMIC_RANGE, 0,
962 : CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth);
963 : }
964 0 : break;
965 :
966 : case CONTROLLER_DP_TEST_PATTERN_COLORRAMP:
967 : {
968 0 : mode = (bit_depth ==
969 : TEST_PATTERN_COLOR_FORMAT_BPC_10 ?
970 0 : TEST_PATTERN_MODE_DUALRAMP_RGB :
971 : TEST_PATTERN_MODE_SINGLERAMP_RGB);
972 :
973 : switch (bit_depth) {
974 : case TEST_PATTERN_COLOR_FORMAT_BPC_6:
975 : dst_bpc = 6;
976 : break;
977 : case TEST_PATTERN_COLOR_FORMAT_BPC_8:
978 : dst_bpc = 8;
979 : break;
980 : case TEST_PATTERN_COLOR_FORMAT_BPC_10:
981 : dst_bpc = 10;
982 : break;
983 : default:
984 : dst_bpc = 8;
985 : break;
986 : }
987 :
988 : /* increment for the first ramp for one color gradation
989 : * 1 gradation for 6-bit color is 2^10
990 : * gradations in 16-bit color
991 : */
992 0 : inc_base = (src_bpc - dst_bpc);
993 :
994 0 : switch (bit_depth) {
995 : case TEST_PATTERN_COLOR_FORMAT_BPC_6:
996 : {
997 0 : CRTC_REG_UPDATE_5(CRTC0_CRTC_TEST_PATTERN_PARAMETERS,
998 : CRTC_TEST_PATTERN_INC0, inc_base,
999 : CRTC_TEST_PATTERN_INC1, 0,
1000 : CRTC_TEST_PATTERN_HRES, 6,
1001 : CRTC_TEST_PATTERN_VRES, 6,
1002 : CRTC_TEST_PATTERN_RAMP0_OFFSET, 0);
1003 : }
1004 0 : break;
1005 : case TEST_PATTERN_COLOR_FORMAT_BPC_8:
1006 : {
1007 0 : CRTC_REG_UPDATE_5(CRTC0_CRTC_TEST_PATTERN_PARAMETERS,
1008 : CRTC_TEST_PATTERN_INC0, inc_base,
1009 : CRTC_TEST_PATTERN_INC1, 0,
1010 : CRTC_TEST_PATTERN_HRES, 8,
1011 : CRTC_TEST_PATTERN_VRES, 6,
1012 : CRTC_TEST_PATTERN_RAMP0_OFFSET, 0);
1013 : }
1014 0 : break;
1015 : case TEST_PATTERN_COLOR_FORMAT_BPC_10:
1016 : {
1017 0 : CRTC_REG_UPDATE_5(CRTC0_CRTC_TEST_PATTERN_PARAMETERS,
1018 : CRTC_TEST_PATTERN_INC0, inc_base,
1019 : CRTC_TEST_PATTERN_INC1, inc_base + 2,
1020 : CRTC_TEST_PATTERN_HRES, 8,
1021 : CRTC_TEST_PATTERN_VRES, 5,
1022 : CRTC_TEST_PATTERN_RAMP0_OFFSET, 384 << 6);
1023 : }
1024 0 : break;
1025 : default:
1026 : break;
1027 : }
1028 :
1029 0 : dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, 0);
1030 :
1031 : /* enable test pattern */
1032 0 : dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_CONTROL, tg110->offsets.crtc, 0);
1033 :
1034 0 : CRTC_REG_UPDATE_4(CRTC0_CRTC_TEST_PATTERN_CONTROL,
1035 : CRTC_TEST_PATTERN_EN, 1,
1036 : CRTC_TEST_PATTERN_MODE, mode,
1037 : CRTC_TEST_PATTERN_DYNAMIC_RANGE, 0,
1038 : CRTC_TEST_PATTERN_COLOR_FORMAT, bit_depth);
1039 : }
1040 0 : break;
1041 : case CONTROLLER_DP_TEST_PATTERN_VIDEOMODE:
1042 : {
1043 0 : value = 0;
1044 0 : dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_CONTROL, tg110->offsets.crtc, value);
1045 0 : dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value);
1046 0 : dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_PARAMETERS, tg110->offsets.crtc, value);
1047 : }
1048 0 : break;
1049 : default:
1050 : break;
1051 : }
1052 0 : }
1053 :
1054 0 : static bool dce120_arm_vert_intr(
1055 : struct timing_generator *tg,
1056 : uint8_t width)
1057 : {
1058 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1059 : uint32_t v_blank_start, v_blank_end, h_position, v_position;
1060 :
1061 0 : tg->funcs->get_scanoutpos(
1062 : tg,
1063 : &v_blank_start,
1064 : &v_blank_end,
1065 : &h_position,
1066 : &v_position);
1067 :
1068 0 : if (v_blank_start == 0 || v_blank_end == 0)
1069 : return false;
1070 :
1071 0 : CRTC_REG_SET_2(
1072 : CRTC0_CRTC_VERTICAL_INTERRUPT0_POSITION,
1073 : CRTC_VERTICAL_INTERRUPT0_LINE_START, v_blank_start,
1074 : CRTC_VERTICAL_INTERRUPT0_LINE_END, v_blank_start + width);
1075 :
1076 0 : return true;
1077 : }
1078 :
1079 :
1080 0 : static bool dce120_is_tg_enabled(struct timing_generator *tg)
1081 : {
1082 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1083 : uint32_t value, field;
1084 :
1085 0 : value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CONTROL,
1086 : tg110->offsets.crtc);
1087 0 : field = get_reg_field_value(value, CRTC0_CRTC_CONTROL,
1088 : CRTC_CURRENT_MASTER_EN_STATE);
1089 :
1090 0 : return field == 1;
1091 : }
1092 :
1093 0 : static bool dce120_configure_crc(struct timing_generator *tg,
1094 : const struct crc_params *params)
1095 : {
1096 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1097 :
1098 : /* Cannot configure crc on a CRTC that is disabled */
1099 0 : if (!dce120_is_tg_enabled(tg))
1100 : return false;
1101 :
1102 : /* First, disable CRC before we configure it. */
1103 0 : dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC_CNTL,
1104 : tg110->offsets.crtc, 0);
1105 :
1106 0 : if (!params->enable)
1107 : return true;
1108 :
1109 : /* Program frame boundaries */
1110 : /* Window A x axis start and end. */
1111 0 : CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWA_X_CONTROL,
1112 : CRTC_CRC0_WINDOWA_X_START, params->windowa_x_start,
1113 : CRTC_CRC0_WINDOWA_X_END, params->windowa_x_end);
1114 :
1115 : /* Window A y axis start and end. */
1116 0 : CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWA_Y_CONTROL,
1117 : CRTC_CRC0_WINDOWA_Y_START, params->windowa_y_start,
1118 : CRTC_CRC0_WINDOWA_Y_END, params->windowa_y_end);
1119 :
1120 : /* Window B x axis start and end. */
1121 0 : CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWB_X_CONTROL,
1122 : CRTC_CRC0_WINDOWB_X_START, params->windowb_x_start,
1123 : CRTC_CRC0_WINDOWB_X_END, params->windowb_x_end);
1124 :
1125 : /* Window B y axis start and end. */
1126 0 : CRTC_REG_UPDATE_2(CRTC0_CRTC_CRC0_WINDOWB_Y_CONTROL,
1127 : CRTC_CRC0_WINDOWB_Y_START, params->windowb_y_start,
1128 : CRTC_CRC0_WINDOWB_Y_END, params->windowb_y_end);
1129 :
1130 : /* Set crc mode and selection, and enable. Only using CRC0*/
1131 0 : CRTC_REG_UPDATE_3(CRTC0_CRTC_CRC_CNTL,
1132 : CRTC_CRC_EN, params->continuous_mode ? 1 : 0,
1133 : CRTC_CRC0_SELECT, params->selection,
1134 : CRTC_CRC_EN, 1);
1135 :
1136 0 : return true;
1137 : }
1138 :
1139 0 : static bool dce120_get_crc(struct timing_generator *tg, uint32_t *r_cr,
1140 : uint32_t *g_y, uint32_t *b_cb)
1141 : {
1142 0 : struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
1143 : uint32_t value, field;
1144 :
1145 0 : value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC_CNTL,
1146 : tg110->offsets.crtc);
1147 0 : field = get_reg_field_value(value, CRTC0_CRTC_CRC_CNTL, CRTC_CRC_EN);
1148 :
1149 : /* Early return if CRC is not enabled for this CRTC */
1150 0 : if (!field)
1151 : return false;
1152 :
1153 0 : value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC0_DATA_RG,
1154 : tg110->offsets.crtc);
1155 0 : *r_cr = get_reg_field_value(value, CRTC0_CRTC_CRC0_DATA_RG, CRC0_R_CR);
1156 0 : *g_y = get_reg_field_value(value, CRTC0_CRTC_CRC0_DATA_RG, CRC0_G_Y);
1157 :
1158 0 : value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC0_DATA_B,
1159 : tg110->offsets.crtc);
1160 0 : *b_cb = get_reg_field_value(value, CRTC0_CRTC_CRC0_DATA_B, CRC0_B_CB);
1161 :
1162 0 : return true;
1163 : }
1164 :
1165 : static const struct timing_generator_funcs dce120_tg_funcs = {
1166 : .validate_timing = dce120_tg_validate_timing,
1167 : .program_timing = dce120_tg_program_timing,
1168 : .enable_crtc = dce120_timing_generator_enable_crtc,
1169 : .disable_crtc = dce110_timing_generator_disable_crtc,
1170 : /* used by enable_timing_synchronization. Not need for FPGA */
1171 : .is_counter_moving = dce110_timing_generator_is_counter_moving,
1172 : /* never be called */
1173 : .get_position = dce120_timing_generator_get_crtc_position,
1174 : .get_frame_count = dce120_timing_generator_get_vblank_counter,
1175 : .get_scanoutpos = dce120_timing_generator_get_crtc_scanoutpos,
1176 : .set_early_control = dce120_timing_generator_set_early_control,
1177 : /* used by enable_timing_synchronization. Not need for FPGA */
1178 : .wait_for_state = dce120_tg_wait_for_state,
1179 : .set_blank = dce120_tg_set_blank,
1180 : .is_blanked = dce120_tg_is_blanked,
1181 : /* never be called */
1182 : .set_colors = dce120_tg_set_colors,
1183 : .set_overscan_blank_color = dce120_timing_generator_set_overscan_color_black,
1184 : .set_blank_color = dce120_timing_generator_program_blank_color,
1185 : .disable_vga = dce120_timing_generator_disable_vga,
1186 : .did_triggered_reset_occur = dce120_timing_generator_did_triggered_reset_occur,
1187 : .setup_global_swap_lock = dce120_timing_generator_setup_global_swap_lock,
1188 : .enable_reset_trigger = dce120_timing_generator_enable_reset_trigger,
1189 : .disable_reset_trigger = dce120_timing_generator_disable_reset_trigger,
1190 : .tear_down_global_swap_lock = dce120_timing_generator_tear_down_global_swap_lock,
1191 : .enable_advanced_request = dce120_timing_generator_enable_advanced_request,
1192 : .set_drr = dce120_timing_generator_set_drr,
1193 : .get_last_used_drr_vtotal = NULL,
1194 : .set_static_screen_control = dce120_timing_generator_set_static_screen_control,
1195 : .set_test_pattern = dce120_timing_generator_set_test_pattern,
1196 : .arm_vert_intr = dce120_arm_vert_intr,
1197 : .is_tg_enabled = dce120_is_tg_enabled,
1198 : .configure_crc = dce120_configure_crc,
1199 : .get_crc = dce120_get_crc,
1200 : };
1201 :
1202 :
1203 0 : void dce120_timing_generator_construct(
1204 : struct dce110_timing_generator *tg110,
1205 : struct dc_context *ctx,
1206 : uint32_t instance,
1207 : const struct dce110_timing_generator_offsets *offsets)
1208 : {
1209 0 : tg110->controller_id = CONTROLLER_ID_D0 + instance;
1210 0 : tg110->base.inst = instance;
1211 :
1212 0 : tg110->offsets = *offsets;
1213 :
1214 0 : tg110->base.funcs = &dce120_tg_funcs;
1215 :
1216 0 : tg110->base.ctx = ctx;
1217 0 : tg110->base.bp = ctx->dc_bios;
1218 :
1219 0 : tg110->max_h_total = CRTC0_CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1;
1220 0 : tg110->max_v_total = CRTC0_CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1;
1221 :
1222 : /*//CRTC requires a minimum HBLANK = 32 pixels and o
1223 : * Minimum HSYNC = 8 pixels*/
1224 0 : tg110->min_h_blank = 32;
1225 : /*DCE12_CRTC_Block_ARch.doc*/
1226 0 : tg110->min_h_front_porch = 0;
1227 0 : tg110->min_h_back_porch = 0;
1228 :
1229 0 : tg110->min_h_sync_width = 4;
1230 0 : tg110->min_v_sync_width = 1;
1231 0 : tg110->min_v_blank = 3;
1232 0 : }
|