1771fe6b9SJerome Glisse /*
2771fe6b9SJerome Glisse  * Copyright 2007-8 Advanced Micro Devices, Inc.
3771fe6b9SJerome Glisse  * Copyright 2008 Red Hat Inc.
4771fe6b9SJerome Glisse  *
5771fe6b9SJerome Glisse  * Permission is hereby granted, free of charge, to any person obtaining a
6771fe6b9SJerome Glisse  * copy of this software and associated documentation files (the "Software"),
7771fe6b9SJerome Glisse  * to deal in the Software without restriction, including without limitation
8771fe6b9SJerome Glisse  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9771fe6b9SJerome Glisse  * and/or sell copies of the Software, and to permit persons to whom the
10771fe6b9SJerome Glisse  * Software is furnished to do so, subject to the following conditions:
11771fe6b9SJerome Glisse  *
12771fe6b9SJerome Glisse  * The above copyright notice and this permission notice shall be included in
13771fe6b9SJerome Glisse  * all copies or substantial portions of the Software.
14771fe6b9SJerome Glisse  *
15771fe6b9SJerome Glisse  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16771fe6b9SJerome Glisse  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17771fe6b9SJerome Glisse  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18771fe6b9SJerome Glisse  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19771fe6b9SJerome Glisse  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20771fe6b9SJerome Glisse  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21771fe6b9SJerome Glisse  * OTHER DEALINGS IN THE SOFTWARE.
22771fe6b9SJerome Glisse  *
23771fe6b9SJerome Glisse  * Authors: Dave Airlie
24771fe6b9SJerome Glisse  *          Alex Deucher
25771fe6b9SJerome Glisse  */
26771fe6b9SJerome Glisse #include <drm/drmP.h>
27771fe6b9SJerome Glisse #include <drm/drm_crtc_helper.h>
28771fe6b9SJerome Glisse #include <drm/radeon_drm.h>
2968adac5eSBen Skeggs #include <drm/drm_fixed.h>
30771fe6b9SJerome Glisse #include "radeon.h"
31771fe6b9SJerome Glisse #include "atom.h"
32771fe6b9SJerome Glisse #include "atom-bits.h"
33771fe6b9SJerome Glisse 
34c93bb85bSJerome Glisse static void atombios_overscan_setup(struct drm_crtc *crtc,
35c93bb85bSJerome Glisse 				    struct drm_display_mode *mode,
36c93bb85bSJerome Glisse 				    struct drm_display_mode *adjusted_mode)
37c93bb85bSJerome Glisse {
38c93bb85bSJerome Glisse 	struct drm_device *dev = crtc->dev;
39c93bb85bSJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
40c93bb85bSJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
41c93bb85bSJerome Glisse 	SET_CRTC_OVERSCAN_PS_ALLOCATION args;
42c93bb85bSJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
43c93bb85bSJerome Glisse 	int a1, a2;
44c93bb85bSJerome Glisse 
45c93bb85bSJerome Glisse 	memset(&args, 0, sizeof(args));
46c93bb85bSJerome Glisse 
47c93bb85bSJerome Glisse 	args.ucCRTC = radeon_crtc->crtc_id;
48c93bb85bSJerome Glisse 
49c93bb85bSJerome Glisse 	switch (radeon_crtc->rmx_type) {
50c93bb85bSJerome Glisse 	case RMX_CENTER:
51c93bb85bSJerome Glisse 		args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
52c93bb85bSJerome Glisse 		args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
53c93bb85bSJerome Glisse 		args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
54c93bb85bSJerome Glisse 		args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
55c93bb85bSJerome Glisse 		break;
56c93bb85bSJerome Glisse 	case RMX_ASPECT:
57c93bb85bSJerome Glisse 		a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
58c93bb85bSJerome Glisse 		a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
59c93bb85bSJerome Glisse 
60c93bb85bSJerome Glisse 		if (a1 > a2) {
61c93bb85bSJerome Glisse 			args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2;
62c93bb85bSJerome Glisse 			args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2;
63c93bb85bSJerome Glisse 		} else if (a2 > a1) {
64c93bb85bSJerome Glisse 			args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
65c93bb85bSJerome Glisse 			args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
66c93bb85bSJerome Glisse 		}
67c93bb85bSJerome Glisse 		break;
68c93bb85bSJerome Glisse 	case RMX_FULL:
69c93bb85bSJerome Glisse 	default:
705b1714d3SAlex Deucher 		args.usOverscanRight = radeon_crtc->h_border;
715b1714d3SAlex Deucher 		args.usOverscanLeft = radeon_crtc->h_border;
725b1714d3SAlex Deucher 		args.usOverscanBottom = radeon_crtc->v_border;
735b1714d3SAlex Deucher 		args.usOverscanTop = radeon_crtc->v_border;
74c93bb85bSJerome Glisse 		break;
75c93bb85bSJerome Glisse 	}
765b1714d3SAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
77c93bb85bSJerome Glisse }
78c93bb85bSJerome Glisse 
79c93bb85bSJerome Glisse static void atombios_scaler_setup(struct drm_crtc *crtc)
80c93bb85bSJerome Glisse {
81c93bb85bSJerome Glisse 	struct drm_device *dev = crtc->dev;
82c93bb85bSJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
83c93bb85bSJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
84c93bb85bSJerome Glisse 	ENABLE_SCALER_PS_ALLOCATION args;
85c93bb85bSJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
864ce001abSDave Airlie 
87c93bb85bSJerome Glisse 	/* fixme - fill in enc_priv for atom dac */
88c93bb85bSJerome Glisse 	enum radeon_tv_std tv_std = TV_STD_NTSC;
894ce001abSDave Airlie 	bool is_tv = false, is_cv = false;
904ce001abSDave Airlie 	struct drm_encoder *encoder;
91c93bb85bSJerome Glisse 
92c93bb85bSJerome Glisse 	if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id)
93c93bb85bSJerome Glisse 		return;
94c93bb85bSJerome Glisse 
954ce001abSDave Airlie 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
964ce001abSDave Airlie 		/* find tv std */
974ce001abSDave Airlie 		if (encoder->crtc == crtc) {
984ce001abSDave Airlie 			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
994ce001abSDave Airlie 			if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
1004ce001abSDave Airlie 				struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv;
1014ce001abSDave Airlie 				tv_std = tv_dac->tv_std;
1024ce001abSDave Airlie 				is_tv = true;
1034ce001abSDave Airlie 			}
1044ce001abSDave Airlie 		}
1054ce001abSDave Airlie 	}
1064ce001abSDave Airlie 
107c93bb85bSJerome Glisse 	memset(&args, 0, sizeof(args));
108c93bb85bSJerome Glisse 
109c93bb85bSJerome Glisse 	args.ucScaler = radeon_crtc->crtc_id;
110c93bb85bSJerome Glisse 
1114ce001abSDave Airlie 	if (is_tv) {
112c93bb85bSJerome Glisse 		switch (tv_std) {
113c93bb85bSJerome Glisse 		case TV_STD_NTSC:
114c93bb85bSJerome Glisse 		default:
115c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_NTSC;
116c93bb85bSJerome Glisse 			break;
117c93bb85bSJerome Glisse 		case TV_STD_PAL:
118c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_PAL;
119c93bb85bSJerome Glisse 			break;
120c93bb85bSJerome Glisse 		case TV_STD_PAL_M:
121c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_PALM;
122c93bb85bSJerome Glisse 			break;
123c93bb85bSJerome Glisse 		case TV_STD_PAL_60:
124c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_PAL60;
125c93bb85bSJerome Glisse 			break;
126c93bb85bSJerome Glisse 		case TV_STD_NTSC_J:
127c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_NTSCJ;
128c93bb85bSJerome Glisse 			break;
129c93bb85bSJerome Glisse 		case TV_STD_SCART_PAL:
130c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_PAL; /* ??? */
131c93bb85bSJerome Glisse 			break;
132c93bb85bSJerome Glisse 		case TV_STD_SECAM:
133c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_SECAM;
134c93bb85bSJerome Glisse 			break;
135c93bb85bSJerome Glisse 		case TV_STD_PAL_CN:
136c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_PALCN;
137c93bb85bSJerome Glisse 			break;
138c93bb85bSJerome Glisse 		}
139c93bb85bSJerome Glisse 		args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
1404ce001abSDave Airlie 	} else if (is_cv) {
141c93bb85bSJerome Glisse 		args.ucTVStandard = ATOM_TV_CV;
142c93bb85bSJerome Glisse 		args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
143c93bb85bSJerome Glisse 	} else {
144c93bb85bSJerome Glisse 		switch (radeon_crtc->rmx_type) {
145c93bb85bSJerome Glisse 		case RMX_FULL:
146c93bb85bSJerome Glisse 			args.ucEnable = ATOM_SCALER_EXPANSION;
147c93bb85bSJerome Glisse 			break;
148c93bb85bSJerome Glisse 		case RMX_CENTER:
149c93bb85bSJerome Glisse 			args.ucEnable = ATOM_SCALER_CENTER;
150c93bb85bSJerome Glisse 			break;
151c93bb85bSJerome Glisse 		case RMX_ASPECT:
152c93bb85bSJerome Glisse 			args.ucEnable = ATOM_SCALER_EXPANSION;
153c93bb85bSJerome Glisse 			break;
154c93bb85bSJerome Glisse 		default:
155c93bb85bSJerome Glisse 			if (ASIC_IS_AVIVO(rdev))
156c93bb85bSJerome Glisse 				args.ucEnable = ATOM_SCALER_DISABLE;
157c93bb85bSJerome Glisse 			else
158c93bb85bSJerome Glisse 				args.ucEnable = ATOM_SCALER_CENTER;
159c93bb85bSJerome Glisse 			break;
160c93bb85bSJerome Glisse 		}
161c93bb85bSJerome Glisse 	}
162c93bb85bSJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
1634ce001abSDave Airlie 	if ((is_tv || is_cv)
1644ce001abSDave Airlie 	    && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_R580) {
1654ce001abSDave Airlie 		atom_rv515_force_tv_scaler(rdev, radeon_crtc);
166c93bb85bSJerome Glisse 	}
167c93bb85bSJerome Glisse }
168c93bb85bSJerome Glisse 
169771fe6b9SJerome Glisse static void atombios_lock_crtc(struct drm_crtc *crtc, int lock)
170771fe6b9SJerome Glisse {
171771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
172771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
173771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
174771fe6b9SJerome Glisse 	int index =
175771fe6b9SJerome Glisse 	    GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
176771fe6b9SJerome Glisse 	ENABLE_CRTC_PS_ALLOCATION args;
177771fe6b9SJerome Glisse 
178771fe6b9SJerome Glisse 	memset(&args, 0, sizeof(args));
179771fe6b9SJerome Glisse 
180771fe6b9SJerome Glisse 	args.ucCRTC = radeon_crtc->crtc_id;
181771fe6b9SJerome Glisse 	args.ucEnable = lock;
182771fe6b9SJerome Glisse 
183771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
184771fe6b9SJerome Glisse }
185771fe6b9SJerome Glisse 
186771fe6b9SJerome Glisse static void atombios_enable_crtc(struct drm_crtc *crtc, int state)
187771fe6b9SJerome Glisse {
188771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
189771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
190771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
191771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
192771fe6b9SJerome Glisse 	ENABLE_CRTC_PS_ALLOCATION args;
193771fe6b9SJerome Glisse 
194771fe6b9SJerome Glisse 	memset(&args, 0, sizeof(args));
195771fe6b9SJerome Glisse 
196771fe6b9SJerome Glisse 	args.ucCRTC = radeon_crtc->crtc_id;
197771fe6b9SJerome Glisse 	args.ucEnable = state;
198771fe6b9SJerome Glisse 
199771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
200771fe6b9SJerome Glisse }
201771fe6b9SJerome Glisse 
202771fe6b9SJerome Glisse static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state)
203771fe6b9SJerome Glisse {
204771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
205771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
206771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
207771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq);
208771fe6b9SJerome Glisse 	ENABLE_CRTC_PS_ALLOCATION args;
209771fe6b9SJerome Glisse 
210771fe6b9SJerome Glisse 	memset(&args, 0, sizeof(args));
211771fe6b9SJerome Glisse 
212771fe6b9SJerome Glisse 	args.ucCRTC = radeon_crtc->crtc_id;
213771fe6b9SJerome Glisse 	args.ucEnable = state;
214771fe6b9SJerome Glisse 
215771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
216771fe6b9SJerome Glisse }
217771fe6b9SJerome Glisse 
218771fe6b9SJerome Glisse static void atombios_blank_crtc(struct drm_crtc *crtc, int state)
219771fe6b9SJerome Glisse {
220771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
221771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
222771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
223771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
224771fe6b9SJerome Glisse 	BLANK_CRTC_PS_ALLOCATION args;
225771fe6b9SJerome Glisse 
226771fe6b9SJerome Glisse 	memset(&args, 0, sizeof(args));
227771fe6b9SJerome Glisse 
228771fe6b9SJerome Glisse 	args.ucCRTC = radeon_crtc->crtc_id;
229771fe6b9SJerome Glisse 	args.ucBlanking = state;
230771fe6b9SJerome Glisse 
231771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
232771fe6b9SJerome Glisse }
233771fe6b9SJerome Glisse 
234771fe6b9SJerome Glisse void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
235771fe6b9SJerome Glisse {
236771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
237771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
238500b7587SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
239771fe6b9SJerome Glisse 
240771fe6b9SJerome Glisse 	switch (mode) {
241771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_ON:
242d7311171SAlex Deucher 		radeon_crtc->enabled = true;
243d7311171SAlex Deucher 		/* adjust pm to dpms changes BEFORE enabling crtcs */
244d7311171SAlex Deucher 		radeon_pm_compute_clocks(rdev);
24537b4390eSAlex Deucher 		atombios_enable_crtc(crtc, ATOM_ENABLE);
246771fe6b9SJerome Glisse 		if (ASIC_IS_DCE3(rdev))
24737b4390eSAlex Deucher 			atombios_enable_crtc_memreq(crtc, ATOM_ENABLE);
24837b4390eSAlex Deucher 		atombios_blank_crtc(crtc, ATOM_DISABLE);
249500b7587SAlex Deucher 		drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
250500b7587SAlex Deucher 		radeon_crtc_load_lut(crtc);
251771fe6b9SJerome Glisse 		break;
252771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_STANDBY:
253771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_SUSPEND:
254771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_OFF:
255500b7587SAlex Deucher 		drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
25637b4390eSAlex Deucher 		atombios_blank_crtc(crtc, ATOM_ENABLE);
257771fe6b9SJerome Glisse 		if (ASIC_IS_DCE3(rdev))
25837b4390eSAlex Deucher 			atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);
25937b4390eSAlex Deucher 		atombios_enable_crtc(crtc, ATOM_DISABLE);
260a48b9b4eSAlex Deucher 		radeon_crtc->enabled = false;
261d7311171SAlex Deucher 		/* adjust pm to dpms changes AFTER disabling crtcs */
262d7311171SAlex Deucher 		radeon_pm_compute_clocks(rdev);
263771fe6b9SJerome Glisse 		break;
264771fe6b9SJerome Glisse 	}
265771fe6b9SJerome Glisse }
266771fe6b9SJerome Glisse 
267771fe6b9SJerome Glisse static void
268771fe6b9SJerome Glisse atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
2695a9bcaccSAlex Deucher 			     struct drm_display_mode *mode)
270771fe6b9SJerome Glisse {
2715a9bcaccSAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
272771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
273771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
2745a9bcaccSAlex Deucher 	SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
275771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
2765a9bcaccSAlex Deucher 	u16 misc = 0;
277771fe6b9SJerome Glisse 
2785a9bcaccSAlex Deucher 	memset(&args, 0, sizeof(args));
2795b1714d3SAlex Deucher 	args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (radeon_crtc->h_border * 2));
2805a9bcaccSAlex Deucher 	args.usH_Blanking_Time =
2815b1714d3SAlex Deucher 		cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (radeon_crtc->h_border * 2));
2825b1714d3SAlex Deucher 	args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (radeon_crtc->v_border * 2));
2835a9bcaccSAlex Deucher 	args.usV_Blanking_Time =
2845b1714d3SAlex Deucher 		cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (radeon_crtc->v_border * 2));
2855a9bcaccSAlex Deucher 	args.usH_SyncOffset =
2865b1714d3SAlex Deucher 		cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + radeon_crtc->h_border);
2875a9bcaccSAlex Deucher 	args.usH_SyncWidth =
2885a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
2895a9bcaccSAlex Deucher 	args.usV_SyncOffset =
2905b1714d3SAlex Deucher 		cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + radeon_crtc->v_border);
2915a9bcaccSAlex Deucher 	args.usV_SyncWidth =
2925a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
2935b1714d3SAlex Deucher 	args.ucH_Border = radeon_crtc->h_border;
2945b1714d3SAlex Deucher 	args.ucV_Border = radeon_crtc->v_border;
2955a9bcaccSAlex Deucher 
2965a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
2975a9bcaccSAlex Deucher 		misc |= ATOM_VSYNC_POLARITY;
2985a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
2995a9bcaccSAlex Deucher 		misc |= ATOM_HSYNC_POLARITY;
3005a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_CSYNC)
3015a9bcaccSAlex Deucher 		misc |= ATOM_COMPOSITESYNC;
3025a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
3035a9bcaccSAlex Deucher 		misc |= ATOM_INTERLACE;
3045a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
3055a9bcaccSAlex Deucher 		misc |= ATOM_DOUBLE_CLOCK_MODE;
3065a9bcaccSAlex Deucher 
3075a9bcaccSAlex Deucher 	args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
3085a9bcaccSAlex Deucher 	args.ucCRTC = radeon_crtc->crtc_id;
309771fe6b9SJerome Glisse 
3105a9bcaccSAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
311771fe6b9SJerome Glisse }
312771fe6b9SJerome Glisse 
3135a9bcaccSAlex Deucher static void atombios_crtc_set_timing(struct drm_crtc *crtc,
3145a9bcaccSAlex Deucher 				     struct drm_display_mode *mode)
315771fe6b9SJerome Glisse {
3165a9bcaccSAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
317771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
318771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
3195a9bcaccSAlex Deucher 	SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args;
320771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing);
3215a9bcaccSAlex Deucher 	u16 misc = 0;
322771fe6b9SJerome Glisse 
3235a9bcaccSAlex Deucher 	memset(&args, 0, sizeof(args));
3245a9bcaccSAlex Deucher 	args.usH_Total = cpu_to_le16(mode->crtc_htotal);
3255a9bcaccSAlex Deucher 	args.usH_Disp = cpu_to_le16(mode->crtc_hdisplay);
3265a9bcaccSAlex Deucher 	args.usH_SyncStart = cpu_to_le16(mode->crtc_hsync_start);
3275a9bcaccSAlex Deucher 	args.usH_SyncWidth =
3285a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
3295a9bcaccSAlex Deucher 	args.usV_Total = cpu_to_le16(mode->crtc_vtotal);
3305a9bcaccSAlex Deucher 	args.usV_Disp = cpu_to_le16(mode->crtc_vdisplay);
3315a9bcaccSAlex Deucher 	args.usV_SyncStart = cpu_to_le16(mode->crtc_vsync_start);
3325a9bcaccSAlex Deucher 	args.usV_SyncWidth =
3335a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
3345a9bcaccSAlex Deucher 
3355a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
3365a9bcaccSAlex Deucher 		misc |= ATOM_VSYNC_POLARITY;
3375a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
3385a9bcaccSAlex Deucher 		misc |= ATOM_HSYNC_POLARITY;
3395a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_CSYNC)
3405a9bcaccSAlex Deucher 		misc |= ATOM_COMPOSITESYNC;
3415a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
3425a9bcaccSAlex Deucher 		misc |= ATOM_INTERLACE;
3435a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
3445a9bcaccSAlex Deucher 		misc |= ATOM_DOUBLE_CLOCK_MODE;
3455a9bcaccSAlex Deucher 
3465a9bcaccSAlex Deucher 	args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
3475a9bcaccSAlex Deucher 	args.ucCRTC = radeon_crtc->crtc_id;
348771fe6b9SJerome Glisse 
3495a9bcaccSAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
350771fe6b9SJerome Glisse }
351771fe6b9SJerome Glisse 
352b792210eSAlex Deucher static void atombios_disable_ss(struct drm_crtc *crtc)
353b792210eSAlex Deucher {
354b792210eSAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
355b792210eSAlex Deucher 	struct drm_device *dev = crtc->dev;
356b792210eSAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
357b792210eSAlex Deucher 	u32 ss_cntl;
358b792210eSAlex Deucher 
359b792210eSAlex Deucher 	if (ASIC_IS_DCE4(rdev)) {
360b792210eSAlex Deucher 		switch (radeon_crtc->pll_id) {
361b792210eSAlex Deucher 		case ATOM_PPLL1:
362b792210eSAlex Deucher 			ss_cntl = RREG32(EVERGREEN_P1PLL_SS_CNTL);
363b792210eSAlex Deucher 			ss_cntl &= ~EVERGREEN_PxPLL_SS_EN;
364b792210eSAlex Deucher 			WREG32(EVERGREEN_P1PLL_SS_CNTL, ss_cntl);
365b792210eSAlex Deucher 			break;
366b792210eSAlex Deucher 		case ATOM_PPLL2:
367b792210eSAlex Deucher 			ss_cntl = RREG32(EVERGREEN_P2PLL_SS_CNTL);
368b792210eSAlex Deucher 			ss_cntl &= ~EVERGREEN_PxPLL_SS_EN;
369b792210eSAlex Deucher 			WREG32(EVERGREEN_P2PLL_SS_CNTL, ss_cntl);
370b792210eSAlex Deucher 			break;
371b792210eSAlex Deucher 		case ATOM_DCPLL:
372b792210eSAlex Deucher 		case ATOM_PPLL_INVALID:
373b792210eSAlex Deucher 			return;
374b792210eSAlex Deucher 		}
375b792210eSAlex Deucher 	} else if (ASIC_IS_AVIVO(rdev)) {
376b792210eSAlex Deucher 		switch (radeon_crtc->pll_id) {
377b792210eSAlex Deucher 		case ATOM_PPLL1:
378b792210eSAlex Deucher 			ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL);
379b792210eSAlex Deucher 			ss_cntl &= ~1;
380b792210eSAlex Deucher 			WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl);
381b792210eSAlex Deucher 			break;
382b792210eSAlex Deucher 		case ATOM_PPLL2:
383b792210eSAlex Deucher 			ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL);
384b792210eSAlex Deucher 			ss_cntl &= ~1;
385b792210eSAlex Deucher 			WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl);
386b792210eSAlex Deucher 			break;
387b792210eSAlex Deucher 		case ATOM_DCPLL:
388b792210eSAlex Deucher 		case ATOM_PPLL_INVALID:
389b792210eSAlex Deucher 			return;
390b792210eSAlex Deucher 		}
391b792210eSAlex Deucher 	}
392b792210eSAlex Deucher }
393b792210eSAlex Deucher 
394b792210eSAlex Deucher 
39526b9fc3aSAlex Deucher union atom_enable_ss {
39626b9fc3aSAlex Deucher 	ENABLE_LVDS_SS_PARAMETERS legacy;
39726b9fc3aSAlex Deucher 	ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
39826b9fc3aSAlex Deucher };
39926b9fc3aSAlex Deucher 
400b792210eSAlex Deucher static void atombios_enable_ss(struct drm_crtc *crtc)
401ebbe1cb9SAlex Deucher {
402ebbe1cb9SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
403ebbe1cb9SAlex Deucher 	struct drm_device *dev = crtc->dev;
404ebbe1cb9SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
405ebbe1cb9SAlex Deucher 	struct drm_encoder *encoder = NULL;
406ebbe1cb9SAlex Deucher 	struct radeon_encoder *radeon_encoder = NULL;
407ebbe1cb9SAlex Deucher 	struct radeon_encoder_atom_dig *dig = NULL;
408ebbe1cb9SAlex Deucher 	int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
40926b9fc3aSAlex Deucher 	union atom_enable_ss args;
410ebbe1cb9SAlex Deucher 	uint16_t percentage = 0;
411ebbe1cb9SAlex Deucher 	uint8_t type = 0, step = 0, delay = 0, range = 0;
412ebbe1cb9SAlex Deucher 
413bcc1c2a1SAlex Deucher 	/* XXX add ss support for DCE4 */
414bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev))
415bcc1c2a1SAlex Deucher 		return;
416bcc1c2a1SAlex Deucher 
417ebbe1cb9SAlex Deucher 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
418ebbe1cb9SAlex Deucher 		if (encoder->crtc == crtc) {
419ebbe1cb9SAlex Deucher 			radeon_encoder = to_radeon_encoder(encoder);
420ebbe1cb9SAlex Deucher 			/* only enable spread spectrum on LVDS */
421d11aa88bSAlex Deucher 			if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
422d11aa88bSAlex Deucher 				dig = radeon_encoder->enc_priv;
423ebbe1cb9SAlex Deucher 				if (dig && dig->ss) {
424ebbe1cb9SAlex Deucher 					percentage = dig->ss->percentage;
425ebbe1cb9SAlex Deucher 					type = dig->ss->type;
426ebbe1cb9SAlex Deucher 					step = dig->ss->step;
427ebbe1cb9SAlex Deucher 					delay = dig->ss->delay;
428ebbe1cb9SAlex Deucher 					range = dig->ss->range;
429b792210eSAlex Deucher 				} else
430ebbe1cb9SAlex Deucher 					return;
431b792210eSAlex Deucher 			} else
432d11aa88bSAlex Deucher 				return;
433ebbe1cb9SAlex Deucher 			break;
434ebbe1cb9SAlex Deucher 		}
435ebbe1cb9SAlex Deucher 	}
436ebbe1cb9SAlex Deucher 
437ebbe1cb9SAlex Deucher 	if (!radeon_encoder)
438ebbe1cb9SAlex Deucher 		return;
439ebbe1cb9SAlex Deucher 
440ebbe1cb9SAlex Deucher 	memset(&args, 0, sizeof(args));
44126b9fc3aSAlex Deucher 	if (ASIC_IS_AVIVO(rdev)) {
44226b9fc3aSAlex Deucher 		args.v1.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
44326b9fc3aSAlex Deucher 		args.v1.ucSpreadSpectrumType = type;
44426b9fc3aSAlex Deucher 		args.v1.ucSpreadSpectrumStep = step;
44526b9fc3aSAlex Deucher 		args.v1.ucSpreadSpectrumDelay = delay;
44626b9fc3aSAlex Deucher 		args.v1.ucSpreadSpectrumRange = range;
44726b9fc3aSAlex Deucher 		args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
448b792210eSAlex Deucher 		args.v1.ucEnable = ATOM_ENABLE;
449ebbe1cb9SAlex Deucher 	} else {
45026b9fc3aSAlex Deucher 		args.legacy.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
45126b9fc3aSAlex Deucher 		args.legacy.ucSpreadSpectrumType = type;
45226b9fc3aSAlex Deucher 		args.legacy.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2;
45326b9fc3aSAlex Deucher 		args.legacy.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4;
454b792210eSAlex Deucher 		args.legacy.ucEnable = ATOM_ENABLE;
455ebbe1cb9SAlex Deucher 	}
45626b9fc3aSAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
457ebbe1cb9SAlex Deucher }
458ebbe1cb9SAlex Deucher 
4594eaeca33SAlex Deucher union adjust_pixel_clock {
4604eaeca33SAlex Deucher 	ADJUST_DISPLAY_PLL_PS_ALLOCATION v1;
461bcc1c2a1SAlex Deucher 	ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3;
4624eaeca33SAlex Deucher };
4634eaeca33SAlex Deucher 
4644eaeca33SAlex Deucher static u32 atombios_adjust_pll(struct drm_crtc *crtc,
4654eaeca33SAlex Deucher 			       struct drm_display_mode *mode,
4664eaeca33SAlex Deucher 			       struct radeon_pll *pll)
467771fe6b9SJerome Glisse {
468771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
469771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
470771fe6b9SJerome Glisse 	struct drm_encoder *encoder = NULL;
471771fe6b9SJerome Glisse 	struct radeon_encoder *radeon_encoder = NULL;
4724eaeca33SAlex Deucher 	u32 adjusted_clock = mode->clock;
473bcc1c2a1SAlex Deucher 	int encoder_mode = 0;
474fbee67a6SAlex Deucher 	u32 dp_clock = mode->clock;
475fbee67a6SAlex Deucher 	int bpc = 8;
476fc10332bSAlex Deucher 
4774eaeca33SAlex Deucher 	/* reset the pll flags */
4784eaeca33SAlex Deucher 	pll->flags = 0;
479771fe6b9SJerome Glisse 
4807c27f87dSAlex Deucher 	/* select the PLL algo */
4817c27f87dSAlex Deucher 	if (ASIC_IS_AVIVO(rdev)) {
482383be5d1SAlex Deucher 		if (radeon_new_pll == 0)
483383be5d1SAlex Deucher 			pll->algo = PLL_ALGO_LEGACY;
484383be5d1SAlex Deucher 		else
485383be5d1SAlex Deucher 			pll->algo = PLL_ALGO_NEW;
486383be5d1SAlex Deucher 	} else {
487383be5d1SAlex Deucher 		if (radeon_new_pll == 1)
488383be5d1SAlex Deucher 			pll->algo = PLL_ALGO_NEW;
4897c27f87dSAlex Deucher 		else
4907c27f87dSAlex Deucher 			pll->algo = PLL_ALGO_LEGACY;
491383be5d1SAlex Deucher 	}
4927c27f87dSAlex Deucher 
493771fe6b9SJerome Glisse 	if (ASIC_IS_AVIVO(rdev)) {
494eb1300bcSAlex Deucher 		if ((rdev->family == CHIP_RS600) ||
495eb1300bcSAlex Deucher 		    (rdev->family == CHIP_RS690) ||
496eb1300bcSAlex Deucher 		    (rdev->family == CHIP_RS740))
4972ff776cfSAlex Deucher 			pll->flags |= (/*RADEON_PLL_USE_FRAC_FB_DIV |*/
498eb1300bcSAlex Deucher 				       RADEON_PLL_PREFER_CLOSEST_LOWER);
499eb1300bcSAlex Deucher 
500771fe6b9SJerome Glisse 		if (ASIC_IS_DCE32(rdev) && mode->clock > 200000)	/* range limits??? */
501fc10332bSAlex Deucher 			pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
502771fe6b9SJerome Glisse 		else
503fc10332bSAlex Deucher 			pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
504771fe6b9SJerome Glisse 	} else {
505fc10332bSAlex Deucher 		pll->flags |= RADEON_PLL_LEGACY;
506771fe6b9SJerome Glisse 
507771fe6b9SJerome Glisse 		if (mode->clock > 200000)	/* range limits??? */
508fc10332bSAlex Deucher 			pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
509771fe6b9SJerome Glisse 		else
510fc10332bSAlex Deucher 			pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
511771fe6b9SJerome Glisse 
512771fe6b9SJerome Glisse 	}
513771fe6b9SJerome Glisse 
514771fe6b9SJerome Glisse 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
515771fe6b9SJerome Glisse 		if (encoder->crtc == crtc) {
5164eaeca33SAlex Deucher 			radeon_encoder = to_radeon_encoder(encoder);
517bcc1c2a1SAlex Deucher 			encoder_mode = atombios_get_encoder_mode(encoder);
518fbee67a6SAlex Deucher 			if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) {
519fbee67a6SAlex Deucher 				struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
520fbee67a6SAlex Deucher 				if (connector) {
521fbee67a6SAlex Deucher 					struct radeon_connector *radeon_connector = to_radeon_connector(connector);
522fbee67a6SAlex Deucher 					struct radeon_connector_atom_dig *dig_connector =
523fbee67a6SAlex Deucher 						radeon_connector->con_priv;
524fbee67a6SAlex Deucher 
525fbee67a6SAlex Deucher 					dp_clock = dig_connector->dp_clock;
526fbee67a6SAlex Deucher 				}
527fbee67a6SAlex Deucher 			}
528fbee67a6SAlex Deucher 
5294eaeca33SAlex Deucher 			if (ASIC_IS_AVIVO(rdev)) {
5304eaeca33SAlex Deucher 				/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
5314eaeca33SAlex Deucher 				if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
5324eaeca33SAlex Deucher 					adjusted_clock = mode->clock * 2;
533a1a4b23bSAlex Deucher 				if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
534a1a4b23bSAlex Deucher 					pll->algo = PLL_ALGO_LEGACY;
535a1a4b23bSAlex Deucher 					pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER;
536a1a4b23bSAlex Deucher 				}
5370d9958b1SAlex Deucher 				/* There is some evidence (often anecdotal) that RV515 LVDS
5380d9958b1SAlex Deucher 				 * (on some boards at least) prefers the legacy algo.  I'm not
5390d9958b1SAlex Deucher 				 * sure whether this should handled generically or on a
5400d9958b1SAlex Deucher 				 * case-by-case quirk basis.  Both algos should work fine in the
5410d9958b1SAlex Deucher 				 * majority of cases.
5420d9958b1SAlex Deucher 				 */
5430d9958b1SAlex Deucher 				if ((radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) &&
5440d9958b1SAlex Deucher 				    (rdev->family == CHIP_RV515)) {
5450d9958b1SAlex Deucher 					/* allow the user to overrride just in case */
5460d9958b1SAlex Deucher 					if (radeon_new_pll == 1)
5470d9958b1SAlex Deucher 						pll->algo = PLL_ALGO_NEW;
5480d9958b1SAlex Deucher 					else
5490d9958b1SAlex Deucher 						pll->algo = PLL_ALGO_LEGACY;
5500d9958b1SAlex Deucher 				}
5514eaeca33SAlex Deucher 			} else {
5524eaeca33SAlex Deucher 				if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
553fc10332bSAlex Deucher 					pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
5544eaeca33SAlex Deucher 				if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS)
555fc10332bSAlex Deucher 					pll->flags |= RADEON_PLL_USE_REF_DIV;
556771fe6b9SJerome Glisse 			}
5573ce0a23dSJerome Glisse 			break;
558771fe6b9SJerome Glisse 		}
559771fe6b9SJerome Glisse 	}
560771fe6b9SJerome Glisse 
5612606c886SAlex Deucher 	/* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock
5622606c886SAlex Deucher 	 * accordingly based on the encoder/transmitter to work around
5632606c886SAlex Deucher 	 * special hw requirements.
5642606c886SAlex Deucher 	 */
5652606c886SAlex Deucher 	if (ASIC_IS_DCE3(rdev)) {
5664eaeca33SAlex Deucher 		union adjust_pixel_clock args;
5674eaeca33SAlex Deucher 		u8 frev, crev;
5684eaeca33SAlex Deucher 		int index;
5692606c886SAlex Deucher 
5702606c886SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
571a084e6eeSAlex Deucher 		if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
572a084e6eeSAlex Deucher 					   &crev))
573a084e6eeSAlex Deucher 			return adjusted_clock;
5744eaeca33SAlex Deucher 
5754eaeca33SAlex Deucher 		memset(&args, 0, sizeof(args));
5764eaeca33SAlex Deucher 
5774eaeca33SAlex Deucher 		switch (frev) {
5784eaeca33SAlex Deucher 		case 1:
5794eaeca33SAlex Deucher 			switch (crev) {
5804eaeca33SAlex Deucher 			case 1:
5814eaeca33SAlex Deucher 			case 2:
5824eaeca33SAlex Deucher 				args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
5834eaeca33SAlex Deucher 				args.v1.ucTransmitterID = radeon_encoder->encoder_id;
584bcc1c2a1SAlex Deucher 				args.v1.ucEncodeMode = encoder_mode;
585fbee67a6SAlex Deucher 				if (encoder_mode == ATOM_ENCODER_MODE_DP) {
586fbee67a6SAlex Deucher 					/* may want to enable SS on DP eventually */
587fbee67a6SAlex Deucher 					/* args.v1.ucConfig |=
588fbee67a6SAlex Deucher 					   ADJUST_DISPLAY_CONFIG_SS_ENABLE;*/
589fbee67a6SAlex Deucher 				} else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) {
590fbee67a6SAlex Deucher 					args.v1.ucConfig |=
591fbee67a6SAlex Deucher 						ADJUST_DISPLAY_CONFIG_SS_ENABLE;
592fbee67a6SAlex Deucher 				}
5934eaeca33SAlex Deucher 
5942606c886SAlex Deucher 				atom_execute_table(rdev->mode_info.atom_context,
5954eaeca33SAlex Deucher 						   index, (uint32_t *)&args);
5964eaeca33SAlex Deucher 				adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;
5974eaeca33SAlex Deucher 				break;
598bcc1c2a1SAlex Deucher 			case 3:
599bcc1c2a1SAlex Deucher 				args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10);
600bcc1c2a1SAlex Deucher 				args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id;
601bcc1c2a1SAlex Deucher 				args.v3.sInput.ucEncodeMode = encoder_mode;
602bcc1c2a1SAlex Deucher 				args.v3.sInput.ucDispPllConfig = 0;
603bcc1c2a1SAlex Deucher 				if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
604bcc1c2a1SAlex Deucher 					struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
605bcc1c2a1SAlex Deucher 
606fbee67a6SAlex Deucher 					if (encoder_mode == ATOM_ENCODER_MODE_DP) {
607fbee67a6SAlex Deucher 						/* may want to enable SS on DP/eDP eventually */
608fbee67a6SAlex Deucher 						/*args.v3.sInput.ucDispPllConfig |=
609fbee67a6SAlex Deucher 						  DISPPLL_CONFIG_SS_ENABLE;*/
610bcc1c2a1SAlex Deucher 						args.v3.sInput.ucDispPllConfig |=
611bcc1c2a1SAlex Deucher 							DISPPLL_CONFIG_COHERENT_MODE;
612fbee67a6SAlex Deucher 						/* 16200 or 27000 */
613fbee67a6SAlex Deucher 						args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
614fbee67a6SAlex Deucher 					} else {
615fbee67a6SAlex Deucher 						if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
616fbee67a6SAlex Deucher 							/* deep color support */
617fbee67a6SAlex Deucher 							args.v3.sInput.usPixelClock =
618fbee67a6SAlex Deucher 								cpu_to_le16((mode->clock * bpc / 8) / 10);
619fbee67a6SAlex Deucher 						}
620bcc1c2a1SAlex Deucher 						if (dig->coherent_mode)
621bcc1c2a1SAlex Deucher 							args.v3.sInput.ucDispPllConfig |=
622bcc1c2a1SAlex Deucher 								DISPPLL_CONFIG_COHERENT_MODE;
623bcc1c2a1SAlex Deucher 						if (mode->clock > 165000)
624bcc1c2a1SAlex Deucher 							args.v3.sInput.ucDispPllConfig |=
625bcc1c2a1SAlex Deucher 								DISPPLL_CONFIG_DUAL_LINK;
626bcc1c2a1SAlex Deucher 					}
627bcc1c2a1SAlex Deucher 				} else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
628fbee67a6SAlex Deucher 					if (encoder_mode == ATOM_ENCODER_MODE_DP) {
629bcc1c2a1SAlex Deucher 						/* may want to enable SS on DP/eDP eventually */
6309f998ad7SAlex Deucher 						/*args.v3.sInput.ucDispPllConfig |=
6319f998ad7SAlex Deucher 						  DISPPLL_CONFIG_SS_ENABLE;*/
632bcc1c2a1SAlex Deucher 						args.v3.sInput.ucDispPllConfig |=
6339f998ad7SAlex Deucher 							DISPPLL_CONFIG_COHERENT_MODE;
634fbee67a6SAlex Deucher 						/* 16200 or 27000 */
635fbee67a6SAlex Deucher 						args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
636fbee67a6SAlex Deucher 					} else if (encoder_mode == ATOM_ENCODER_MODE_LVDS) {
637fbee67a6SAlex Deucher 						/* want to enable SS on LVDS eventually */
638fbee67a6SAlex Deucher 						/*args.v3.sInput.ucDispPllConfig |=
639fbee67a6SAlex Deucher 						  DISPPLL_CONFIG_SS_ENABLE;*/
640fbee67a6SAlex Deucher 					} else {
641bcc1c2a1SAlex Deucher 						if (mode->clock > 165000)
642bcc1c2a1SAlex Deucher 							args.v3.sInput.ucDispPllConfig |=
643bcc1c2a1SAlex Deucher 								DISPPLL_CONFIG_DUAL_LINK;
644bcc1c2a1SAlex Deucher 					}
6459f998ad7SAlex Deucher 				}
646bcc1c2a1SAlex Deucher 				atom_execute_table(rdev->mode_info.atom_context,
647bcc1c2a1SAlex Deucher 						   index, (uint32_t *)&args);
648bcc1c2a1SAlex Deucher 				adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
649bcc1c2a1SAlex Deucher 				if (args.v3.sOutput.ucRefDiv) {
650bcc1c2a1SAlex Deucher 					pll->flags |= RADEON_PLL_USE_REF_DIV;
651bcc1c2a1SAlex Deucher 					pll->reference_div = args.v3.sOutput.ucRefDiv;
652bcc1c2a1SAlex Deucher 				}
653bcc1c2a1SAlex Deucher 				if (args.v3.sOutput.ucPostDiv) {
654bcc1c2a1SAlex Deucher 					pll->flags |= RADEON_PLL_USE_POST_DIV;
655bcc1c2a1SAlex Deucher 					pll->post_div = args.v3.sOutput.ucPostDiv;
656bcc1c2a1SAlex Deucher 				}
657bcc1c2a1SAlex Deucher 				break;
6584eaeca33SAlex Deucher 			default:
6594eaeca33SAlex Deucher 				DRM_ERROR("Unknown table version %d %d\n", frev, crev);
6604eaeca33SAlex Deucher 				return adjusted_clock;
661d56ef9c8SAlex Deucher 			}
6624eaeca33SAlex Deucher 			break;
6634eaeca33SAlex Deucher 		default:
6644eaeca33SAlex Deucher 			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
6654eaeca33SAlex Deucher 			return adjusted_clock;
6664eaeca33SAlex Deucher 		}
6674eaeca33SAlex Deucher 	}
6684eaeca33SAlex Deucher 	return adjusted_clock;
6694eaeca33SAlex Deucher }
6704eaeca33SAlex Deucher 
6714eaeca33SAlex Deucher union set_pixel_clock {
6724eaeca33SAlex Deucher 	SET_PIXEL_CLOCK_PS_ALLOCATION base;
6734eaeca33SAlex Deucher 	PIXEL_CLOCK_PARAMETERS v1;
6744eaeca33SAlex Deucher 	PIXEL_CLOCK_PARAMETERS_V2 v2;
6754eaeca33SAlex Deucher 	PIXEL_CLOCK_PARAMETERS_V3 v3;
676bcc1c2a1SAlex Deucher 	PIXEL_CLOCK_PARAMETERS_V5 v5;
6774eaeca33SAlex Deucher };
6784eaeca33SAlex Deucher 
679bcc1c2a1SAlex Deucher static void atombios_crtc_set_dcpll(struct drm_crtc *crtc)
680bcc1c2a1SAlex Deucher {
681bcc1c2a1SAlex Deucher 	struct drm_device *dev = crtc->dev;
682bcc1c2a1SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
683bcc1c2a1SAlex Deucher 	u8 frev, crev;
684bcc1c2a1SAlex Deucher 	int index;
685bcc1c2a1SAlex Deucher 	union set_pixel_clock args;
686bcc1c2a1SAlex Deucher 
687bcc1c2a1SAlex Deucher 	memset(&args, 0, sizeof(args));
688bcc1c2a1SAlex Deucher 
689bcc1c2a1SAlex Deucher 	index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
690a084e6eeSAlex Deucher 	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
691a084e6eeSAlex Deucher 				   &crev))
692a084e6eeSAlex Deucher 		return;
693bcc1c2a1SAlex Deucher 
694bcc1c2a1SAlex Deucher 	switch (frev) {
695bcc1c2a1SAlex Deucher 	case 1:
696bcc1c2a1SAlex Deucher 		switch (crev) {
697bcc1c2a1SAlex Deucher 		case 5:
698bcc1c2a1SAlex Deucher 			/* if the default dcpll clock is specified,
699bcc1c2a1SAlex Deucher 			 * SetPixelClock provides the dividers
700bcc1c2a1SAlex Deucher 			 */
701bcc1c2a1SAlex Deucher 			args.v5.ucCRTC = ATOM_CRTC_INVALID;
702bcc1c2a1SAlex Deucher 			args.v5.usPixelClock = rdev->clock.default_dispclk;
703bcc1c2a1SAlex Deucher 			args.v5.ucPpll = ATOM_DCPLL;
704bcc1c2a1SAlex Deucher 			break;
705bcc1c2a1SAlex Deucher 		default:
706bcc1c2a1SAlex Deucher 			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
707bcc1c2a1SAlex Deucher 			return;
708bcc1c2a1SAlex Deucher 		}
709bcc1c2a1SAlex Deucher 		break;
710bcc1c2a1SAlex Deucher 	default:
711bcc1c2a1SAlex Deucher 		DRM_ERROR("Unknown table version %d %d\n", frev, crev);
712bcc1c2a1SAlex Deucher 		return;
713bcc1c2a1SAlex Deucher 	}
714bcc1c2a1SAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
715bcc1c2a1SAlex Deucher }
716bcc1c2a1SAlex Deucher 
71737f9003bSAlex Deucher static void atombios_crtc_program_pll(struct drm_crtc *crtc,
71837f9003bSAlex Deucher 				      int crtc_id,
71937f9003bSAlex Deucher 				      int pll_id,
72037f9003bSAlex Deucher 				      u32 encoder_mode,
72137f9003bSAlex Deucher 				      u32 encoder_id,
72237f9003bSAlex Deucher 				      u32 clock,
72337f9003bSAlex Deucher 				      u32 ref_div,
72437f9003bSAlex Deucher 				      u32 fb_div,
72537f9003bSAlex Deucher 				      u32 frac_fb_div,
72637f9003bSAlex Deucher 				      u32 post_div)
72737f9003bSAlex Deucher {
72837f9003bSAlex Deucher 	struct drm_device *dev = crtc->dev;
72937f9003bSAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
73037f9003bSAlex Deucher 	u8 frev, crev;
73137f9003bSAlex Deucher 	int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
73237f9003bSAlex Deucher 	union set_pixel_clock args;
73337f9003bSAlex Deucher 
73437f9003bSAlex Deucher 	memset(&args, 0, sizeof(args));
73537f9003bSAlex Deucher 
73637f9003bSAlex Deucher 	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
73737f9003bSAlex Deucher 				   &crev))
73837f9003bSAlex Deucher 		return;
73937f9003bSAlex Deucher 
74037f9003bSAlex Deucher 	switch (frev) {
74137f9003bSAlex Deucher 	case 1:
74237f9003bSAlex Deucher 		switch (crev) {
74337f9003bSAlex Deucher 		case 1:
74437f9003bSAlex Deucher 			if (clock == ATOM_DISABLE)
74537f9003bSAlex Deucher 				return;
74637f9003bSAlex Deucher 			args.v1.usPixelClock = cpu_to_le16(clock / 10);
74737f9003bSAlex Deucher 			args.v1.usRefDiv = cpu_to_le16(ref_div);
74837f9003bSAlex Deucher 			args.v1.usFbDiv = cpu_to_le16(fb_div);
74937f9003bSAlex Deucher 			args.v1.ucFracFbDiv = frac_fb_div;
75037f9003bSAlex Deucher 			args.v1.ucPostDiv = post_div;
75137f9003bSAlex Deucher 			args.v1.ucPpll = pll_id;
75237f9003bSAlex Deucher 			args.v1.ucCRTC = crtc_id;
75337f9003bSAlex Deucher 			args.v1.ucRefDivSrc = 1;
75437f9003bSAlex Deucher 			break;
75537f9003bSAlex Deucher 		case 2:
75637f9003bSAlex Deucher 			args.v2.usPixelClock = cpu_to_le16(clock / 10);
75737f9003bSAlex Deucher 			args.v2.usRefDiv = cpu_to_le16(ref_div);
75837f9003bSAlex Deucher 			args.v2.usFbDiv = cpu_to_le16(fb_div);
75937f9003bSAlex Deucher 			args.v2.ucFracFbDiv = frac_fb_div;
76037f9003bSAlex Deucher 			args.v2.ucPostDiv = post_div;
76137f9003bSAlex Deucher 			args.v2.ucPpll = pll_id;
76237f9003bSAlex Deucher 			args.v2.ucCRTC = crtc_id;
76337f9003bSAlex Deucher 			args.v2.ucRefDivSrc = 1;
76437f9003bSAlex Deucher 			break;
76537f9003bSAlex Deucher 		case 3:
76637f9003bSAlex Deucher 			args.v3.usPixelClock = cpu_to_le16(clock / 10);
76737f9003bSAlex Deucher 			args.v3.usRefDiv = cpu_to_le16(ref_div);
76837f9003bSAlex Deucher 			args.v3.usFbDiv = cpu_to_le16(fb_div);
76937f9003bSAlex Deucher 			args.v3.ucFracFbDiv = frac_fb_div;
77037f9003bSAlex Deucher 			args.v3.ucPostDiv = post_div;
77137f9003bSAlex Deucher 			args.v3.ucPpll = pll_id;
77237f9003bSAlex Deucher 			args.v3.ucMiscInfo = (pll_id << 2);
77337f9003bSAlex Deucher 			args.v3.ucTransmitterId = encoder_id;
77437f9003bSAlex Deucher 			args.v3.ucEncoderMode = encoder_mode;
77537f9003bSAlex Deucher 			break;
77637f9003bSAlex Deucher 		case 5:
77737f9003bSAlex Deucher 			args.v5.ucCRTC = crtc_id;
77837f9003bSAlex Deucher 			args.v5.usPixelClock = cpu_to_le16(clock / 10);
77937f9003bSAlex Deucher 			args.v5.ucRefDiv = ref_div;
78037f9003bSAlex Deucher 			args.v5.usFbDiv = cpu_to_le16(fb_div);
78137f9003bSAlex Deucher 			args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
78237f9003bSAlex Deucher 			args.v5.ucPostDiv = post_div;
78337f9003bSAlex Deucher 			args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
78437f9003bSAlex Deucher 			args.v5.ucTransmitterID = encoder_id;
78537f9003bSAlex Deucher 			args.v5.ucEncoderMode = encoder_mode;
78637f9003bSAlex Deucher 			args.v5.ucPpll = pll_id;
78737f9003bSAlex Deucher 			break;
78837f9003bSAlex Deucher 		default:
78937f9003bSAlex Deucher 			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
79037f9003bSAlex Deucher 			return;
79137f9003bSAlex Deucher 		}
79237f9003bSAlex Deucher 		break;
79337f9003bSAlex Deucher 	default:
79437f9003bSAlex Deucher 		DRM_ERROR("Unknown table version %d %d\n", frev, crev);
79537f9003bSAlex Deucher 		return;
79637f9003bSAlex Deucher 	}
79737f9003bSAlex Deucher 
79837f9003bSAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
79937f9003bSAlex Deucher }
80037f9003bSAlex Deucher 
801bcc1c2a1SAlex Deucher static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
8024eaeca33SAlex Deucher {
8034eaeca33SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
8044eaeca33SAlex Deucher 	struct drm_device *dev = crtc->dev;
8054eaeca33SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
8064eaeca33SAlex Deucher 	struct drm_encoder *encoder = NULL;
8074eaeca33SAlex Deucher 	struct radeon_encoder *radeon_encoder = NULL;
8084eaeca33SAlex Deucher 	u32 pll_clock = mode->clock;
8094eaeca33SAlex Deucher 	u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
8104eaeca33SAlex Deucher 	struct radeon_pll *pll;
8114eaeca33SAlex Deucher 	u32 adjusted_clock;
812bcc1c2a1SAlex Deucher 	int encoder_mode = 0;
8134eaeca33SAlex Deucher 
8144eaeca33SAlex Deucher 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
8154eaeca33SAlex Deucher 		if (encoder->crtc == crtc) {
8164eaeca33SAlex Deucher 			radeon_encoder = to_radeon_encoder(encoder);
817bcc1c2a1SAlex Deucher 			encoder_mode = atombios_get_encoder_mode(encoder);
8184eaeca33SAlex Deucher 			break;
8194eaeca33SAlex Deucher 		}
8204eaeca33SAlex Deucher 	}
8214eaeca33SAlex Deucher 
8224eaeca33SAlex Deucher 	if (!radeon_encoder)
8234eaeca33SAlex Deucher 		return;
8244eaeca33SAlex Deucher 
825bcc1c2a1SAlex Deucher 	switch (radeon_crtc->pll_id) {
826bcc1c2a1SAlex Deucher 	case ATOM_PPLL1:
8274eaeca33SAlex Deucher 		pll = &rdev->clock.p1pll;
828bcc1c2a1SAlex Deucher 		break;
829bcc1c2a1SAlex Deucher 	case ATOM_PPLL2:
8304eaeca33SAlex Deucher 		pll = &rdev->clock.p2pll;
831bcc1c2a1SAlex Deucher 		break;
832bcc1c2a1SAlex Deucher 	case ATOM_DCPLL:
833bcc1c2a1SAlex Deucher 	case ATOM_PPLL_INVALID:
834921d98b5SStefan Richter 	default:
835bcc1c2a1SAlex Deucher 		pll = &rdev->clock.dcpll;
836bcc1c2a1SAlex Deucher 		break;
837bcc1c2a1SAlex Deucher 	}
8384eaeca33SAlex Deucher 
8394eaeca33SAlex Deucher 	/* adjust pixel clock as needed */
8404eaeca33SAlex Deucher 	adjusted_clock = atombios_adjust_pll(crtc, mode, pll);
8412606c886SAlex Deucher 
8422606c886SAlex Deucher 	radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
843fc10332bSAlex Deucher 			   &ref_div, &post_div);
844771fe6b9SJerome Glisse 
84537f9003bSAlex Deucher 	atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
84637f9003bSAlex Deucher 				  encoder_mode, radeon_encoder->encoder_id, mode->clock,
84737f9003bSAlex Deucher 				  ref_div, fb_div, frac_fb_div, post_div);
848771fe6b9SJerome Glisse 
849771fe6b9SJerome Glisse }
850771fe6b9SJerome Glisse 
851bcc1c2a1SAlex Deucher static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
852bcc1c2a1SAlex Deucher 				   struct drm_framebuffer *old_fb)
853bcc1c2a1SAlex Deucher {
854bcc1c2a1SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
855bcc1c2a1SAlex Deucher 	struct drm_device *dev = crtc->dev;
856bcc1c2a1SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
857bcc1c2a1SAlex Deucher 	struct radeon_framebuffer *radeon_fb;
858bcc1c2a1SAlex Deucher 	struct drm_gem_object *obj;
859bcc1c2a1SAlex Deucher 	struct radeon_bo *rbo;
860bcc1c2a1SAlex Deucher 	uint64_t fb_location;
861bcc1c2a1SAlex Deucher 	uint32_t fb_format, fb_pitch_pixels, tiling_flags;
862bcc1c2a1SAlex Deucher 	int r;
863bcc1c2a1SAlex Deucher 
864bcc1c2a1SAlex Deucher 	/* no fb bound */
865bcc1c2a1SAlex Deucher 	if (!crtc->fb) {
866d9fdaafbSDave Airlie 		DRM_DEBUG_KMS("No FB bound\n");
867bcc1c2a1SAlex Deucher 		return 0;
868bcc1c2a1SAlex Deucher 	}
869bcc1c2a1SAlex Deucher 
870bcc1c2a1SAlex Deucher 	radeon_fb = to_radeon_framebuffer(crtc->fb);
871bcc1c2a1SAlex Deucher 
872bcc1c2a1SAlex Deucher 	/* Pin framebuffer & get tilling informations */
873bcc1c2a1SAlex Deucher 	obj = radeon_fb->obj;
874bcc1c2a1SAlex Deucher 	rbo = obj->driver_private;
875bcc1c2a1SAlex Deucher 	r = radeon_bo_reserve(rbo, false);
876bcc1c2a1SAlex Deucher 	if (unlikely(r != 0))
877bcc1c2a1SAlex Deucher 		return r;
878bcc1c2a1SAlex Deucher 	r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
879bcc1c2a1SAlex Deucher 	if (unlikely(r != 0)) {
880bcc1c2a1SAlex Deucher 		radeon_bo_unreserve(rbo);
881bcc1c2a1SAlex Deucher 		return -EINVAL;
882bcc1c2a1SAlex Deucher 	}
883bcc1c2a1SAlex Deucher 	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
884bcc1c2a1SAlex Deucher 	radeon_bo_unreserve(rbo);
885bcc1c2a1SAlex Deucher 
886bcc1c2a1SAlex Deucher 	switch (crtc->fb->bits_per_pixel) {
887bcc1c2a1SAlex Deucher 	case 8:
888bcc1c2a1SAlex Deucher 		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) |
889bcc1c2a1SAlex Deucher 			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED));
890bcc1c2a1SAlex Deucher 		break;
891bcc1c2a1SAlex Deucher 	case 15:
892bcc1c2a1SAlex Deucher 		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
893bcc1c2a1SAlex Deucher 			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555));
894bcc1c2a1SAlex Deucher 		break;
895bcc1c2a1SAlex Deucher 	case 16:
896bcc1c2a1SAlex Deucher 		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
897bcc1c2a1SAlex Deucher 			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565));
898bcc1c2a1SAlex Deucher 		break;
899bcc1c2a1SAlex Deucher 	case 24:
900bcc1c2a1SAlex Deucher 	case 32:
901bcc1c2a1SAlex Deucher 		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |
902bcc1c2a1SAlex Deucher 			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888));
903bcc1c2a1SAlex Deucher 		break;
904bcc1c2a1SAlex Deucher 	default:
905bcc1c2a1SAlex Deucher 		DRM_ERROR("Unsupported screen depth %d\n",
906bcc1c2a1SAlex Deucher 			  crtc->fb->bits_per_pixel);
907bcc1c2a1SAlex Deucher 		return -EINVAL;
908bcc1c2a1SAlex Deucher 	}
909bcc1c2a1SAlex Deucher 
91097d66328SAlex Deucher 	if (tiling_flags & RADEON_TILING_MACRO)
91197d66328SAlex Deucher 		fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1);
91297d66328SAlex Deucher 	else if (tiling_flags & RADEON_TILING_MICRO)
91397d66328SAlex Deucher 		fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1);
91497d66328SAlex Deucher 
915bcc1c2a1SAlex Deucher 	switch (radeon_crtc->crtc_id) {
916bcc1c2a1SAlex Deucher 	case 0:
917bcc1c2a1SAlex Deucher 		WREG32(AVIVO_D1VGA_CONTROL, 0);
918bcc1c2a1SAlex Deucher 		break;
919bcc1c2a1SAlex Deucher 	case 1:
920bcc1c2a1SAlex Deucher 		WREG32(AVIVO_D2VGA_CONTROL, 0);
921bcc1c2a1SAlex Deucher 		break;
922bcc1c2a1SAlex Deucher 	case 2:
923bcc1c2a1SAlex Deucher 		WREG32(EVERGREEN_D3VGA_CONTROL, 0);
924bcc1c2a1SAlex Deucher 		break;
925bcc1c2a1SAlex Deucher 	case 3:
926bcc1c2a1SAlex Deucher 		WREG32(EVERGREEN_D4VGA_CONTROL, 0);
927bcc1c2a1SAlex Deucher 		break;
928bcc1c2a1SAlex Deucher 	case 4:
929bcc1c2a1SAlex Deucher 		WREG32(EVERGREEN_D5VGA_CONTROL, 0);
930bcc1c2a1SAlex Deucher 		break;
931bcc1c2a1SAlex Deucher 	case 5:
932bcc1c2a1SAlex Deucher 		WREG32(EVERGREEN_D6VGA_CONTROL, 0);
933bcc1c2a1SAlex Deucher 		break;
934bcc1c2a1SAlex Deucher 	default:
935bcc1c2a1SAlex Deucher 		break;
936bcc1c2a1SAlex Deucher 	}
937bcc1c2a1SAlex Deucher 
938bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
939bcc1c2a1SAlex Deucher 	       upper_32_bits(fb_location));
940bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
941bcc1c2a1SAlex Deucher 	       upper_32_bits(fb_location));
942bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
943bcc1c2a1SAlex Deucher 	       (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
944bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
945bcc1c2a1SAlex Deucher 	       (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
946bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
947bcc1c2a1SAlex Deucher 
948bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
949bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
950bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0);
951bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0);
952bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
953bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
954bcc1c2a1SAlex Deucher 
955bcc1c2a1SAlex Deucher 	fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
956bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
957bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
958bcc1c2a1SAlex Deucher 
959bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
960bcc1c2a1SAlex Deucher 	       crtc->mode.vdisplay);
961bcc1c2a1SAlex Deucher 	x &= ~3;
962bcc1c2a1SAlex Deucher 	y &= ~1;
963bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset,
964bcc1c2a1SAlex Deucher 	       (x << 16) | y);
965bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
966bcc1c2a1SAlex Deucher 	       (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
967bcc1c2a1SAlex Deucher 
968bcc1c2a1SAlex Deucher 	if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
969bcc1c2a1SAlex Deucher 		WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset,
970bcc1c2a1SAlex Deucher 		       EVERGREEN_INTERLEAVE_EN);
971bcc1c2a1SAlex Deucher 	else
972bcc1c2a1SAlex Deucher 		WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
973bcc1c2a1SAlex Deucher 
974bcc1c2a1SAlex Deucher 	if (old_fb && old_fb != crtc->fb) {
975bcc1c2a1SAlex Deucher 		radeon_fb = to_radeon_framebuffer(old_fb);
976bcc1c2a1SAlex Deucher 		rbo = radeon_fb->obj->driver_private;
977bcc1c2a1SAlex Deucher 		r = radeon_bo_reserve(rbo, false);
978bcc1c2a1SAlex Deucher 		if (unlikely(r != 0))
979bcc1c2a1SAlex Deucher 			return r;
980bcc1c2a1SAlex Deucher 		radeon_bo_unpin(rbo);
981bcc1c2a1SAlex Deucher 		radeon_bo_unreserve(rbo);
982bcc1c2a1SAlex Deucher 	}
983bcc1c2a1SAlex Deucher 
984bcc1c2a1SAlex Deucher 	/* Bytes per pixel may have changed */
985bcc1c2a1SAlex Deucher 	radeon_bandwidth_update(rdev);
986bcc1c2a1SAlex Deucher 
987bcc1c2a1SAlex Deucher 	return 0;
988bcc1c2a1SAlex Deucher }
989bcc1c2a1SAlex Deucher 
99054f088a9SAlex Deucher static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
991771fe6b9SJerome Glisse 			       struct drm_framebuffer *old_fb)
992771fe6b9SJerome Glisse {
993771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
994771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
995771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
996771fe6b9SJerome Glisse 	struct radeon_framebuffer *radeon_fb;
997771fe6b9SJerome Glisse 	struct drm_gem_object *obj;
9984c788679SJerome Glisse 	struct radeon_bo *rbo;
999771fe6b9SJerome Glisse 	uint64_t fb_location;
1000e024e110SDave Airlie 	uint32_t fb_format, fb_pitch_pixels, tiling_flags;
10014c788679SJerome Glisse 	int r;
1002771fe6b9SJerome Glisse 
10032de3b484SJerome Glisse 	/* no fb bound */
10042de3b484SJerome Glisse 	if (!crtc->fb) {
1005d9fdaafbSDave Airlie 		DRM_DEBUG_KMS("No FB bound\n");
10062de3b484SJerome Glisse 		return 0;
10072de3b484SJerome Glisse 	}
1008771fe6b9SJerome Glisse 
1009771fe6b9SJerome Glisse 	radeon_fb = to_radeon_framebuffer(crtc->fb);
1010771fe6b9SJerome Glisse 
10114c788679SJerome Glisse 	/* Pin framebuffer & get tilling informations */
1012771fe6b9SJerome Glisse 	obj = radeon_fb->obj;
10134c788679SJerome Glisse 	rbo = obj->driver_private;
10144c788679SJerome Glisse 	r = radeon_bo_reserve(rbo, false);
10154c788679SJerome Glisse 	if (unlikely(r != 0))
10164c788679SJerome Glisse 		return r;
10174c788679SJerome Glisse 	r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
10184c788679SJerome Glisse 	if (unlikely(r != 0)) {
10194c788679SJerome Glisse 		radeon_bo_unreserve(rbo);
1020771fe6b9SJerome Glisse 		return -EINVAL;
1021771fe6b9SJerome Glisse 	}
10224c788679SJerome Glisse 	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
10234c788679SJerome Glisse 	radeon_bo_unreserve(rbo);
1024771fe6b9SJerome Glisse 
1025771fe6b9SJerome Glisse 	switch (crtc->fb->bits_per_pixel) {
102641456df2SDave Airlie 	case 8:
102741456df2SDave Airlie 		fb_format =
102841456df2SDave Airlie 		    AVIVO_D1GRPH_CONTROL_DEPTH_8BPP |
102941456df2SDave Airlie 		    AVIVO_D1GRPH_CONTROL_8BPP_INDEXED;
103041456df2SDave Airlie 		break;
1031771fe6b9SJerome Glisse 	case 15:
1032771fe6b9SJerome Glisse 		fb_format =
1033771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
1034771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555;
1035771fe6b9SJerome Glisse 		break;
1036771fe6b9SJerome Glisse 	case 16:
1037771fe6b9SJerome Glisse 		fb_format =
1038771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
1039771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_16BPP_RGB565;
1040771fe6b9SJerome Glisse 		break;
1041771fe6b9SJerome Glisse 	case 24:
1042771fe6b9SJerome Glisse 	case 32:
1043771fe6b9SJerome Glisse 		fb_format =
1044771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
1045771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888;
1046771fe6b9SJerome Glisse 		break;
1047771fe6b9SJerome Glisse 	default:
1048771fe6b9SJerome Glisse 		DRM_ERROR("Unsupported screen depth %d\n",
1049771fe6b9SJerome Glisse 			  crtc->fb->bits_per_pixel);
1050771fe6b9SJerome Glisse 		return -EINVAL;
1051771fe6b9SJerome Glisse 	}
1052771fe6b9SJerome Glisse 
105340c4ac1cSAlex Deucher 	if (rdev->family >= CHIP_R600) {
105440c4ac1cSAlex Deucher 		if (tiling_flags & RADEON_TILING_MACRO)
105540c4ac1cSAlex Deucher 			fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1;
105640c4ac1cSAlex Deucher 		else if (tiling_flags & RADEON_TILING_MICRO)
105740c4ac1cSAlex Deucher 			fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1;
105840c4ac1cSAlex Deucher 	} else {
1059cf2f05d3SDave Airlie 		if (tiling_flags & RADEON_TILING_MACRO)
1060cf2f05d3SDave Airlie 			fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE;
1061cf2f05d3SDave Airlie 
1062e024e110SDave Airlie 		if (tiling_flags & RADEON_TILING_MICRO)
1063e024e110SDave Airlie 			fb_format |= AVIVO_D1GRPH_TILED;
106440c4ac1cSAlex Deucher 	}
1065e024e110SDave Airlie 
1066771fe6b9SJerome Glisse 	if (radeon_crtc->crtc_id == 0)
1067771fe6b9SJerome Glisse 		WREG32(AVIVO_D1VGA_CONTROL, 0);
1068771fe6b9SJerome Glisse 	else
1069771fe6b9SJerome Glisse 		WREG32(AVIVO_D2VGA_CONTROL, 0);
1070c290dadfSAlex Deucher 
1071c290dadfSAlex Deucher 	if (rdev->family >= CHIP_RV770) {
1072c290dadfSAlex Deucher 		if (radeon_crtc->crtc_id) {
1073c290dadfSAlex Deucher 			WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0);
1074c290dadfSAlex Deucher 			WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0);
1075c290dadfSAlex Deucher 		} else {
1076c290dadfSAlex Deucher 			WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0);
1077c290dadfSAlex Deucher 			WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0);
1078c290dadfSAlex Deucher 		}
1079c290dadfSAlex Deucher 	}
1080771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
1081771fe6b9SJerome Glisse 	       (u32) fb_location);
1082771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS +
1083771fe6b9SJerome Glisse 	       radeon_crtc->crtc_offset, (u32) fb_location);
1084771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
1085771fe6b9SJerome Glisse 
1086771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
1087771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
1088771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0);
1089771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0);
1090771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
1091771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
1092771fe6b9SJerome Glisse 
1093771fe6b9SJerome Glisse 	fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
1094771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
1095771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
1096771fe6b9SJerome Glisse 
1097771fe6b9SJerome Glisse 	WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
1098771fe6b9SJerome Glisse 	       crtc->mode.vdisplay);
1099771fe6b9SJerome Glisse 	x &= ~3;
1100771fe6b9SJerome Glisse 	y &= ~1;
1101771fe6b9SJerome Glisse 	WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset,
1102771fe6b9SJerome Glisse 	       (x << 16) | y);
1103771fe6b9SJerome Glisse 	WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
1104771fe6b9SJerome Glisse 	       (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
1105771fe6b9SJerome Glisse 
1106771fe6b9SJerome Glisse 	if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
1107771fe6b9SJerome Glisse 		WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
1108771fe6b9SJerome Glisse 		       AVIVO_D1MODE_INTERLEAVE_EN);
1109771fe6b9SJerome Glisse 	else
1110771fe6b9SJerome Glisse 		WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
1111771fe6b9SJerome Glisse 
1112771fe6b9SJerome Glisse 	if (old_fb && old_fb != crtc->fb) {
1113771fe6b9SJerome Glisse 		radeon_fb = to_radeon_framebuffer(old_fb);
11144c788679SJerome Glisse 		rbo = radeon_fb->obj->driver_private;
11154c788679SJerome Glisse 		r = radeon_bo_reserve(rbo, false);
11164c788679SJerome Glisse 		if (unlikely(r != 0))
11174c788679SJerome Glisse 			return r;
11184c788679SJerome Glisse 		radeon_bo_unpin(rbo);
11194c788679SJerome Glisse 		radeon_bo_unreserve(rbo);
1120771fe6b9SJerome Glisse 	}
1121f30f37deSMichel Dänzer 
1122f30f37deSMichel Dänzer 	/* Bytes per pixel may have changed */
1123f30f37deSMichel Dänzer 	radeon_bandwidth_update(rdev);
1124f30f37deSMichel Dänzer 
1125771fe6b9SJerome Glisse 	return 0;
1126771fe6b9SJerome Glisse }
1127771fe6b9SJerome Glisse 
112854f088a9SAlex Deucher int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
112954f088a9SAlex Deucher 			   struct drm_framebuffer *old_fb)
113054f088a9SAlex Deucher {
113154f088a9SAlex Deucher 	struct drm_device *dev = crtc->dev;
113254f088a9SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
113354f088a9SAlex Deucher 
1134bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev))
1135bcc1c2a1SAlex Deucher 		return evergreen_crtc_set_base(crtc, x, y, old_fb);
1136bcc1c2a1SAlex Deucher 	else if (ASIC_IS_AVIVO(rdev))
113754f088a9SAlex Deucher 		return avivo_crtc_set_base(crtc, x, y, old_fb);
113854f088a9SAlex Deucher 	else
113954f088a9SAlex Deucher 		return radeon_crtc_set_base(crtc, x, y, old_fb);
114054f088a9SAlex Deucher }
114154f088a9SAlex Deucher 
1142615e0cb6SAlex Deucher /* properly set additional regs when using atombios */
1143615e0cb6SAlex Deucher static void radeon_legacy_atom_fixup(struct drm_crtc *crtc)
1144615e0cb6SAlex Deucher {
1145615e0cb6SAlex Deucher 	struct drm_device *dev = crtc->dev;
1146615e0cb6SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
1147615e0cb6SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1148615e0cb6SAlex Deucher 	u32 disp_merge_cntl;
1149615e0cb6SAlex Deucher 
1150615e0cb6SAlex Deucher 	switch (radeon_crtc->crtc_id) {
1151615e0cb6SAlex Deucher 	case 0:
1152615e0cb6SAlex Deucher 		disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL);
1153615e0cb6SAlex Deucher 		disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
1154615e0cb6SAlex Deucher 		WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl);
1155615e0cb6SAlex Deucher 		break;
1156615e0cb6SAlex Deucher 	case 1:
1157615e0cb6SAlex Deucher 		disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL);
1158615e0cb6SAlex Deucher 		disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN;
1159615e0cb6SAlex Deucher 		WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl);
1160615e0cb6SAlex Deucher 		WREG32(RADEON_FP_H2_SYNC_STRT_WID,   RREG32(RADEON_CRTC2_H_SYNC_STRT_WID));
1161615e0cb6SAlex Deucher 		WREG32(RADEON_FP_V2_SYNC_STRT_WID,   RREG32(RADEON_CRTC2_V_SYNC_STRT_WID));
1162615e0cb6SAlex Deucher 		break;
1163615e0cb6SAlex Deucher 	}
1164615e0cb6SAlex Deucher }
1165615e0cb6SAlex Deucher 
1166bcc1c2a1SAlex Deucher static int radeon_atom_pick_pll(struct drm_crtc *crtc)
1167bcc1c2a1SAlex Deucher {
1168bcc1c2a1SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1169bcc1c2a1SAlex Deucher 	struct drm_device *dev = crtc->dev;
1170bcc1c2a1SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
1171bcc1c2a1SAlex Deucher 	struct drm_encoder *test_encoder;
1172bcc1c2a1SAlex Deucher 	struct drm_crtc *test_crtc;
1173bcc1c2a1SAlex Deucher 	uint32_t pll_in_use = 0;
1174bcc1c2a1SAlex Deucher 
1175bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev)) {
1176bcc1c2a1SAlex Deucher 		/* if crtc is driving DP and we have an ext clock, use that */
1177bcc1c2a1SAlex Deucher 		list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
1178bcc1c2a1SAlex Deucher 			if (test_encoder->crtc && (test_encoder->crtc == crtc)) {
1179bcc1c2a1SAlex Deucher 				if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) {
1180bcc1c2a1SAlex Deucher 					if (rdev->clock.dp_extclk)
1181bcc1c2a1SAlex Deucher 						return ATOM_PPLL_INVALID;
1182bcc1c2a1SAlex Deucher 				}
1183bcc1c2a1SAlex Deucher 			}
1184bcc1c2a1SAlex Deucher 		}
1185bcc1c2a1SAlex Deucher 
1186bcc1c2a1SAlex Deucher 		/* otherwise, pick one of the plls */
1187bcc1c2a1SAlex Deucher 		list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
1188bcc1c2a1SAlex Deucher 			struct radeon_crtc *radeon_test_crtc;
1189bcc1c2a1SAlex Deucher 
1190bcc1c2a1SAlex Deucher 			if (crtc == test_crtc)
1191bcc1c2a1SAlex Deucher 				continue;
1192bcc1c2a1SAlex Deucher 
1193bcc1c2a1SAlex Deucher 			radeon_test_crtc = to_radeon_crtc(test_crtc);
1194bcc1c2a1SAlex Deucher 			if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) &&
1195bcc1c2a1SAlex Deucher 			    (radeon_test_crtc->pll_id <= ATOM_PPLL2))
1196bcc1c2a1SAlex Deucher 				pll_in_use |= (1 << radeon_test_crtc->pll_id);
1197bcc1c2a1SAlex Deucher 		}
1198bcc1c2a1SAlex Deucher 		if (!(pll_in_use & 1))
1199bcc1c2a1SAlex Deucher 			return ATOM_PPLL1;
1200bcc1c2a1SAlex Deucher 		return ATOM_PPLL2;
1201bcc1c2a1SAlex Deucher 	} else
1202bcc1c2a1SAlex Deucher 		return radeon_crtc->crtc_id;
1203bcc1c2a1SAlex Deucher 
1204bcc1c2a1SAlex Deucher }
1205bcc1c2a1SAlex Deucher 
1206771fe6b9SJerome Glisse int atombios_crtc_mode_set(struct drm_crtc *crtc,
1207771fe6b9SJerome Glisse 			   struct drm_display_mode *mode,
1208771fe6b9SJerome Glisse 			   struct drm_display_mode *adjusted_mode,
1209771fe6b9SJerome Glisse 			   int x, int y, struct drm_framebuffer *old_fb)
1210771fe6b9SJerome Glisse {
1211771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1212771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
1213771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
1214771fe6b9SJerome Glisse 
1215771fe6b9SJerome Glisse 	/* TODO color tiling */
1216771fe6b9SJerome Glisse 
1217b792210eSAlex Deucher 	atombios_disable_ss(crtc);
1218bcc1c2a1SAlex Deucher 	/* always set DCPLL */
1219bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev))
1220bcc1c2a1SAlex Deucher 		atombios_crtc_set_dcpll(crtc);
1221771fe6b9SJerome Glisse 	atombios_crtc_set_pll(crtc, adjusted_mode);
1222b792210eSAlex Deucher 	atombios_enable_ss(crtc);
1223771fe6b9SJerome Glisse 
12245b1714d3SAlex Deucher 	if (ASIC_IS_AVIVO(rdev))
1225bcc1c2a1SAlex Deucher 		atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
1226771fe6b9SJerome Glisse 	else {
1227bcc1c2a1SAlex Deucher 		atombios_crtc_set_timing(crtc, adjusted_mode);
12285a9bcaccSAlex Deucher 		if (radeon_crtc->crtc_id == 0)
12295a9bcaccSAlex Deucher 			atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
1230615e0cb6SAlex Deucher 		radeon_legacy_atom_fixup(crtc);
1231771fe6b9SJerome Glisse 	}
1232bcc1c2a1SAlex Deucher 	atombios_crtc_set_base(crtc, x, y, old_fb);
1233c93bb85bSJerome Glisse 	atombios_overscan_setup(crtc, mode, adjusted_mode);
1234c93bb85bSJerome Glisse 	atombios_scaler_setup(crtc);
1235771fe6b9SJerome Glisse 	return 0;
1236771fe6b9SJerome Glisse }
1237771fe6b9SJerome Glisse 
1238771fe6b9SJerome Glisse static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
1239771fe6b9SJerome Glisse 				     struct drm_display_mode *mode,
1240771fe6b9SJerome Glisse 				     struct drm_display_mode *adjusted_mode)
1241771fe6b9SJerome Glisse {
124203214bd5SAlex Deucher 	struct drm_device *dev = crtc->dev;
124303214bd5SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
124403214bd5SAlex Deucher 
124503214bd5SAlex Deucher 	/* adjust pm to upcoming mode change */
124603214bd5SAlex Deucher 	radeon_pm_compute_clocks(rdev);
124703214bd5SAlex Deucher 
1248c93bb85bSJerome Glisse 	if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
1249c93bb85bSJerome Glisse 		return false;
1250771fe6b9SJerome Glisse 	return true;
1251771fe6b9SJerome Glisse }
1252771fe6b9SJerome Glisse 
1253771fe6b9SJerome Glisse static void atombios_crtc_prepare(struct drm_crtc *crtc)
1254771fe6b9SJerome Glisse {
1255267364acSAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1256267364acSAlex Deucher 
1257267364acSAlex Deucher 	/* pick pll */
1258267364acSAlex Deucher 	radeon_crtc->pll_id = radeon_atom_pick_pll(crtc);
1259267364acSAlex Deucher 
126037b4390eSAlex Deucher 	atombios_lock_crtc(crtc, ATOM_ENABLE);
1261a348c84dSAlex Deucher 	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
1262771fe6b9SJerome Glisse }
1263771fe6b9SJerome Glisse 
1264771fe6b9SJerome Glisse static void atombios_crtc_commit(struct drm_crtc *crtc)
1265771fe6b9SJerome Glisse {
1266771fe6b9SJerome Glisse 	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
126737b4390eSAlex Deucher 	atombios_lock_crtc(crtc, ATOM_DISABLE);
1268771fe6b9SJerome Glisse }
1269771fe6b9SJerome Glisse 
127037f9003bSAlex Deucher static void atombios_crtc_disable(struct drm_crtc *crtc)
127137f9003bSAlex Deucher {
127237f9003bSAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
127337f9003bSAlex Deucher 	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
127437f9003bSAlex Deucher 
127537f9003bSAlex Deucher 	switch (radeon_crtc->pll_id) {
127637f9003bSAlex Deucher 	case ATOM_PPLL1:
127737f9003bSAlex Deucher 	case ATOM_PPLL2:
127837f9003bSAlex Deucher 		/* disable the ppll */
127937f9003bSAlex Deucher 		atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
128037f9003bSAlex Deucher 					  0, 0, ATOM_DISABLE, 0, 0, 0, 0);
128137f9003bSAlex Deucher 		break;
128237f9003bSAlex Deucher 	default:
128337f9003bSAlex Deucher 		break;
128437f9003bSAlex Deucher 	}
128537f9003bSAlex Deucher 	radeon_crtc->pll_id = -1;
128637f9003bSAlex Deucher }
128737f9003bSAlex Deucher 
1288771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
1289771fe6b9SJerome Glisse 	.dpms = atombios_crtc_dpms,
1290771fe6b9SJerome Glisse 	.mode_fixup = atombios_crtc_mode_fixup,
1291771fe6b9SJerome Glisse 	.mode_set = atombios_crtc_mode_set,
1292771fe6b9SJerome Glisse 	.mode_set_base = atombios_crtc_set_base,
1293771fe6b9SJerome Glisse 	.prepare = atombios_crtc_prepare,
1294771fe6b9SJerome Glisse 	.commit = atombios_crtc_commit,
1295068143d3SDave Airlie 	.load_lut = radeon_crtc_load_lut,
129637f9003bSAlex Deucher 	.disable = atombios_crtc_disable,
1297771fe6b9SJerome Glisse };
1298771fe6b9SJerome Glisse 
1299771fe6b9SJerome Glisse void radeon_atombios_init_crtc(struct drm_device *dev,
1300771fe6b9SJerome Glisse 			       struct radeon_crtc *radeon_crtc)
1301771fe6b9SJerome Glisse {
1302bcc1c2a1SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
1303bcc1c2a1SAlex Deucher 
1304bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev)) {
1305bcc1c2a1SAlex Deucher 		switch (radeon_crtc->crtc_id) {
1306bcc1c2a1SAlex Deucher 		case 0:
1307bcc1c2a1SAlex Deucher 		default:
130812d7798fSAlex Deucher 			radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET;
1309bcc1c2a1SAlex Deucher 			break;
1310bcc1c2a1SAlex Deucher 		case 1:
131112d7798fSAlex Deucher 			radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET;
1312bcc1c2a1SAlex Deucher 			break;
1313bcc1c2a1SAlex Deucher 		case 2:
131412d7798fSAlex Deucher 			radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET;
1315bcc1c2a1SAlex Deucher 			break;
1316bcc1c2a1SAlex Deucher 		case 3:
131712d7798fSAlex Deucher 			radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET;
1318bcc1c2a1SAlex Deucher 			break;
1319bcc1c2a1SAlex Deucher 		case 4:
132012d7798fSAlex Deucher 			radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET;
1321bcc1c2a1SAlex Deucher 			break;
1322bcc1c2a1SAlex Deucher 		case 5:
132312d7798fSAlex Deucher 			radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET;
1324bcc1c2a1SAlex Deucher 			break;
1325bcc1c2a1SAlex Deucher 		}
1326bcc1c2a1SAlex Deucher 	} else {
1327771fe6b9SJerome Glisse 		if (radeon_crtc->crtc_id == 1)
1328771fe6b9SJerome Glisse 			radeon_crtc->crtc_offset =
1329771fe6b9SJerome Glisse 				AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL;
1330bcc1c2a1SAlex Deucher 		else
1331bcc1c2a1SAlex Deucher 			radeon_crtc->crtc_offset = 0;
1332bcc1c2a1SAlex Deucher 	}
1333bcc1c2a1SAlex Deucher 	radeon_crtc->pll_id = -1;
1334771fe6b9SJerome Glisse 	drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
1335771fe6b9SJerome Glisse }
1336