Home | History | Annotate | Line # | Download | only in amdgpu
      1 /*	$NetBSD: amdgpu_atombios_crtc.c,v 1.3 2021/12/18 23:44:58 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2007-8 Advanced Micro Devices, Inc.
      5  * Copyright 2008 Red Hat Inc.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the "Software"),
      9  * to deal in the Software without restriction, including without limitation
     10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11  * and/or sell copies of the Software, and to permit persons to whom the
     12  * Software is furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included in
     15  * all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     23  * OTHER DEALINGS IN THE SOFTWARE.
     24  *
     25  * Authors: Dave Airlie
     26  *          Alex Deucher
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: amdgpu_atombios_crtc.c,v 1.3 2021/12/18 23:44:58 riastradh Exp $");
     31 
     32 #include <drm/drm_crtc_helper.h>
     33 #include <drm/amdgpu_drm.h>
     34 #include <drm/drm_fixed.h>
     35 #include "amdgpu.h"
     36 #include "atom.h"
     37 #include "atom-bits.h"
     38 #include "atombios_encoders.h"
     39 #include "atombios_crtc.h"
     40 #include "amdgpu_atombios.h"
     41 #include "amdgpu_pll.h"
     42 #include "amdgpu_connectors.h"
     43 #include "atombios_crtc.h"
     44 
     45 void amdgpu_atombios_crtc_overscan_setup(struct drm_crtc *crtc,
     46 				  struct drm_display_mode *mode,
     47 				  struct drm_display_mode *adjusted_mode)
     48 {
     49 	struct drm_device *dev = crtc->dev;
     50 	struct amdgpu_device *adev = dev->dev_private;
     51 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
     52 	SET_CRTC_OVERSCAN_PS_ALLOCATION args;
     53 	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
     54 	int a1, a2;
     55 
     56 	memset(&args, 0, sizeof(args));
     57 
     58 	args.ucCRTC = amdgpu_crtc->crtc_id;
     59 
     60 	switch (amdgpu_crtc->rmx_type) {
     61 	case RMX_CENTER:
     62 		args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
     63 		args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2);
     64 		args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
     65 		args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2);
     66 		break;
     67 	case RMX_ASPECT:
     68 		a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
     69 		a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
     70 
     71 		if (a1 > a2) {
     72 			args.usOverscanLeft = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
     73 			args.usOverscanRight = cpu_to_le16((adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2);
     74 		} else if (a2 > a1) {
     75 			args.usOverscanTop = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
     76 			args.usOverscanBottom = cpu_to_le16((adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2);
     77 		}
     78 		break;
     79 	case RMX_FULL:
     80 	default:
     81 		args.usOverscanRight = cpu_to_le16(amdgpu_crtc->h_border);
     82 		args.usOverscanLeft = cpu_to_le16(amdgpu_crtc->h_border);
     83 		args.usOverscanBottom = cpu_to_le16(amdgpu_crtc->v_border);
     84 		args.usOverscanTop = cpu_to_le16(amdgpu_crtc->v_border);
     85 		break;
     86 	}
     87 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
     88 }
     89 
     90 void amdgpu_atombios_crtc_scaler_setup(struct drm_crtc *crtc)
     91 {
     92 	struct drm_device *dev = crtc->dev;
     93 	struct amdgpu_device *adev = dev->dev_private;
     94 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
     95 	ENABLE_SCALER_PS_ALLOCATION args;
     96 	int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
     97 
     98 	memset(&args, 0, sizeof(args));
     99 
    100 	args.ucScaler = amdgpu_crtc->crtc_id;
    101 
    102 	switch (amdgpu_crtc->rmx_type) {
    103 	case RMX_FULL:
    104 		args.ucEnable = ATOM_SCALER_EXPANSION;
    105 		break;
    106 	case RMX_CENTER:
    107 		args.ucEnable = ATOM_SCALER_CENTER;
    108 		break;
    109 	case RMX_ASPECT:
    110 		args.ucEnable = ATOM_SCALER_EXPANSION;
    111 		break;
    112 	default:
    113 		args.ucEnable = ATOM_SCALER_DISABLE;
    114 		break;
    115 	}
    116 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
    117 }
    118 
    119 void amdgpu_atombios_crtc_lock(struct drm_crtc *crtc, int lock)
    120 {
    121 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
    122 	struct drm_device *dev = crtc->dev;
    123 	struct amdgpu_device *adev = dev->dev_private;
    124 	int index =
    125 	    GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
    126 	ENABLE_CRTC_PS_ALLOCATION args;
    127 
    128 	memset(&args, 0, sizeof(args));
    129 
    130 	args.ucCRTC = amdgpu_crtc->crtc_id;
    131 	args.ucEnable = lock;
    132 
    133 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
    134 }
    135 
    136 void amdgpu_atombios_crtc_enable(struct drm_crtc *crtc, int state)
    137 {
    138 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
    139 	struct drm_device *dev = crtc->dev;
    140 	struct amdgpu_device *adev = dev->dev_private;
    141 	int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
    142 	ENABLE_CRTC_PS_ALLOCATION args;
    143 
    144 	memset(&args, 0, sizeof(args));
    145 
    146 	args.ucCRTC = amdgpu_crtc->crtc_id;
    147 	args.ucEnable = state;
    148 
    149 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
    150 }
    151 
    152 void amdgpu_atombios_crtc_blank(struct drm_crtc *crtc, int state)
    153 {
    154 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
    155 	struct drm_device *dev = crtc->dev;
    156 	struct amdgpu_device *adev = dev->dev_private;
    157 	int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
    158 	BLANK_CRTC_PS_ALLOCATION args;
    159 
    160 	memset(&args, 0, sizeof(args));
    161 
    162 	args.ucCRTC = amdgpu_crtc->crtc_id;
    163 	args.ucBlanking = state;
    164 
    165 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
    166 }
    167 
    168 void amdgpu_atombios_crtc_powergate(struct drm_crtc *crtc, int state)
    169 {
    170 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
    171 	struct drm_device *dev = crtc->dev;
    172 	struct amdgpu_device *adev = dev->dev_private;
    173 	int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
    174 	ENABLE_DISP_POWER_GATING_PS_ALLOCATION args;
    175 
    176 	memset(&args, 0, sizeof(args));
    177 
    178 	args.ucDispPipeId = amdgpu_crtc->crtc_id;
    179 	args.ucEnable = state;
    180 
    181 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
    182 }
    183 
    184 void amdgpu_atombios_crtc_powergate_init(struct amdgpu_device *adev)
    185 {
    186 	int index = GetIndexIntoMasterTable(COMMAND, EnableDispPowerGating);
    187 	ENABLE_DISP_POWER_GATING_PS_ALLOCATION args;
    188 
    189 	memset(&args, 0, sizeof(args));
    190 
    191 	args.ucEnable = ATOM_INIT;
    192 
    193 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
    194 }
    195 
    196 void amdgpu_atombios_crtc_set_dtd_timing(struct drm_crtc *crtc,
    197 				  struct drm_display_mode *mode)
    198 {
    199 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
    200 	struct drm_device *dev = crtc->dev;
    201 	struct amdgpu_device *adev = dev->dev_private;
    202 	SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
    203 	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
    204 	u16 misc = 0;
    205 
    206 	memset(&args, 0, sizeof(args));
    207 	args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (amdgpu_crtc->h_border * 2));
    208 	args.usH_Blanking_Time =
    209 		cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (amdgpu_crtc->h_border * 2));
    210 	args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (amdgpu_crtc->v_border * 2));
    211 	args.usV_Blanking_Time =
    212 		cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (amdgpu_crtc->v_border * 2));
    213 	args.usH_SyncOffset =
    214 		cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + amdgpu_crtc->h_border);
    215 	args.usH_SyncWidth =
    216 		cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
    217 	args.usV_SyncOffset =
    218 		cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + amdgpu_crtc->v_border);
    219 	args.usV_SyncWidth =
    220 		cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
    221 	args.ucH_Border = amdgpu_crtc->h_border;
    222 	args.ucV_Border = amdgpu_crtc->v_border;
    223 
    224 	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
    225 		misc |= ATOM_VSYNC_POLARITY;
    226 	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
    227 		misc |= ATOM_HSYNC_POLARITY;
    228 	if (mode->flags & DRM_MODE_FLAG_CSYNC)
    229 		misc |= ATOM_COMPOSITESYNC;
    230 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
    231 		misc |= ATOM_INTERLACE;
    232 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
    233 		misc |= ATOM_DOUBLE_CLOCK_MODE;
    234 
    235 	args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
    236 	args.ucCRTC = amdgpu_crtc->crtc_id;
    237 
    238 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
    239 }
    240 
    241 union atom_enable_ss {
    242 	ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
    243 	ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2;
    244 	ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3;
    245 };
    246 
    247 static void amdgpu_atombios_crtc_program_ss(struct amdgpu_device *adev,
    248 				     int enable,
    249 				     int pll_id,
    250 				     int crtc_id,
    251 				     struct amdgpu_atom_ss *ss)
    252 {
    253 	unsigned i;
    254 	int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
    255 	union atom_enable_ss args;
    256 
    257 	if (enable) {
    258 		/* Don't mess with SS if percentage is 0 or external ss.
    259 		 * SS is already disabled previously, and disabling it
    260 		 * again can cause display problems if the pll is already
    261 		 * programmed.
    262 		 */
    263 		if (ss->percentage == 0)
    264 			return;
    265 		if (ss->type & ATOM_EXTERNAL_SS_MASK)
    266 			return;
    267 	} else {
    268 		for (i = 0; i < adev->mode_info.num_crtc; i++) {
    269 			if (adev->mode_info.crtcs[i] &&
    270 			    adev->mode_info.crtcs[i]->enabled &&
    271 			    i != crtc_id &&
    272 			    pll_id == adev->mode_info.crtcs[i]->pll_id) {
    273 				/* one other crtc is using this pll don't turn
    274 				 * off spread spectrum as it might turn off
    275 				 * display on active crtc
    276 				 */
    277 				return;
    278 			}
    279 		}
    280 	}
    281 
    282 	memset(&args, 0, sizeof(args));
    283 
    284 	args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0);
    285 	args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
    286 	switch (pll_id) {
    287 	case ATOM_PPLL1:
    288 		args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
    289 		break;
    290 	case ATOM_PPLL2:
    291 		args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL;
    292 		break;
    293 	case ATOM_DCPLL:
    294 		args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL;
    295 		break;
    296 	case ATOM_PPLL_INVALID:
    297 		return;
    298 	}
    299 	args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
    300 	args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step);
    301 	args.v3.ucEnable = enable;
    302 
    303 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
    304 }
    305 
    306 union adjust_pixel_clock {
    307 	ADJUST_DISPLAY_PLL_PS_ALLOCATION v1;
    308 	ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3;
    309 };
    310 
    311 static u32 amdgpu_atombios_crtc_adjust_pll(struct drm_crtc *crtc,
    312 				    struct drm_display_mode *mode)
    313 {
    314 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
    315 	struct drm_device *dev = crtc->dev;
    316 	struct amdgpu_device *adev = dev->dev_private;
    317 	struct drm_encoder *encoder = amdgpu_crtc->encoder;
    318 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
    319 	struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
    320 	u32 adjusted_clock = mode->clock;
    321 	int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
    322 	u32 dp_clock = mode->clock;
    323 	u32 clock = mode->clock;
    324 	int bpc = amdgpu_crtc->bpc;
    325 	bool is_duallink = amdgpu_dig_monitor_is_duallink(encoder, mode->clock);
    326 	union adjust_pixel_clock args;
    327 	u8 frev, crev;
    328 	int index;
    329 
    330 	amdgpu_crtc->pll_flags = AMDGPU_PLL_USE_FRAC_FB_DIV;
    331 
    332 	if ((amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
    333 	    (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) {
    334 		if (connector) {
    335 			struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
    336 			struct amdgpu_connector_atom_dig *dig_connector =
    337 				amdgpu_connector->con_priv;
    338 
    339 			dp_clock = dig_connector->dp_clock;
    340 		}
    341 	}
    342 
    343 	/* use recommended ref_div for ss */
    344 	if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
    345 		if (amdgpu_crtc->ss_enabled) {
    346 			if (amdgpu_crtc->ss.refdiv) {
    347 				amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_REF_DIV;
    348 				amdgpu_crtc->pll_reference_div = amdgpu_crtc->ss.refdiv;
    349 				amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
    350 			}
    351 		}
    352 	}
    353 
    354 	/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
    355 	if (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
    356 		adjusted_clock = mode->clock * 2;
    357 	if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
    358 		amdgpu_crtc->pll_flags |= AMDGPU_PLL_PREFER_CLOSEST_LOWER;
    359 	if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
    360 		amdgpu_crtc->pll_flags |= AMDGPU_PLL_IS_LCD;
    361 
    362 
    363 	/* adjust pll for deep color modes */
    364 	if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
    365 		switch (bpc) {
    366 		case 8:
    367 		default:
    368 			break;
    369 		case 10:
    370 			clock = (clock * 5) / 4;
    371 			break;
    372 		case 12:
    373 			clock = (clock * 3) / 2;
    374 			break;
    375 		case 16:
    376 			clock = clock * 2;
    377 			break;
    378 		}
    379 	}
    380 
    381 	/* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock
    382 	 * accordingly based on the encoder/transmitter to work around
    383 	 * special hw requirements.
    384 	 */
    385 	index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
    386 	if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
    387 				   &crev))
    388 		return adjusted_clock;
    389 
    390 	memset(&args, 0, sizeof(args));
    391 
    392 	switch (frev) {
    393 	case 1:
    394 		switch (crev) {
    395 		case 1:
    396 		case 2:
    397 			args.v1.usPixelClock = cpu_to_le16(clock / 10);
    398 			args.v1.ucTransmitterID = amdgpu_encoder->encoder_id;
    399 			args.v1.ucEncodeMode = encoder_mode;
    400 			if (amdgpu_crtc->ss_enabled && amdgpu_crtc->ss.percentage)
    401 				args.v1.ucConfig |=
    402 					ADJUST_DISPLAY_CONFIG_SS_ENABLE;
    403 
    404 			amdgpu_atom_execute_table(adev->mode_info.atom_context,
    405 					   index, (uint32_t *)&args);
    406 			adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;
    407 			break;
    408 		case 3:
    409 			args.v3.sInput.usPixelClock = cpu_to_le16(clock / 10);
    410 			args.v3.sInput.ucTransmitterID = amdgpu_encoder->encoder_id;
    411 			args.v3.sInput.ucEncodeMode = encoder_mode;
    412 			args.v3.sInput.ucDispPllConfig = 0;
    413 			if (amdgpu_crtc->ss_enabled && amdgpu_crtc->ss.percentage)
    414 				args.v3.sInput.ucDispPllConfig |=
    415 					DISPPLL_CONFIG_SS_ENABLE;
    416 			if (ENCODER_MODE_IS_DP(encoder_mode)) {
    417 				args.v3.sInput.ucDispPllConfig |=
    418 					DISPPLL_CONFIG_COHERENT_MODE;
    419 				/* 16200 or 27000 */
    420 				args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
    421 			} else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
    422 				struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
    423 				if (dig->coherent_mode)
    424 					args.v3.sInput.ucDispPllConfig |=
    425 						DISPPLL_CONFIG_COHERENT_MODE;
    426 				if (is_duallink)
    427 					args.v3.sInput.ucDispPllConfig |=
    428 						DISPPLL_CONFIG_DUAL_LINK;
    429 			}
    430 			if (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) !=
    431 			    ENCODER_OBJECT_ID_NONE)
    432 				args.v3.sInput.ucExtTransmitterID =
    433 					amdgpu_encoder_get_dp_bridge_encoder_id(encoder);
    434 			else
    435 				args.v3.sInput.ucExtTransmitterID = 0;
    436 
    437 			amdgpu_atom_execute_table(adev->mode_info.atom_context,
    438 					   index, (uint32_t *)&args);
    439 			adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
    440 			if (args.v3.sOutput.ucRefDiv) {
    441 				amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
    442 				amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_REF_DIV;
    443 				amdgpu_crtc->pll_reference_div = args.v3.sOutput.ucRefDiv;
    444 			}
    445 			if (args.v3.sOutput.ucPostDiv) {
    446 				amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_FRAC_FB_DIV;
    447 				amdgpu_crtc->pll_flags |= AMDGPU_PLL_USE_POST_DIV;
    448 				amdgpu_crtc->pll_post_div = args.v3.sOutput.ucPostDiv;
    449 			}
    450 			break;
    451 		default:
    452 			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
    453 			return adjusted_clock;
    454 		}
    455 		break;
    456 	default:
    457 		DRM_ERROR("Unknown table version %d %d\n", frev, crev);
    458 		return adjusted_clock;
    459 	}
    460 
    461 	return adjusted_clock;
    462 }
    463 
    464 union set_pixel_clock {
    465 	SET_PIXEL_CLOCK_PS_ALLOCATION base;
    466 	PIXEL_CLOCK_PARAMETERS v1;
    467 	PIXEL_CLOCK_PARAMETERS_V2 v2;
    468 	PIXEL_CLOCK_PARAMETERS_V3 v3;
    469 	PIXEL_CLOCK_PARAMETERS_V5 v5;
    470 	PIXEL_CLOCK_PARAMETERS_V6 v6;
    471 	PIXEL_CLOCK_PARAMETERS_V7 v7;
    472 };
    473 
    474 /* on DCE5, make sure the voltage is high enough to support the
    475  * required disp clk.
    476  */
    477 void amdgpu_atombios_crtc_set_disp_eng_pll(struct amdgpu_device *adev,
    478 					   u32 dispclk)
    479 {
    480 	u8 frev, crev;
    481 	int index;
    482 	union set_pixel_clock args;
    483 
    484 	memset(&args, 0, sizeof(args));
    485 
    486 	index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
    487 	if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
    488 				   &crev))
    489 		return;
    490 
    491 	switch (frev) {
    492 	case 1:
    493 		switch (crev) {
    494 		case 5:
    495 			/* if the default dcpll clock is specified,
    496 			 * SetPixelClock provides the dividers
    497 			 */
    498 			args.v5.ucCRTC = ATOM_CRTC_INVALID;
    499 			args.v5.usPixelClock = cpu_to_le16(dispclk);
    500 			args.v5.ucPpll = ATOM_DCPLL;
    501 			break;
    502 		case 6:
    503 			/* if the default dcpll clock is specified,
    504 			 * SetPixelClock provides the dividers
    505 			 */
    506 			args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
    507 			if (adev->asic_type == CHIP_TAHITI ||
    508 			    adev->asic_type == CHIP_PITCAIRN ||
    509 			    adev->asic_type == CHIP_VERDE ||
    510 			    adev->asic_type == CHIP_OLAND)
    511 				args.v6.ucPpll = ATOM_PPLL0;
    512 			else
    513 				args.v6.ucPpll = ATOM_EXT_PLL1;
    514 			break;
    515 		default:
    516 			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
    517 			return;
    518 		}
    519 		break;
    520 	default:
    521 		DRM_ERROR("Unknown table version %d %d\n", frev, crev);
    522 		return;
    523 	}
    524 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
    525 }
    526 
    527 union set_dce_clock {
    528 	SET_DCE_CLOCK_PS_ALLOCATION_V1_1 v1_1;
    529 	SET_DCE_CLOCK_PS_ALLOCATION_V2_1 v2_1;
    530 };
    531 
    532 u32 amdgpu_atombios_crtc_set_dce_clock(struct amdgpu_device *adev,
    533 				       u32 freq, u8 clk_type, u8 clk_src)
    534 {
    535 	u8 frev, crev;
    536 	int index;
    537 	union set_dce_clock args;
    538 	u32 ret_freq = 0;
    539 
    540 	memset(&args, 0, sizeof(args));
    541 
    542 	index = GetIndexIntoMasterTable(COMMAND, SetDCEClock);
    543 	if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
    544 				   &crev))
    545 		return 0;
    546 
    547 	switch (frev) {
    548 	case 2:
    549 		switch (crev) {
    550 		case 1:
    551 			args.v2_1.asParam.ulDCEClkFreq = cpu_to_le32(freq); /* 10kHz units */
    552 			args.v2_1.asParam.ucDCEClkType = clk_type;
    553 			args.v2_1.asParam.ucDCEClkSrc = clk_src;
    554 			amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
    555 			ret_freq = le32_to_cpu(args.v2_1.asParam.ulDCEClkFreq) * 10;
    556 			break;
    557 		default:
    558 			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
    559 			return 0;
    560 		}
    561 		break;
    562 	default:
    563 		DRM_ERROR("Unknown table version %d %d\n", frev, crev);
    564 		return 0;
    565 	}
    566 
    567 	return ret_freq;
    568 }
    569 
    570 static bool is_pixel_clock_source_from_pll(u32 encoder_mode, int pll_id)
    571 {
    572 	if (ENCODER_MODE_IS_DP(encoder_mode)) {
    573 		if (pll_id < ATOM_EXT_PLL1)
    574 			return true;
    575 		else
    576 			return false;
    577 	} else {
    578 		return true;
    579 	}
    580 }
    581 
    582 void amdgpu_atombios_crtc_program_pll(struct drm_crtc *crtc,
    583 				      u32 crtc_id,
    584 				      int pll_id,
    585 				      u32 encoder_mode,
    586 				      u32 encoder_id,
    587 				      u32 clock,
    588 				      u32 ref_div,
    589 				      u32 fb_div,
    590 				      u32 frac_fb_div,
    591 				      u32 post_div,
    592 				      int bpc,
    593 				      bool ss_enabled,
    594 				      struct amdgpu_atom_ss *ss)
    595 {
    596 	struct drm_device *dev = crtc->dev;
    597 	struct amdgpu_device *adev = dev->dev_private;
    598 	u8 frev, crev;
    599 	int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
    600 	union set_pixel_clock args;
    601 
    602 	memset(&args, 0, sizeof(args));
    603 
    604 	if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev,
    605 				   &crev))
    606 		return;
    607 
    608 	switch (frev) {
    609 	case 1:
    610 		switch (crev) {
    611 		case 1:
    612 			if (clock == ATOM_DISABLE)
    613 				return;
    614 			args.v1.usPixelClock = cpu_to_le16(clock / 10);
    615 			args.v1.usRefDiv = cpu_to_le16(ref_div);
    616 			args.v1.usFbDiv = cpu_to_le16(fb_div);
    617 			args.v1.ucFracFbDiv = frac_fb_div;
    618 			args.v1.ucPostDiv = post_div;
    619 			args.v1.ucPpll = pll_id;
    620 			args.v1.ucCRTC = crtc_id;
    621 			args.v1.ucRefDivSrc = 1;
    622 			break;
    623 		case 2:
    624 			args.v2.usPixelClock = cpu_to_le16(clock / 10);
    625 			args.v2.usRefDiv = cpu_to_le16(ref_div);
    626 			args.v2.usFbDiv = cpu_to_le16(fb_div);
    627 			args.v2.ucFracFbDiv = frac_fb_div;
    628 			args.v2.ucPostDiv = post_div;
    629 			args.v2.ucPpll = pll_id;
    630 			args.v2.ucCRTC = crtc_id;
    631 			args.v2.ucRefDivSrc = 1;
    632 			break;
    633 		case 3:
    634 			args.v3.usPixelClock = cpu_to_le16(clock / 10);
    635 			args.v3.usRefDiv = cpu_to_le16(ref_div);
    636 			args.v3.usFbDiv = cpu_to_le16(fb_div);
    637 			args.v3.ucFracFbDiv = frac_fb_div;
    638 			args.v3.ucPostDiv = post_div;
    639 			args.v3.ucPpll = pll_id;
    640 			if (crtc_id == ATOM_CRTC2)
    641 				args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2;
    642 			else
    643 				args.v3.ucMiscInfo = PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1;
    644 			if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
    645 				args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
    646 			args.v3.ucTransmitterId = encoder_id;
    647 			args.v3.ucEncoderMode = encoder_mode;
    648 			break;
    649 		case 5:
    650 			args.v5.ucCRTC = crtc_id;
    651 			args.v5.usPixelClock = cpu_to_le16(clock / 10);
    652 			args.v5.ucRefDiv = ref_div;
    653 			args.v5.usFbDiv = cpu_to_le16(fb_div);
    654 			args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
    655 			args.v5.ucPostDiv = post_div;
    656 			args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
    657 			if ((ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) &&
    658 			    (pll_id < ATOM_EXT_PLL1))
    659 				args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
    660 			if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
    661 				switch (bpc) {
    662 				case 8:
    663 				default:
    664 					args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
    665 					break;
    666 				case 10:
    667 					/* yes this is correct, the atom define is wrong */
    668 					args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP;
    669 					break;
    670 				case 12:
    671 					/* yes this is correct, the atom define is wrong */
    672 					args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
    673 					break;
    674 				}
    675 			}
    676 			args.v5.ucTransmitterID = encoder_id;
    677 			args.v5.ucEncoderMode = encoder_mode;
    678 			args.v5.ucPpll = pll_id;
    679 			break;
    680 		case 6:
    681 			args.v6.ulDispEngClkFreq = cpu_to_le32(crtc_id << 24 | clock / 10);
    682 			args.v6.ucRefDiv = ref_div;
    683 			args.v6.usFbDiv = cpu_to_le16(fb_div);
    684 			args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
    685 			args.v6.ucPostDiv = post_div;
    686 			args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
    687 			if ((ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) &&
    688 			    (pll_id < ATOM_EXT_PLL1) &&
    689 			    !is_pixel_clock_source_from_pll(encoder_mode, pll_id))
    690 				args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
    691 			if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
    692 				switch (bpc) {
    693 				case 8:
    694 				default:
    695 					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
    696 					break;
    697 				case 10:
    698 					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6;
    699 					break;
    700 				case 12:
    701 					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6;
    702 					break;
    703 				case 16:
    704 					args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
    705 					break;
    706 				}
    707 			}
    708 			args.v6.ucTransmitterID = encoder_id;
    709 			args.v6.ucEncoderMode = encoder_mode;
    710 			args.v6.ucPpll = pll_id;
    711 			break;
    712 		case 7:
    713 			args.v7.ulPixelClock = cpu_to_le32(clock * 10); /* 100 hz units */
    714 			args.v7.ucMiscInfo = 0;
    715 			if ((encoder_mode == ATOM_ENCODER_MODE_DVI) &&
    716 			    (clock > 165000))
    717 				args.v7.ucMiscInfo |= PIXEL_CLOCK_V7_MISC_DVI_DUALLINK_EN;
    718 			args.v7.ucCRTC = crtc_id;
    719 			if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
    720 				switch (bpc) {
    721 				case 8:
    722 				default:
    723 					args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_DIS;
    724 					break;
    725 				case 10:
    726 					args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_5_4;
    727 					break;
    728 				case 12:
    729 					args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_3_2;
    730 					break;
    731 				case 16:
    732 					args.v7.ucDeepColorRatio = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_2_1;
    733 					break;
    734 				}
    735 			}
    736 			args.v7.ucTransmitterID = encoder_id;
    737 			args.v7.ucEncoderMode = encoder_mode;
    738 			args.v7.ucPpll = pll_id;
    739 			break;
    740 		default:
    741 			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
    742 			return;
    743 		}
    744 		break;
    745 	default:
    746 		DRM_ERROR("Unknown table version %d %d\n", frev, crev);
    747 		return;
    748 	}
    749 
    750 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
    751 }
    752 
    753 int amdgpu_atombios_crtc_prepare_pll(struct drm_crtc *crtc,
    754 			      struct drm_display_mode *mode)
    755 {
    756 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
    757 	struct drm_device *dev = crtc->dev;
    758 	struct amdgpu_device *adev = dev->dev_private;
    759 	struct amdgpu_encoder *amdgpu_encoder =
    760 		to_amdgpu_encoder(amdgpu_crtc->encoder);
    761 	int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder);
    762 
    763 	amdgpu_crtc->bpc = 8;
    764 	amdgpu_crtc->ss_enabled = false;
    765 
    766 	if ((amdgpu_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
    767 	    (amdgpu_encoder_get_dp_bridge_encoder_id(amdgpu_crtc->encoder) != ENCODER_OBJECT_ID_NONE)) {
    768 		struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
    769 		struct drm_connector *connector =
    770 			amdgpu_get_connector_for_encoder(amdgpu_crtc->encoder);
    771 		struct amdgpu_connector *amdgpu_connector =
    772 			to_amdgpu_connector(connector);
    773 		struct amdgpu_connector_atom_dig *dig_connector =
    774 			amdgpu_connector->con_priv;
    775 		int dp_clock;
    776 
    777 		/* Assign mode clock for hdmi deep color max clock limit check */
    778 		amdgpu_connector->pixelclock_for_modeset = mode->clock;
    779 		amdgpu_crtc->bpc = amdgpu_connector_get_monitor_bpc(connector);
    780 
    781 		switch (encoder_mode) {
    782 		case ATOM_ENCODER_MODE_DP_MST:
    783 		case ATOM_ENCODER_MODE_DP:
    784 			/* DP/eDP */
    785 			dp_clock = dig_connector->dp_clock / 10;
    786 			amdgpu_crtc->ss_enabled =
    787 				amdgpu_atombios_get_asic_ss_info(adev, &amdgpu_crtc->ss,
    788 								 ASIC_INTERNAL_SS_ON_DP,
    789 								 dp_clock);
    790 			break;
    791 		case ATOM_ENCODER_MODE_LVDS:
    792 			amdgpu_crtc->ss_enabled =
    793 				amdgpu_atombios_get_asic_ss_info(adev,
    794 								 &amdgpu_crtc->ss,
    795 								 dig->lcd_ss_id,
    796 								 mode->clock / 10);
    797 			break;
    798 		case ATOM_ENCODER_MODE_DVI:
    799 			amdgpu_crtc->ss_enabled =
    800 				amdgpu_atombios_get_asic_ss_info(adev,
    801 								 &amdgpu_crtc->ss,
    802 								 ASIC_INTERNAL_SS_ON_TMDS,
    803 								 mode->clock / 10);
    804 			break;
    805 		case ATOM_ENCODER_MODE_HDMI:
    806 			amdgpu_crtc->ss_enabled =
    807 				amdgpu_atombios_get_asic_ss_info(adev,
    808 								 &amdgpu_crtc->ss,
    809 								 ASIC_INTERNAL_SS_ON_HDMI,
    810 								 mode->clock / 10);
    811 			break;
    812 		default:
    813 			break;
    814 		}
    815 	}
    816 
    817 	/* adjust pixel clock as needed */
    818 	amdgpu_crtc->adjusted_clock = amdgpu_atombios_crtc_adjust_pll(crtc, mode);
    819 
    820 	return 0;
    821 }
    822 
    823 void amdgpu_atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
    824 {
    825 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
    826 	struct drm_device *dev = crtc->dev;
    827 	struct amdgpu_device *adev = dev->dev_private;
    828 	struct amdgpu_encoder *amdgpu_encoder =
    829 		to_amdgpu_encoder(amdgpu_crtc->encoder);
    830 	u32 pll_clock = mode->clock;
    831 	u32 clock = mode->clock;
    832 	u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
    833 	struct amdgpu_pll *pll;
    834 	int encoder_mode = amdgpu_atombios_encoder_get_encoder_mode(amdgpu_crtc->encoder);
    835 
    836 	/* pass the actual clock to amdgpu_atombios_crtc_program_pll for HDMI */
    837 	if ((encoder_mode == ATOM_ENCODER_MODE_HDMI) &&
    838 	    (amdgpu_crtc->bpc > 8))
    839 		clock = amdgpu_crtc->adjusted_clock;
    840 
    841 	switch (amdgpu_crtc->pll_id) {
    842 	case ATOM_PPLL1:
    843 		pll = &adev->clock.ppll[0];
    844 		break;
    845 	case ATOM_PPLL2:
    846 		pll = &adev->clock.ppll[1];
    847 		break;
    848 	case ATOM_PPLL0:
    849 	case ATOM_PPLL_INVALID:
    850 	default:
    851 		pll = &adev->clock.ppll[2];
    852 		break;
    853 	}
    854 
    855 	/* update pll params */
    856 	pll->flags = amdgpu_crtc->pll_flags;
    857 	pll->reference_div = amdgpu_crtc->pll_reference_div;
    858 	pll->post_div = amdgpu_crtc->pll_post_div;
    859 
    860 	amdgpu_pll_compute(pll, amdgpu_crtc->adjusted_clock, &pll_clock,
    861 			    &fb_div, &frac_fb_div, &ref_div, &post_div);
    862 
    863 	amdgpu_atombios_crtc_program_ss(adev, ATOM_DISABLE, amdgpu_crtc->pll_id,
    864 				 amdgpu_crtc->crtc_id, &amdgpu_crtc->ss);
    865 
    866 	amdgpu_atombios_crtc_program_pll(crtc, amdgpu_crtc->crtc_id, amdgpu_crtc->pll_id,
    867 				  encoder_mode, amdgpu_encoder->encoder_id, clock,
    868 				  ref_div, fb_div, frac_fb_div, post_div,
    869 				  amdgpu_crtc->bpc, amdgpu_crtc->ss_enabled, &amdgpu_crtc->ss);
    870 
    871 	if (amdgpu_crtc->ss_enabled) {
    872 		/* calculate ss amount and step size */
    873 		u32 step_size;
    874 		u32 amount = (((fb_div * 10) + frac_fb_div) *
    875 			      (u32)amdgpu_crtc->ss.percentage) /
    876 			(100 * (u32)amdgpu_crtc->ss.percentage_divider);
    877 		amdgpu_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
    878 		amdgpu_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
    879 			ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
    880 		if (amdgpu_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
    881 			step_size = (4 * amount * ref_div * ((u32)amdgpu_crtc->ss.rate * 2048)) /
    882 				(125 * 25 * pll->reference_freq / 100);
    883 		else
    884 			step_size = (2 * amount * ref_div * ((u32)amdgpu_crtc->ss.rate * 2048)) /
    885 				(125 * 25 * pll->reference_freq / 100);
    886 		amdgpu_crtc->ss.step = step_size;
    887 
    888 		amdgpu_atombios_crtc_program_ss(adev, ATOM_ENABLE, amdgpu_crtc->pll_id,
    889 					 amdgpu_crtc->crtc_id, &amdgpu_crtc->ss);
    890 	}
    891 }
    892 
    893