brintos

brintos / linux-shallow public Read only

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