cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dce120_timing_generator.c (38275B)


      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 */
     85static bool dce120_timing_generator_is_in_vertical_blank(
     86		struct timing_generator *tg)
     87{
     88	uint32_t field = 0;
     89	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
     90	uint32_t value = dm_read_reg_soc15(
     91					tg->ctx,
     92					mmCRTC0_CRTC_STATUS,
     93					tg110->offsets.crtc);
     94
     95	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 */
    101static 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	uint32_t interlace_factor = timing->flags.INTERLACE ? 2 : 1;
    107	uint32_t v_blank =
    108					(timing->v_total - timing->v_addressable -
    109					timing->v_border_top - timing->v_border_bottom) *
    110					interlace_factor;
    111	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    112
    113	if (!dce110_timing_generator_validate_timing(
    114					tg,
    115					timing,
    116					signal))
    117		return false;
    118
    119
    120	if (v_blank < tg110->min_v_blank	||
    121		 timing->h_sync_width  < tg110->min_h_sync_width ||
    122		 timing->v_sync_width  < tg110->min_v_sync_width)
    123		return false;
    124
    125	return true;
    126}
    127
    128static bool dce120_tg_validate_timing(struct timing_generator *tg,
    129	const struct dc_crtc_timing *timing)
    130{
    131	return dce120_timing_generator_validate_timing(tg, timing, SIGNAL_TYPE_NONE);
    132}
    133
    134/******** HW programming ************/
    135/* Disable/Enable Timing Generator */
    136static bool dce120_timing_generator_enable_crtc(struct timing_generator *tg)
    137{
    138	enum bp_result result;
    139	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	CRTC_REG_UPDATE(CRTC0_CRTC_MASTER_UPDATE_MODE,
    145			MASTER_UPDATE_MODE, 0);
    146
    147	CRTC_REG_UPDATE(CRTC0_CRTC_MASTER_UPDATE_LOCK,
    148			UNDERFLOW_UPDATE_LOCK, 0);
    149
    150	/* TODO API for AtomFirmware didn't change*/
    151	result = tg->bp->funcs->enable_crtc(tg->bp, tg110->controller_id, true);
    152
    153	return result == BP_RESULT_OK;
    154}
    155
    156static void dce120_timing_generator_set_early_control(
    157		struct timing_generator *tg,
    158		uint32_t early_cntl)
    159{
    160	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    161
    162	CRTC_REG_UPDATE(CRTC0_CRTC_CONTROL,
    163			CRTC_HBLANK_EARLY_CONTROL, early_cntl);
    164}
    165
    166/**************** TG current status ******************/
    167
    168/* return the current frame counter. Used by Linux kernel DRM */
    169static uint32_t dce120_timing_generator_get_vblank_counter(
    170		struct timing_generator *tg)
    171{
    172	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    173	uint32_t value = dm_read_reg_soc15(
    174				tg->ctx,
    175				mmCRTC0_CRTC_STATUS_FRAME_COUNT,
    176				tg110->offsets.crtc);
    177	uint32_t field = get_reg_field_value(
    178				value, CRTC0_CRTC_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT);
    179
    180	return field;
    181}
    182
    183/* Get current H and V position */
    184static void dce120_timing_generator_get_crtc_position(
    185	struct timing_generator *tg,
    186	struct crtc_position *position)
    187{
    188	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    189	uint32_t value = dm_read_reg_soc15(
    190				tg->ctx,
    191				mmCRTC0_CRTC_STATUS_POSITION,
    192				tg110->offsets.crtc);
    193
    194	position->horizontal_count = get_reg_field_value(value,
    195			CRTC0_CRTC_STATUS_POSITION, CRTC_HORZ_COUNT);
    196
    197	position->vertical_count = get_reg_field_value(value,
    198			CRTC0_CRTC_STATUS_POSITION, CRTC_VERT_COUNT);
    199
    200	value = dm_read_reg_soc15(
    201				tg->ctx,
    202				mmCRTC0_CRTC_NOM_VERT_POSITION,
    203				tg110->offsets.crtc);
    204
    205	position->nominal_vcount = get_reg_field_value(value,
    206			CRTC0_CRTC_NOM_VERT_POSITION, CRTC_VERT_COUNT_NOM);
    207}
    208
    209/* wait until TG is in beginning of vertical blank region */
    210static 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	while (dce120_timing_generator_is_in_vertical_blank(tg)) {
    217		if (!tg->funcs->is_counter_moving(tg)) {
    218			/* error - no point to wait if counter is not moving */
    219			break;
    220		}
    221	}
    222
    223	while (!dce120_timing_generator_is_in_vertical_blank(tg)) {
    224		if (!tg->funcs->is_counter_moving(tg)) {
    225			/* error - no point to wait if counter is not moving */
    226			break;
    227		}
    228	}
    229}
    230
    231/* wait until TG is in beginning of active region */
    232static void dce120_timing_generator_wait_for_vactive(struct timing_generator *tg)
    233{
    234	while (dce120_timing_generator_is_in_vertical_blank(tg)) {
    235		if (!tg->funcs->is_counter_moving(tg)) {
    236			/* error - no point to wait if counter is not moving */
    237			break;
    238		}
    239	}
    240}
    241
    242/*********** Timing Generator Synchronization routines ****/
    243
    244/* Setups Global Swap Lock group, TimingServer or TimingClient*/
    245static void dce120_timing_generator_setup_global_swap_lock(
    246	struct timing_generator *tg,
    247	const struct dcp_gsl_params *gsl_params)
    248{
    249	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    250	uint32_t value_crtc_vtotal =
    251							dm_read_reg_soc15(tg->ctx,
    252							mmCRTC0_CRTC_V_TOTAL,
    253							tg110->offsets.crtc);
    254	/* Checkpoint relative to end of frame */
    255	uint32_t check_point =
    256							get_reg_field_value(value_crtc_vtotal,
    257							CRTC0_CRTC_V_TOTAL,
    258							CRTC_V_TOTAL);
    259
    260
    261	dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_GSL_WINDOW, tg110->offsets.crtc, 0);
    262
    263	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	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}
    280
    281/* Clear all the register writes done by setup_global_swap_lock */
    282static void dce120_timing_generator_tear_down_global_swap_lock(
    283	struct timing_generator *tg)
    284{
    285	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    286
    287	/* Settig HW default values from reg specs */
    288	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	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}
    301
    302/* Reset slave controllers on master VSync */
    303static void dce120_timing_generator_enable_reset_trigger(
    304	struct timing_generator *tg,
    305	int source)
    306{
    307	enum trigger_source_select trig_src_select = TRIGGER_SOURCE_SELECT_LOGIC_ZERO;
    308	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    309	uint32_t rising_edge = 0;
    310	uint32_t falling_edge = 0;
    311	/* Setup trigger edge */
    312	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	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		falling_edge = 1;
    325	}
    326
    327	/* TODO What about other sources ?*/
    328	trig_src_select = TRIGGER_SOURCE_SELECT_GSL_GROUP0;
    329
    330	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	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}
    348
    349/* disabling trigger-reset */
    350static void dce120_timing_generator_disable_reset_trigger(
    351	struct timing_generator *tg)
    352{
    353	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    354
    355	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	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}
    368
    369/* Checks whether CRTC triggered reset occurred */
    370static bool dce120_timing_generator_did_triggered_reset_occur(
    371	struct timing_generator *tg)
    372{
    373	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    374	uint32_t value = dm_read_reg_soc15(
    375			tg->ctx,
    376			mmCRTC0_CRTC_FORCE_COUNT_NOW_CNTL,
    377			tg110->offsets.crtc);
    378
    379	return get_reg_field_value(value,
    380			CRTC0_CRTC_FORCE_COUNT_NOW_CNTL,
    381			CRTC_FORCE_COUNT_NOW_OCCURRED) != 0;
    382}
    383
    384
    385/******** Stuff to move to other virtual HW objects *****************/
    386/* Move to enable accelerated mode */
    387static void dce120_timing_generator_disable_vga(struct timing_generator *tg)
    388{
    389	uint32_t offset = 0;
    390	uint32_t value = 0;
    391	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    392
    393	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	value = dm_read_reg_soc15(tg->ctx, mmD1VGA_CONTROL, offset);
    417
    418	set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_MODE_ENABLE);
    419	set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_TIMING_SELECT);
    420	set_reg_field_value(
    421			value, 0, D1VGA_CONTROL, D1VGA_SYNC_POLARITY_SELECT);
    422	set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_OVERSCAN_COLOR_EN);
    423
    424	dm_write_reg_soc15(tg->ctx, mmD1VGA_CONTROL, offset, value);
    425}
    426/* TODO: Should we move it to transform */
    427/* Fully program CRTC timing in timing generator */
    428static void dce120_timing_generator_program_blanking(
    429	struct timing_generator *tg,
    430	const struct dc_crtc_timing *timing)
    431{
    432	uint32_t tmp1 = 0;
    433	uint32_t tmp2 = 0;
    434	uint32_t vsync_offset = timing->v_border_bottom +
    435			timing->v_front_porch;
    436	uint32_t v_sync_start = timing->v_addressable + vsync_offset;
    437
    438	uint32_t hsync_offset = timing->h_border_right +
    439			timing->h_front_porch;
    440	uint32_t h_sync_start = timing->h_addressable + hsync_offset;
    441	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    442
    443	CRTC_REG_UPDATE(
    444		CRTC0_CRTC_H_TOTAL,
    445		CRTC_H_TOTAL,
    446		timing->h_total - 1);
    447
    448	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	CRTC_REG_UPDATE(
    457		CRTC0_CRTC_V_TOTAL_MAX,
    458		CRTC_V_TOTAL_MAX,
    459		timing->v_total - 1);
    460
    461	CRTC_REG_UPDATE(
    462		CRTC0_CRTC_V_TOTAL_MIN,
    463		CRTC_V_TOTAL_MIN,
    464		timing->v_total - 1);
    465
    466	tmp1 = timing->h_total -
    467			(h_sync_start + timing->h_border_left);
    468	tmp2 = tmp1 + timing->h_addressable +
    469			timing->h_border_left + timing->h_border_right;
    470
    471	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	tmp1 = timing->v_total - (v_sync_start + timing->v_border_top);
    477	tmp2 = tmp1 + timing->v_addressable + timing->v_border_top +
    478			timing->v_border_bottom;
    479
    480	CRTC_REG_UPDATE_2(
    481		CRTC0_CRTC_V_BLANK_START_END,
    482		CRTC_V_BLANK_END, tmp1,
    483		CRTC_V_BLANK_START, tmp2);
    484}
    485
    486/* TODO: Should we move it to opp? */
    487/* Combine with below and move YUV/RGB color conversion to SW layer */
    488static void dce120_timing_generator_program_blank_color(
    489	struct timing_generator *tg,
    490	const struct tg_color *black_color)
    491{
    492	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    493
    494	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}
    500/* Combine with above and move YUV/RGB color conversion to SW layer */
    501static void dce120_timing_generator_set_overscan_color_black(
    502	struct timing_generator *tg,
    503	const struct tg_color *color)
    504{
    505	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    506	uint32_t value = 0;
    507	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	value = dm_read_reg_soc15(
    514			tg->ctx,
    515			mmCRTC0_CRTC_OVERSCAN_COLOR,
    516			tg110->offsets.crtc);
    517
    518	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	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}
    542
    543static void dce120_timing_generator_set_drr(
    544	struct timing_generator *tg,
    545	const struct drr_params *params)
    546{
    547
    548	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    549
    550	if (params != NULL &&
    551		params->vertical_total_max > 0 &&
    552		params->vertical_total_min > 0) {
    553
    554		CRTC_REG_UPDATE(
    555				CRTC0_CRTC_V_TOTAL_MIN,
    556				CRTC_V_TOTAL_MIN, params->vertical_total_min - 1);
    557		CRTC_REG_UPDATE(
    558				CRTC0_CRTC_V_TOTAL_MAX,
    559				CRTC_V_TOTAL_MAX, params->vertical_total_max - 1);
    560		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		CRTC_REG_UPDATE(
    568				CRTC0_CRTC_STATIC_SCREEN_CONTROL,
    569				CRTC_STATIC_SCREEN_EVENT_MASK,
    570				0x180);
    571
    572	} else {
    573		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		CRTC_REG_UPDATE(
    580				CRTC0_CRTC_V_TOTAL_MIN,
    581				CRTC_V_TOTAL_MIN, 0);
    582		CRTC_REG_UPDATE(
    583				CRTC0_CRTC_V_TOTAL_MAX,
    584				CRTC_V_TOTAL_MAX, 0);
    585		CRTC_REG_UPDATE(
    586				CRTC0_CRTC_STATIC_SCREEN_CONTROL,
    587				CRTC_STATIC_SCREEN_EVENT_MASK,
    588				0);
    589	}
    590}
    591
    592static 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	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    600	struct crtc_position position;
    601
    602	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	*v_blank_start = get_reg_field_value(v_blank_start_end,
    608					     CRTC0_CRTC_V_BLANK_START_END,
    609					     CRTC_V_BLANK_START);
    610	*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	dce120_timing_generator_get_crtc_position(
    615			tg, &position);
    616
    617	*h_position = position.horizontal_count;
    618	*v_position = position.vertical_count;
    619}
    620
    621static void dce120_timing_generator_enable_advanced_request(
    622	struct timing_generator *tg,
    623	bool enable,
    624	const struct dc_crtc_timing *timing)
    625{
    626	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    627	uint32_t v_sync_width_and_b_porch =
    628				timing->v_total - timing->v_addressable -
    629				timing->v_border_bottom - timing->v_front_porch;
    630	uint32_t value = dm_read_reg_soc15(
    631				tg->ctx,
    632				mmCRTC0_CRTC_START_LINE_CONTROL,
    633				tg110->offsets.crtc);
    634
    635	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	if (v_sync_width_and_b_porch > 10)
    645		v_sync_width_and_b_porch = 10;
    646
    647	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	dm_write_reg_soc15(tg->ctx,
    654			mmCRTC0_CRTC_START_LINE_CONTROL,
    655			tg110->offsets.crtc,
    656			value);
    657}
    658
    659static void dce120_tg_program_blank_color(struct timing_generator *tg,
    660	const struct tg_color *black_color)
    661{
    662	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    663	uint32_t value = 0;
    664
    665	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	value = dm_read_reg_soc15(
    672				tg->ctx,
    673				mmCRTC0_CRTC_BLACK_COLOR,
    674				tg110->offsets.crtc);
    675	dm_write_reg_soc15(
    676		tg->ctx,
    677		mmCRTC0_CRTC_BLANK_DATA_COLOR,
    678		tg110->offsets.crtc,
    679		value);
    680}
    681
    682static void dce120_tg_set_overscan_color(struct timing_generator *tg,
    683	const struct tg_color *overscan_color)
    684{
    685	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    686
    687	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}
    693
    694static 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	if (use_vbios)
    704		dce110_timing_generator_program_timing_generator(tg, timing);
    705	else
    706		dce120_timing_generator_program_blanking(tg, timing);
    707}
    708
    709static bool dce120_tg_is_blanked(struct timing_generator *tg)
    710{
    711	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    712	uint32_t value = dm_read_reg_soc15(
    713			tg->ctx,
    714			mmCRTC0_CRTC_BLANK_CONTROL,
    715			tg110->offsets.crtc);
    716
    717	if (get_reg_field_value(
    718		value,
    719		CRTC0_CRTC_BLANK_CONTROL,
    720		CRTC_BLANK_DATA_EN) == 1 &&
    721	    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
    730static void dce120_tg_set_blank(struct timing_generator *tg,
    731		bool enable_blanking)
    732{
    733	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    734
    735	CRTC_REG_SET(
    736		CRTC0_CRTC_DOUBLE_BUFFER_CONTROL,
    737		CRTC_BLANK_DATA_DOUBLE_BUFFER_EN, 1);
    738
    739	if (enable_blanking)
    740		CRTC_REG_SET(CRTC0_CRTC_BLANK_CONTROL, CRTC_BLANK_DATA_EN, 1);
    741	else
    742		dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_BLANK_CONTROL,
    743			tg110->offsets.crtc, 0);
    744}
    745
    746bool dce120_tg_validate_timing(struct timing_generator *tg,
    747	const struct dc_crtc_timing *timing);
    748
    749static void dce120_tg_wait_for_state(struct timing_generator *tg,
    750	enum crtc_state state)
    751{
    752	switch (state) {
    753	case CRTC_STATE_VBLANK:
    754		dce120_timing_generator_wait_for_vblank(tg);
    755		break;
    756
    757	case CRTC_STATE_VACTIVE:
    758		dce120_timing_generator_wait_for_vactive(tg);
    759		break;
    760
    761	default:
    762		break;
    763	}
    764}
    765
    766static 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	if (blank_color != NULL)
    771		dce120_tg_program_blank_color(tg, blank_color);
    772
    773	if (overscan_color != NULL)
    774		dce120_tg_set_overscan_color(tg, overscan_color);
    775}
    776
    777static 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	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
    783
    784	// By register spec, it only takes 8 bit value
    785	if (num_frames > 0xFF)
    786		num_frames = 0xFF;
    787
    788	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}
    792
    793static 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	struct dc_context *ctx = tg->ctx;
    802	uint32_t value;
    803	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	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	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	switch (test_pattern) {
    843	case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES:
    844	case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA:
    845	{
    846		dyn_range = (test_pattern ==
    847				CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA ?
    848				TEST_PATTERN_DYN_RANGE_CEA :
    849				TEST_PATTERN_DYN_RANGE_VESA);
    850		mode = TEST_PATTERN_MODE_COLORSQUARES_RGB;
    851
    852		CRTC_REG_UPDATE_2(CRTC0_CRTC_TEST_PATTERN_PARAMETERS,
    853				CRTC_TEST_PATTERN_VRES, 6,
    854				CRTC_TEST_PATTERN_HRES, 6);
    855
    856		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	break;
    863
    864	case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS:
    865	case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS:
    866	{
    867		mode = (test_pattern ==
    868			CONTROLLER_DP_TEST_PATTERN_VERTICALBARS ?
    869			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		for (index = 0; index < 6; index++) {
    889			/* dst = 2^dstBpc * src / 2^srcBpc = src >>
    890			 * (srcBpc - dstBpc);
    891			 */
    892			dst_color[index] =
    893				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			dst_color[index] <<= (16 - dst_bpc);
    901		}
    902
    903		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		value = 0;
    932		for (index = 0; index < 6; index++) {
    933			/* prepare color mask, first write PATTERN_DATA
    934			 * will have all zeros
    935			 */
    936			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			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			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		dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value);
    956
    957		/* enable test pattern */
    958		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	break;
    965
    966	case CONTROLLER_DP_TEST_PATTERN_COLORRAMP:
    967	{
    968		mode = (bit_depth ==
    969			TEST_PATTERN_COLOR_FORMAT_BPC_10 ?
    970			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		inc_base = (src_bpc - dst_bpc);
    993
    994		switch (bit_depth) {
    995		case TEST_PATTERN_COLOR_FORMAT_BPC_6:
    996		{
    997			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		break;
   1005		case TEST_PATTERN_COLOR_FORMAT_BPC_8:
   1006		{
   1007			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		break;
   1015		case TEST_PATTERN_COLOR_FORMAT_BPC_10:
   1016		{
   1017			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		break;
   1025		default:
   1026		break;
   1027		}
   1028
   1029		dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, 0);
   1030
   1031		/* enable test pattern */
   1032		dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_CONTROL, tg110->offsets.crtc, 0);
   1033
   1034		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	break;
   1041	case CONTROLLER_DP_TEST_PATTERN_VIDEOMODE:
   1042	{
   1043		value = 0;
   1044		dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_CONTROL, tg110->offsets.crtc,  value);
   1045		dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_COLOR, tg110->offsets.crtc, value);
   1046		dm_write_reg_soc15(ctx, mmCRTC0_CRTC_TEST_PATTERN_PARAMETERS, tg110->offsets.crtc, value);
   1047	}
   1048	break;
   1049	default:
   1050	break;
   1051	}
   1052}
   1053
   1054static bool dce120_arm_vert_intr(
   1055		struct timing_generator *tg,
   1056		uint8_t width)
   1057{
   1058	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
   1059	uint32_t v_blank_start, v_blank_end, h_position, v_position;
   1060
   1061	tg->funcs->get_scanoutpos(
   1062				tg,
   1063				&v_blank_start,
   1064				&v_blank_end,
   1065				&h_position,
   1066				&v_position);
   1067
   1068	if (v_blank_start == 0 || v_blank_end == 0)
   1069		return false;
   1070
   1071	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	return true;
   1077}
   1078
   1079
   1080static bool dce120_is_tg_enabled(struct timing_generator *tg)
   1081{
   1082	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
   1083	uint32_t value, field;
   1084
   1085	value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CONTROL,
   1086				  tg110->offsets.crtc);
   1087	field = get_reg_field_value(value, CRTC0_CRTC_CONTROL,
   1088				    CRTC_CURRENT_MASTER_EN_STATE);
   1089
   1090	return field == 1;
   1091}
   1092
   1093static bool dce120_configure_crc(struct timing_generator *tg,
   1094				 const struct crc_params *params)
   1095{
   1096	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
   1097
   1098	/* Cannot configure crc on a CRTC that is disabled */
   1099	if (!dce120_is_tg_enabled(tg))
   1100		return false;
   1101
   1102	/* First, disable CRC before we configure it. */
   1103	dm_write_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC_CNTL,
   1104			   tg110->offsets.crtc, 0);
   1105
   1106	if (!params->enable)
   1107		return true;
   1108
   1109	/* Program frame boundaries */
   1110	/* Window A x axis start and end. */
   1111	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	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	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	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	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	return true;
   1137}
   1138
   1139static bool dce120_get_crc(struct timing_generator *tg, uint32_t *r_cr,
   1140			   uint32_t *g_y, uint32_t *b_cb)
   1141{
   1142	struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
   1143	uint32_t value, field;
   1144
   1145	value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC_CNTL,
   1146				  tg110->offsets.crtc);
   1147	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	if (!field)
   1151		return false;
   1152
   1153	value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC0_DATA_RG,
   1154				  tg110->offsets.crtc);
   1155	*r_cr = get_reg_field_value(value, CRTC0_CRTC_CRC0_DATA_RG, CRC0_R_CR);
   1156	*g_y = get_reg_field_value(value, CRTC0_CRTC_CRC0_DATA_RG, CRC0_G_Y);
   1157
   1158	value = dm_read_reg_soc15(tg->ctx, mmCRTC0_CRTC_CRC0_DATA_B,
   1159				  tg110->offsets.crtc);
   1160	*b_cb = get_reg_field_value(value, CRTC0_CRTC_CRC0_DATA_B, CRC0_B_CB);
   1161
   1162	return true;
   1163}
   1164
   1165static 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
   1203void 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	tg110->controller_id = CONTROLLER_ID_D0 + instance;
   1210	tg110->base.inst = instance;
   1211
   1212	tg110->offsets = *offsets;
   1213
   1214	tg110->base.funcs = &dce120_tg_funcs;
   1215
   1216	tg110->base.ctx = ctx;
   1217	tg110->base.bp = ctx->dc_bios;
   1218
   1219	tg110->max_h_total = CRTC0_CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1;
   1220	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	tg110->min_h_blank = 32;
   1225	/*DCE12_CRTC_Block_ARch.doc*/
   1226	tg110->min_h_front_porch = 0;
   1227	tg110->min_h_back_porch = 0;
   1228
   1229	tg110->min_h_sync_width = 4;
   1230	tg110->min_v_sync_width = 1;
   1231	tg110->min_v_blank = 3;
   1232}