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>
29771fe6b9SJerome Glisse #include "radeon_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.usOverscanRight = 0;
48c93bb85bSJerome Glisse 	args.usOverscanLeft = 0;
49c93bb85bSJerome Glisse 	args.usOverscanBottom = 0;
50c93bb85bSJerome Glisse 	args.usOverscanTop = 0;
51c93bb85bSJerome Glisse 	args.ucCRTC = radeon_crtc->crtc_id;
52c93bb85bSJerome Glisse 
53c93bb85bSJerome Glisse 	switch (radeon_crtc->rmx_type) {
54c93bb85bSJerome Glisse 	case RMX_CENTER:
55c93bb85bSJerome Glisse 		args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
56c93bb85bSJerome Glisse 		args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
57c93bb85bSJerome Glisse 		args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
58c93bb85bSJerome Glisse 		args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
59c93bb85bSJerome Glisse 		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
60c93bb85bSJerome Glisse 		break;
61c93bb85bSJerome Glisse 	case RMX_ASPECT:
62c93bb85bSJerome Glisse 		a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
63c93bb85bSJerome Glisse 		a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
64c93bb85bSJerome Glisse 
65c93bb85bSJerome Glisse 		if (a1 > a2) {
66c93bb85bSJerome Glisse 			args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2;
67c93bb85bSJerome Glisse 			args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2;
68c93bb85bSJerome Glisse 		} else if (a2 > a1) {
69c93bb85bSJerome Glisse 			args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
70c93bb85bSJerome Glisse 			args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
71c93bb85bSJerome Glisse 		}
72c93bb85bSJerome Glisse 		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
73c93bb85bSJerome Glisse 		break;
74c93bb85bSJerome Glisse 	case RMX_FULL:
75c93bb85bSJerome Glisse 	default:
76c93bb85bSJerome Glisse 		args.usOverscanRight = 0;
77c93bb85bSJerome Glisse 		args.usOverscanLeft = 0;
78c93bb85bSJerome Glisse 		args.usOverscanBottom = 0;
79c93bb85bSJerome Glisse 		args.usOverscanTop = 0;
80c93bb85bSJerome Glisse 		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
81c93bb85bSJerome Glisse 		break;
82c93bb85bSJerome Glisse 	}
83c93bb85bSJerome Glisse }
84c93bb85bSJerome Glisse 
85c93bb85bSJerome Glisse static void atombios_scaler_setup(struct drm_crtc *crtc)
86c93bb85bSJerome Glisse {
87c93bb85bSJerome Glisse 	struct drm_device *dev = crtc->dev;
88c93bb85bSJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
89c93bb85bSJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
90c93bb85bSJerome Glisse 	ENABLE_SCALER_PS_ALLOCATION args;
91c93bb85bSJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
924ce001abSDave Airlie 
93c93bb85bSJerome Glisse 	/* fixme - fill in enc_priv for atom dac */
94c93bb85bSJerome Glisse 	enum radeon_tv_std tv_std = TV_STD_NTSC;
954ce001abSDave Airlie 	bool is_tv = false, is_cv = false;
964ce001abSDave Airlie 	struct drm_encoder *encoder;
97c93bb85bSJerome Glisse 
98c93bb85bSJerome Glisse 	if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id)
99c93bb85bSJerome Glisse 		return;
100c93bb85bSJerome Glisse 
1014ce001abSDave Airlie 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
1024ce001abSDave Airlie 		/* find tv std */
1034ce001abSDave Airlie 		if (encoder->crtc == crtc) {
1044ce001abSDave Airlie 			struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
1054ce001abSDave Airlie 			if (radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT) {
1064ce001abSDave Airlie 				struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv;
1074ce001abSDave Airlie 				tv_std = tv_dac->tv_std;
1084ce001abSDave Airlie 				is_tv = true;
1094ce001abSDave Airlie 			}
1104ce001abSDave Airlie 		}
1114ce001abSDave Airlie 	}
1124ce001abSDave Airlie 
113c93bb85bSJerome Glisse 	memset(&args, 0, sizeof(args));
114c93bb85bSJerome Glisse 
115c93bb85bSJerome Glisse 	args.ucScaler = radeon_crtc->crtc_id;
116c93bb85bSJerome Glisse 
1174ce001abSDave Airlie 	if (is_tv) {
118c93bb85bSJerome Glisse 		switch (tv_std) {
119c93bb85bSJerome Glisse 		case TV_STD_NTSC:
120c93bb85bSJerome Glisse 		default:
121c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_NTSC;
122c93bb85bSJerome Glisse 			break;
123c93bb85bSJerome Glisse 		case TV_STD_PAL:
124c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_PAL;
125c93bb85bSJerome Glisse 			break;
126c93bb85bSJerome Glisse 		case TV_STD_PAL_M:
127c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_PALM;
128c93bb85bSJerome Glisse 			break;
129c93bb85bSJerome Glisse 		case TV_STD_PAL_60:
130c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_PAL60;
131c93bb85bSJerome Glisse 			break;
132c93bb85bSJerome Glisse 		case TV_STD_NTSC_J:
133c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_NTSCJ;
134c93bb85bSJerome Glisse 			break;
135c93bb85bSJerome Glisse 		case TV_STD_SCART_PAL:
136c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_PAL; /* ??? */
137c93bb85bSJerome Glisse 			break;
138c93bb85bSJerome Glisse 		case TV_STD_SECAM:
139c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_SECAM;
140c93bb85bSJerome Glisse 			break;
141c93bb85bSJerome Glisse 		case TV_STD_PAL_CN:
142c93bb85bSJerome Glisse 			args.ucTVStandard = ATOM_TV_PALCN;
143c93bb85bSJerome Glisse 			break;
144c93bb85bSJerome Glisse 		}
145c93bb85bSJerome Glisse 		args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
1464ce001abSDave Airlie 	} else if (is_cv) {
147c93bb85bSJerome Glisse 		args.ucTVStandard = ATOM_TV_CV;
148c93bb85bSJerome Glisse 		args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
149c93bb85bSJerome Glisse 	} else {
150c93bb85bSJerome Glisse 		switch (radeon_crtc->rmx_type) {
151c93bb85bSJerome Glisse 		case RMX_FULL:
152c93bb85bSJerome Glisse 			args.ucEnable = ATOM_SCALER_EXPANSION;
153c93bb85bSJerome Glisse 			break;
154c93bb85bSJerome Glisse 		case RMX_CENTER:
155c93bb85bSJerome Glisse 			args.ucEnable = ATOM_SCALER_CENTER;
156c93bb85bSJerome Glisse 			break;
157c93bb85bSJerome Glisse 		case RMX_ASPECT:
158c93bb85bSJerome Glisse 			args.ucEnable = ATOM_SCALER_EXPANSION;
159c93bb85bSJerome Glisse 			break;
160c93bb85bSJerome Glisse 		default:
161c93bb85bSJerome Glisse 			if (ASIC_IS_AVIVO(rdev))
162c93bb85bSJerome Glisse 				args.ucEnable = ATOM_SCALER_DISABLE;
163c93bb85bSJerome Glisse 			else
164c93bb85bSJerome Glisse 				args.ucEnable = ATOM_SCALER_CENTER;
165c93bb85bSJerome Glisse 			break;
166c93bb85bSJerome Glisse 		}
167c93bb85bSJerome Glisse 	}
168c93bb85bSJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
1694ce001abSDave Airlie 	if ((is_tv || is_cv)
1704ce001abSDave Airlie 	    && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_R580) {
1714ce001abSDave Airlie 		atom_rv515_force_tv_scaler(rdev, radeon_crtc);
172c93bb85bSJerome Glisse 	}
173c93bb85bSJerome Glisse }
174c93bb85bSJerome Glisse 
175771fe6b9SJerome Glisse static void atombios_lock_crtc(struct drm_crtc *crtc, int lock)
176771fe6b9SJerome Glisse {
177771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
178771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
179771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
180771fe6b9SJerome Glisse 	int index =
181771fe6b9SJerome Glisse 	    GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
182771fe6b9SJerome Glisse 	ENABLE_CRTC_PS_ALLOCATION args;
183771fe6b9SJerome Glisse 
184771fe6b9SJerome Glisse 	memset(&args, 0, sizeof(args));
185771fe6b9SJerome Glisse 
186771fe6b9SJerome Glisse 	args.ucCRTC = radeon_crtc->crtc_id;
187771fe6b9SJerome Glisse 	args.ucEnable = lock;
188771fe6b9SJerome Glisse 
189771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
190771fe6b9SJerome Glisse }
191771fe6b9SJerome Glisse 
192771fe6b9SJerome Glisse static void atombios_enable_crtc(struct drm_crtc *crtc, int state)
193771fe6b9SJerome Glisse {
194771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
195771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
196771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
197771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
198771fe6b9SJerome Glisse 	ENABLE_CRTC_PS_ALLOCATION args;
199771fe6b9SJerome Glisse 
200771fe6b9SJerome Glisse 	memset(&args, 0, sizeof(args));
201771fe6b9SJerome Glisse 
202771fe6b9SJerome Glisse 	args.ucCRTC = radeon_crtc->crtc_id;
203771fe6b9SJerome Glisse 	args.ucEnable = state;
204771fe6b9SJerome Glisse 
205771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
206771fe6b9SJerome Glisse }
207771fe6b9SJerome Glisse 
208771fe6b9SJerome Glisse static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state)
209771fe6b9SJerome Glisse {
210771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
211771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
212771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
213771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq);
214771fe6b9SJerome Glisse 	ENABLE_CRTC_PS_ALLOCATION args;
215771fe6b9SJerome Glisse 
216771fe6b9SJerome Glisse 	memset(&args, 0, sizeof(args));
217771fe6b9SJerome Glisse 
218771fe6b9SJerome Glisse 	args.ucCRTC = radeon_crtc->crtc_id;
219771fe6b9SJerome Glisse 	args.ucEnable = state;
220771fe6b9SJerome Glisse 
221771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
222771fe6b9SJerome Glisse }
223771fe6b9SJerome Glisse 
224771fe6b9SJerome Glisse static void atombios_blank_crtc(struct drm_crtc *crtc, int state)
225771fe6b9SJerome Glisse {
226771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
227771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
228771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
229771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
230771fe6b9SJerome Glisse 	BLANK_CRTC_PS_ALLOCATION args;
231771fe6b9SJerome Glisse 
232771fe6b9SJerome Glisse 	memset(&args, 0, sizeof(args));
233771fe6b9SJerome Glisse 
234771fe6b9SJerome Glisse 	args.ucCRTC = radeon_crtc->crtc_id;
235771fe6b9SJerome Glisse 	args.ucBlanking = state;
236771fe6b9SJerome Glisse 
237771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
238771fe6b9SJerome Glisse }
239771fe6b9SJerome Glisse 
240771fe6b9SJerome Glisse void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
241771fe6b9SJerome Glisse {
242771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
243771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
244500b7587SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
245771fe6b9SJerome Glisse 
246771fe6b9SJerome Glisse 	switch (mode) {
247771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_ON:
24837b4390eSAlex Deucher 		atombios_enable_crtc(crtc, ATOM_ENABLE);
249771fe6b9SJerome Glisse 		if (ASIC_IS_DCE3(rdev))
25037b4390eSAlex Deucher 			atombios_enable_crtc_memreq(crtc, ATOM_ENABLE);
25137b4390eSAlex Deucher 		atombios_blank_crtc(crtc, ATOM_DISABLE);
252500b7587SAlex Deucher 		drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
253500b7587SAlex Deucher 		radeon_crtc_load_lut(crtc);
254a48b9b4eSAlex Deucher 		radeon_crtc->enabled = true;
255771fe6b9SJerome Glisse 		break;
256771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_STANDBY:
257771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_SUSPEND:
258771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_OFF:
259500b7587SAlex Deucher 		drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
26037b4390eSAlex Deucher 		atombios_blank_crtc(crtc, ATOM_ENABLE);
261771fe6b9SJerome Glisse 		if (ASIC_IS_DCE3(rdev))
26237b4390eSAlex Deucher 			atombios_enable_crtc_memreq(crtc, ATOM_DISABLE);
26337b4390eSAlex Deucher 		atombios_enable_crtc(crtc, ATOM_DISABLE);
264a48b9b4eSAlex Deucher 		radeon_crtc->enabled = false;
265771fe6b9SJerome Glisse 		break;
266771fe6b9SJerome Glisse 	}
26703214bd5SAlex Deucher 
26803214bd5SAlex Deucher 	/* adjust pm to dpms change */
26903214bd5SAlex Deucher 	radeon_pm_compute_clocks(rdev);
270771fe6b9SJerome Glisse }
271771fe6b9SJerome Glisse 
272771fe6b9SJerome Glisse static void
273771fe6b9SJerome Glisse atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
2745a9bcaccSAlex Deucher 			     struct drm_display_mode *mode)
275771fe6b9SJerome Glisse {
2765a9bcaccSAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
277771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
278771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
2795a9bcaccSAlex Deucher 	SET_CRTC_USING_DTD_TIMING_PARAMETERS args;
280771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
2815a9bcaccSAlex Deucher 	u16 misc = 0;
282771fe6b9SJerome Glisse 
2835a9bcaccSAlex Deucher 	memset(&args, 0, sizeof(args));
2845a9bcaccSAlex Deucher 	args.usH_Size = cpu_to_le16(mode->crtc_hdisplay);
2855a9bcaccSAlex Deucher 	args.usH_Blanking_Time =
2865a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay);
2875a9bcaccSAlex Deucher 	args.usV_Size = cpu_to_le16(mode->crtc_vdisplay);
2885a9bcaccSAlex Deucher 	args.usV_Blanking_Time =
2895a9bcaccSAlex Deucher 	    cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay);
2905a9bcaccSAlex Deucher 	args.usH_SyncOffset =
2915a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay);
2925a9bcaccSAlex Deucher 	args.usH_SyncWidth =
2935a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
2945a9bcaccSAlex Deucher 	args.usV_SyncOffset =
2955a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay);
2965a9bcaccSAlex Deucher 	args.usV_SyncWidth =
2975a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
2985a9bcaccSAlex Deucher 	/*args.ucH_Border = mode->hborder;*/
2995a9bcaccSAlex Deucher 	/*args.ucV_Border = mode->vborder;*/
3005a9bcaccSAlex Deucher 
3015a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
3025a9bcaccSAlex Deucher 		misc |= ATOM_VSYNC_POLARITY;
3035a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
3045a9bcaccSAlex Deucher 		misc |= ATOM_HSYNC_POLARITY;
3055a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_CSYNC)
3065a9bcaccSAlex Deucher 		misc |= ATOM_COMPOSITESYNC;
3075a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
3085a9bcaccSAlex Deucher 		misc |= ATOM_INTERLACE;
3095a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
3105a9bcaccSAlex Deucher 		misc |= ATOM_DOUBLE_CLOCK_MODE;
3115a9bcaccSAlex Deucher 
3125a9bcaccSAlex Deucher 	args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
3135a9bcaccSAlex Deucher 	args.ucCRTC = radeon_crtc->crtc_id;
314771fe6b9SJerome Glisse 
3155a9bcaccSAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
316771fe6b9SJerome Glisse }
317771fe6b9SJerome Glisse 
3185a9bcaccSAlex Deucher static void atombios_crtc_set_timing(struct drm_crtc *crtc,
3195a9bcaccSAlex Deucher 				     struct drm_display_mode *mode)
320771fe6b9SJerome Glisse {
3215a9bcaccSAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
322771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
323771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
3245a9bcaccSAlex Deucher 	SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args;
325771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing);
3265a9bcaccSAlex Deucher 	u16 misc = 0;
327771fe6b9SJerome Glisse 
3285a9bcaccSAlex Deucher 	memset(&args, 0, sizeof(args));
3295a9bcaccSAlex Deucher 	args.usH_Total = cpu_to_le16(mode->crtc_htotal);
3305a9bcaccSAlex Deucher 	args.usH_Disp = cpu_to_le16(mode->crtc_hdisplay);
3315a9bcaccSAlex Deucher 	args.usH_SyncStart = cpu_to_le16(mode->crtc_hsync_start);
3325a9bcaccSAlex Deucher 	args.usH_SyncWidth =
3335a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
3345a9bcaccSAlex Deucher 	args.usV_Total = cpu_to_le16(mode->crtc_vtotal);
3355a9bcaccSAlex Deucher 	args.usV_Disp = cpu_to_le16(mode->crtc_vdisplay);
3365a9bcaccSAlex Deucher 	args.usV_SyncStart = cpu_to_le16(mode->crtc_vsync_start);
3375a9bcaccSAlex Deucher 	args.usV_SyncWidth =
3385a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
3395a9bcaccSAlex Deucher 
3405a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
3415a9bcaccSAlex Deucher 		misc |= ATOM_VSYNC_POLARITY;
3425a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
3435a9bcaccSAlex Deucher 		misc |= ATOM_HSYNC_POLARITY;
3445a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_CSYNC)
3455a9bcaccSAlex Deucher 		misc |= ATOM_COMPOSITESYNC;
3465a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
3475a9bcaccSAlex Deucher 		misc |= ATOM_INTERLACE;
3485a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
3495a9bcaccSAlex Deucher 		misc |= ATOM_DOUBLE_CLOCK_MODE;
3505a9bcaccSAlex Deucher 
3515a9bcaccSAlex Deucher 	args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
3525a9bcaccSAlex Deucher 	args.ucCRTC = radeon_crtc->crtc_id;
353771fe6b9SJerome Glisse 
3545a9bcaccSAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
355771fe6b9SJerome Glisse }
356771fe6b9SJerome Glisse 
357b792210eSAlex Deucher static void atombios_disable_ss(struct drm_crtc *crtc)
358b792210eSAlex Deucher {
359b792210eSAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
360b792210eSAlex Deucher 	struct drm_device *dev = crtc->dev;
361b792210eSAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
362b792210eSAlex Deucher 	u32 ss_cntl;
363b792210eSAlex Deucher 
364b792210eSAlex Deucher 	if (ASIC_IS_DCE4(rdev)) {
365b792210eSAlex Deucher 		switch (radeon_crtc->pll_id) {
366b792210eSAlex Deucher 		case ATOM_PPLL1:
367b792210eSAlex Deucher 			ss_cntl = RREG32(EVERGREEN_P1PLL_SS_CNTL);
368b792210eSAlex Deucher 			ss_cntl &= ~EVERGREEN_PxPLL_SS_EN;
369b792210eSAlex Deucher 			WREG32(EVERGREEN_P1PLL_SS_CNTL, ss_cntl);
370b792210eSAlex Deucher 			break;
371b792210eSAlex Deucher 		case ATOM_PPLL2:
372b792210eSAlex Deucher 			ss_cntl = RREG32(EVERGREEN_P2PLL_SS_CNTL);
373b792210eSAlex Deucher 			ss_cntl &= ~EVERGREEN_PxPLL_SS_EN;
374b792210eSAlex Deucher 			WREG32(EVERGREEN_P2PLL_SS_CNTL, ss_cntl);
375b792210eSAlex Deucher 			break;
376b792210eSAlex Deucher 		case ATOM_DCPLL:
377b792210eSAlex Deucher 		case ATOM_PPLL_INVALID:
378b792210eSAlex Deucher 			return;
379b792210eSAlex Deucher 		}
380b792210eSAlex Deucher 	} else if (ASIC_IS_AVIVO(rdev)) {
381b792210eSAlex Deucher 		switch (radeon_crtc->pll_id) {
382b792210eSAlex Deucher 		case ATOM_PPLL1:
383b792210eSAlex Deucher 			ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL);
384b792210eSAlex Deucher 			ss_cntl &= ~1;
385b792210eSAlex Deucher 			WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl);
386b792210eSAlex Deucher 			break;
387b792210eSAlex Deucher 		case ATOM_PPLL2:
388b792210eSAlex Deucher 			ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL);
389b792210eSAlex Deucher 			ss_cntl &= ~1;
390b792210eSAlex Deucher 			WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl);
391b792210eSAlex Deucher 			break;
392b792210eSAlex Deucher 		case ATOM_DCPLL:
393b792210eSAlex Deucher 		case ATOM_PPLL_INVALID:
394b792210eSAlex Deucher 			return;
395b792210eSAlex Deucher 		}
396b792210eSAlex Deucher 	}
397b792210eSAlex Deucher }
398b792210eSAlex Deucher 
399b792210eSAlex Deucher 
40026b9fc3aSAlex Deucher union atom_enable_ss {
40126b9fc3aSAlex Deucher 	ENABLE_LVDS_SS_PARAMETERS legacy;
40226b9fc3aSAlex Deucher 	ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1;
40326b9fc3aSAlex Deucher };
40426b9fc3aSAlex Deucher 
405b792210eSAlex Deucher static void atombios_enable_ss(struct drm_crtc *crtc)
406ebbe1cb9SAlex Deucher {
407ebbe1cb9SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
408ebbe1cb9SAlex Deucher 	struct drm_device *dev = crtc->dev;
409ebbe1cb9SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
410ebbe1cb9SAlex Deucher 	struct drm_encoder *encoder = NULL;
411ebbe1cb9SAlex Deucher 	struct radeon_encoder *radeon_encoder = NULL;
412ebbe1cb9SAlex Deucher 	struct radeon_encoder_atom_dig *dig = NULL;
413ebbe1cb9SAlex Deucher 	int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
41426b9fc3aSAlex Deucher 	union atom_enable_ss args;
415ebbe1cb9SAlex Deucher 	uint16_t percentage = 0;
416ebbe1cb9SAlex Deucher 	uint8_t type = 0, step = 0, delay = 0, range = 0;
417ebbe1cb9SAlex Deucher 
418bcc1c2a1SAlex Deucher 	/* XXX add ss support for DCE4 */
419bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev))
420bcc1c2a1SAlex Deucher 		return;
421bcc1c2a1SAlex Deucher 
422ebbe1cb9SAlex Deucher 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
423ebbe1cb9SAlex Deucher 		if (encoder->crtc == crtc) {
424ebbe1cb9SAlex Deucher 			radeon_encoder = to_radeon_encoder(encoder);
425ebbe1cb9SAlex Deucher 			/* only enable spread spectrum on LVDS */
426d11aa88bSAlex Deucher 			if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
427d11aa88bSAlex Deucher 				dig = radeon_encoder->enc_priv;
428ebbe1cb9SAlex Deucher 				if (dig && dig->ss) {
429ebbe1cb9SAlex Deucher 					percentage = dig->ss->percentage;
430ebbe1cb9SAlex Deucher 					type = dig->ss->type;
431ebbe1cb9SAlex Deucher 					step = dig->ss->step;
432ebbe1cb9SAlex Deucher 					delay = dig->ss->delay;
433ebbe1cb9SAlex Deucher 					range = dig->ss->range;
434b792210eSAlex Deucher 				} else
435ebbe1cb9SAlex Deucher 					return;
436b792210eSAlex Deucher 			} else
437d11aa88bSAlex Deucher 				return;
438ebbe1cb9SAlex Deucher 			break;
439ebbe1cb9SAlex Deucher 		}
440ebbe1cb9SAlex Deucher 	}
441ebbe1cb9SAlex Deucher 
442ebbe1cb9SAlex Deucher 	if (!radeon_encoder)
443ebbe1cb9SAlex Deucher 		return;
444ebbe1cb9SAlex Deucher 
445ebbe1cb9SAlex Deucher 	memset(&args, 0, sizeof(args));
44626b9fc3aSAlex Deucher 	if (ASIC_IS_AVIVO(rdev)) {
44726b9fc3aSAlex Deucher 		args.v1.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
44826b9fc3aSAlex Deucher 		args.v1.ucSpreadSpectrumType = type;
44926b9fc3aSAlex Deucher 		args.v1.ucSpreadSpectrumStep = step;
45026b9fc3aSAlex Deucher 		args.v1.ucSpreadSpectrumDelay = delay;
45126b9fc3aSAlex Deucher 		args.v1.ucSpreadSpectrumRange = range;
45226b9fc3aSAlex Deucher 		args.v1.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
453b792210eSAlex Deucher 		args.v1.ucEnable = ATOM_ENABLE;
454ebbe1cb9SAlex Deucher 	} else {
45526b9fc3aSAlex Deucher 		args.legacy.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
45626b9fc3aSAlex Deucher 		args.legacy.ucSpreadSpectrumType = type;
45726b9fc3aSAlex Deucher 		args.legacy.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2;
45826b9fc3aSAlex Deucher 		args.legacy.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4;
459b792210eSAlex Deucher 		args.legacy.ucEnable = ATOM_ENABLE;
460ebbe1cb9SAlex Deucher 	}
46126b9fc3aSAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
462ebbe1cb9SAlex Deucher }
463ebbe1cb9SAlex Deucher 
4644eaeca33SAlex Deucher union adjust_pixel_clock {
4654eaeca33SAlex Deucher 	ADJUST_DISPLAY_PLL_PS_ALLOCATION v1;
466bcc1c2a1SAlex Deucher 	ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3;
4674eaeca33SAlex Deucher };
4684eaeca33SAlex Deucher 
4694eaeca33SAlex Deucher static u32 atombios_adjust_pll(struct drm_crtc *crtc,
4704eaeca33SAlex Deucher 			       struct drm_display_mode *mode,
4714eaeca33SAlex Deucher 			       struct radeon_pll *pll)
472771fe6b9SJerome Glisse {
473771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
474771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
475771fe6b9SJerome Glisse 	struct drm_encoder *encoder = NULL;
476771fe6b9SJerome Glisse 	struct radeon_encoder *radeon_encoder = NULL;
4774eaeca33SAlex Deucher 	u32 adjusted_clock = mode->clock;
478bcc1c2a1SAlex Deucher 	int encoder_mode = 0;
479fc10332bSAlex Deucher 
4804eaeca33SAlex Deucher 	/* reset the pll flags */
4814eaeca33SAlex Deucher 	pll->flags = 0;
482771fe6b9SJerome Glisse 
4837c27f87dSAlex Deucher 	/* select the PLL algo */
4847c27f87dSAlex Deucher 	if (ASIC_IS_AVIVO(rdev)) {
485383be5d1SAlex Deucher 		if (radeon_new_pll == 0)
486383be5d1SAlex Deucher 			pll->algo = PLL_ALGO_LEGACY;
487383be5d1SAlex Deucher 		else
488383be5d1SAlex Deucher 			pll->algo = PLL_ALGO_NEW;
489383be5d1SAlex Deucher 	} else {
490383be5d1SAlex Deucher 		if (radeon_new_pll == 1)
491383be5d1SAlex Deucher 			pll->algo = PLL_ALGO_NEW;
4927c27f87dSAlex Deucher 		else
4937c27f87dSAlex Deucher 			pll->algo = PLL_ALGO_LEGACY;
494383be5d1SAlex Deucher 	}
4957c27f87dSAlex Deucher 
496771fe6b9SJerome Glisse 	if (ASIC_IS_AVIVO(rdev)) {
497eb1300bcSAlex Deucher 		if ((rdev->family == CHIP_RS600) ||
498eb1300bcSAlex Deucher 		    (rdev->family == CHIP_RS690) ||
499eb1300bcSAlex Deucher 		    (rdev->family == CHIP_RS740))
500fc10332bSAlex Deucher 			pll->flags |= (RADEON_PLL_USE_FRAC_FB_DIV |
501eb1300bcSAlex Deucher 				       RADEON_PLL_PREFER_CLOSEST_LOWER);
502eb1300bcSAlex Deucher 
503771fe6b9SJerome Glisse 		if (ASIC_IS_DCE32(rdev) && mode->clock > 200000)	/* range limits??? */
504fc10332bSAlex Deucher 			pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
505771fe6b9SJerome Glisse 		else
506fc10332bSAlex Deucher 			pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
507771fe6b9SJerome Glisse 	} else {
508fc10332bSAlex Deucher 		pll->flags |= RADEON_PLL_LEGACY;
509771fe6b9SJerome Glisse 
510771fe6b9SJerome Glisse 		if (mode->clock > 200000)	/* range limits??? */
511fc10332bSAlex Deucher 			pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
512771fe6b9SJerome Glisse 		else
513fc10332bSAlex Deucher 			pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
514771fe6b9SJerome Glisse 
515771fe6b9SJerome Glisse 	}
516771fe6b9SJerome Glisse 
517771fe6b9SJerome Glisse 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
518771fe6b9SJerome Glisse 		if (encoder->crtc == crtc) {
5194eaeca33SAlex Deucher 			radeon_encoder = to_radeon_encoder(encoder);
520bcc1c2a1SAlex Deucher 			encoder_mode = atombios_get_encoder_mode(encoder);
5214eaeca33SAlex Deucher 			if (ASIC_IS_AVIVO(rdev)) {
5224eaeca33SAlex Deucher 				/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
5234eaeca33SAlex Deucher 				if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
5244eaeca33SAlex Deucher 					adjusted_clock = mode->clock * 2;
525a1a4b23bSAlex Deucher 				if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
526a1a4b23bSAlex Deucher 					pll->algo = PLL_ALGO_LEGACY;
527a1a4b23bSAlex Deucher 					pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER;
528a1a4b23bSAlex Deucher 				}
5294eaeca33SAlex Deucher 			} else {
5304eaeca33SAlex Deucher 				if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
531fc10332bSAlex Deucher 					pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
5324eaeca33SAlex Deucher 				if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS)
533fc10332bSAlex Deucher 					pll->flags |= RADEON_PLL_USE_REF_DIV;
534771fe6b9SJerome Glisse 			}
5353ce0a23dSJerome Glisse 			break;
536771fe6b9SJerome Glisse 		}
537771fe6b9SJerome Glisse 	}
538771fe6b9SJerome Glisse 
5392606c886SAlex Deucher 	/* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock
5402606c886SAlex Deucher 	 * accordingly based on the encoder/transmitter to work around
5412606c886SAlex Deucher 	 * special hw requirements.
5422606c886SAlex Deucher 	 */
5432606c886SAlex Deucher 	if (ASIC_IS_DCE3(rdev)) {
5444eaeca33SAlex Deucher 		union adjust_pixel_clock args;
5454eaeca33SAlex Deucher 		u8 frev, crev;
5464eaeca33SAlex Deucher 		int index;
5472606c886SAlex Deucher 
5482606c886SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
549a084e6eeSAlex Deucher 		if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
550a084e6eeSAlex Deucher 					   &crev))
551a084e6eeSAlex Deucher 			return adjusted_clock;
5524eaeca33SAlex Deucher 
5534eaeca33SAlex Deucher 		memset(&args, 0, sizeof(args));
5544eaeca33SAlex Deucher 
5554eaeca33SAlex Deucher 		switch (frev) {
5564eaeca33SAlex Deucher 		case 1:
5574eaeca33SAlex Deucher 			switch (crev) {
5584eaeca33SAlex Deucher 			case 1:
5594eaeca33SAlex Deucher 			case 2:
5604eaeca33SAlex Deucher 				args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
5614eaeca33SAlex Deucher 				args.v1.ucTransmitterID = radeon_encoder->encoder_id;
562bcc1c2a1SAlex Deucher 				args.v1.ucEncodeMode = encoder_mode;
5634eaeca33SAlex Deucher 
5642606c886SAlex Deucher 				atom_execute_table(rdev->mode_info.atom_context,
5654eaeca33SAlex Deucher 						   index, (uint32_t *)&args);
5664eaeca33SAlex Deucher 				adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;
5674eaeca33SAlex Deucher 				break;
568bcc1c2a1SAlex Deucher 			case 3:
569bcc1c2a1SAlex Deucher 				args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10);
570bcc1c2a1SAlex Deucher 				args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id;
571bcc1c2a1SAlex Deucher 				args.v3.sInput.ucEncodeMode = encoder_mode;
572bcc1c2a1SAlex Deucher 				args.v3.sInput.ucDispPllConfig = 0;
573bcc1c2a1SAlex Deucher 				if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
574bcc1c2a1SAlex Deucher 					struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
575bcc1c2a1SAlex Deucher 
576bcc1c2a1SAlex Deucher 					if (encoder_mode == ATOM_ENCODER_MODE_DP)
577bcc1c2a1SAlex Deucher 						args.v3.sInput.ucDispPllConfig |=
578bcc1c2a1SAlex Deucher 							DISPPLL_CONFIG_COHERENT_MODE;
579bcc1c2a1SAlex Deucher 					else {
580bcc1c2a1SAlex Deucher 						if (dig->coherent_mode)
581bcc1c2a1SAlex Deucher 							args.v3.sInput.ucDispPllConfig |=
582bcc1c2a1SAlex Deucher 								DISPPLL_CONFIG_COHERENT_MODE;
583bcc1c2a1SAlex Deucher 						if (mode->clock > 165000)
584bcc1c2a1SAlex Deucher 							args.v3.sInput.ucDispPllConfig |=
585bcc1c2a1SAlex Deucher 								DISPPLL_CONFIG_DUAL_LINK;
586bcc1c2a1SAlex Deucher 					}
587bcc1c2a1SAlex Deucher 				} else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
588bcc1c2a1SAlex Deucher 					/* may want to enable SS on DP/eDP eventually */
5899f998ad7SAlex Deucher 					/*args.v3.sInput.ucDispPllConfig |=
5909f998ad7SAlex Deucher 						DISPPLL_CONFIG_SS_ENABLE;*/
5919f998ad7SAlex Deucher 					if (encoder_mode == ATOM_ENCODER_MODE_DP)
592bcc1c2a1SAlex Deucher 						args.v3.sInput.ucDispPllConfig |=
5939f998ad7SAlex Deucher 							DISPPLL_CONFIG_COHERENT_MODE;
5949f998ad7SAlex Deucher 					else {
595bcc1c2a1SAlex Deucher 						if (mode->clock > 165000)
596bcc1c2a1SAlex Deucher 							args.v3.sInput.ucDispPllConfig |=
597bcc1c2a1SAlex Deucher 								DISPPLL_CONFIG_DUAL_LINK;
598bcc1c2a1SAlex Deucher 					}
5999f998ad7SAlex Deucher 				}
600bcc1c2a1SAlex Deucher 				atom_execute_table(rdev->mode_info.atom_context,
601bcc1c2a1SAlex Deucher 						   index, (uint32_t *)&args);
602bcc1c2a1SAlex Deucher 				adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10;
603bcc1c2a1SAlex Deucher 				if (args.v3.sOutput.ucRefDiv) {
604bcc1c2a1SAlex Deucher 					pll->flags |= RADEON_PLL_USE_REF_DIV;
605bcc1c2a1SAlex Deucher 					pll->reference_div = args.v3.sOutput.ucRefDiv;
606bcc1c2a1SAlex Deucher 				}
607bcc1c2a1SAlex Deucher 				if (args.v3.sOutput.ucPostDiv) {
608bcc1c2a1SAlex Deucher 					pll->flags |= RADEON_PLL_USE_POST_DIV;
609bcc1c2a1SAlex Deucher 					pll->post_div = args.v3.sOutput.ucPostDiv;
610bcc1c2a1SAlex Deucher 				}
611bcc1c2a1SAlex Deucher 				break;
6124eaeca33SAlex Deucher 			default:
6134eaeca33SAlex Deucher 				DRM_ERROR("Unknown table version %d %d\n", frev, crev);
6144eaeca33SAlex Deucher 				return adjusted_clock;
615d56ef9c8SAlex Deucher 			}
6164eaeca33SAlex Deucher 			break;
6174eaeca33SAlex Deucher 		default:
6184eaeca33SAlex Deucher 			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
6194eaeca33SAlex Deucher 			return adjusted_clock;
6204eaeca33SAlex Deucher 		}
6214eaeca33SAlex Deucher 	}
6224eaeca33SAlex Deucher 	return adjusted_clock;
6234eaeca33SAlex Deucher }
6244eaeca33SAlex Deucher 
6254eaeca33SAlex Deucher union set_pixel_clock {
6264eaeca33SAlex Deucher 	SET_PIXEL_CLOCK_PS_ALLOCATION base;
6274eaeca33SAlex Deucher 	PIXEL_CLOCK_PARAMETERS v1;
6284eaeca33SAlex Deucher 	PIXEL_CLOCK_PARAMETERS_V2 v2;
6294eaeca33SAlex Deucher 	PIXEL_CLOCK_PARAMETERS_V3 v3;
630bcc1c2a1SAlex Deucher 	PIXEL_CLOCK_PARAMETERS_V5 v5;
6314eaeca33SAlex Deucher };
6324eaeca33SAlex Deucher 
633bcc1c2a1SAlex Deucher static void atombios_crtc_set_dcpll(struct drm_crtc *crtc)
634bcc1c2a1SAlex Deucher {
635bcc1c2a1SAlex Deucher 	struct drm_device *dev = crtc->dev;
636bcc1c2a1SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
637bcc1c2a1SAlex Deucher 	u8 frev, crev;
638bcc1c2a1SAlex Deucher 	int index;
639bcc1c2a1SAlex Deucher 	union set_pixel_clock args;
640bcc1c2a1SAlex Deucher 
641bcc1c2a1SAlex Deucher 	memset(&args, 0, sizeof(args));
642bcc1c2a1SAlex Deucher 
643bcc1c2a1SAlex Deucher 	index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
644a084e6eeSAlex Deucher 	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
645a084e6eeSAlex Deucher 				   &crev))
646a084e6eeSAlex Deucher 		return;
647bcc1c2a1SAlex Deucher 
648bcc1c2a1SAlex Deucher 	switch (frev) {
649bcc1c2a1SAlex Deucher 	case 1:
650bcc1c2a1SAlex Deucher 		switch (crev) {
651bcc1c2a1SAlex Deucher 		case 5:
652bcc1c2a1SAlex Deucher 			/* if the default dcpll clock is specified,
653bcc1c2a1SAlex Deucher 			 * SetPixelClock provides the dividers
654bcc1c2a1SAlex Deucher 			 */
655bcc1c2a1SAlex Deucher 			args.v5.ucCRTC = ATOM_CRTC_INVALID;
656bcc1c2a1SAlex Deucher 			args.v5.usPixelClock = rdev->clock.default_dispclk;
657bcc1c2a1SAlex Deucher 			args.v5.ucPpll = ATOM_DCPLL;
658bcc1c2a1SAlex Deucher 			break;
659bcc1c2a1SAlex Deucher 		default:
660bcc1c2a1SAlex Deucher 			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
661bcc1c2a1SAlex Deucher 			return;
662bcc1c2a1SAlex Deucher 		}
663bcc1c2a1SAlex Deucher 		break;
664bcc1c2a1SAlex Deucher 	default:
665bcc1c2a1SAlex Deucher 		DRM_ERROR("Unknown table version %d %d\n", frev, crev);
666bcc1c2a1SAlex Deucher 		return;
667bcc1c2a1SAlex Deucher 	}
668bcc1c2a1SAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
669bcc1c2a1SAlex Deucher }
670bcc1c2a1SAlex Deucher 
671bcc1c2a1SAlex Deucher static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
6724eaeca33SAlex Deucher {
6734eaeca33SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
6744eaeca33SAlex Deucher 	struct drm_device *dev = crtc->dev;
6754eaeca33SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
6764eaeca33SAlex Deucher 	struct drm_encoder *encoder = NULL;
6774eaeca33SAlex Deucher 	struct radeon_encoder *radeon_encoder = NULL;
6784eaeca33SAlex Deucher 	u8 frev, crev;
6794eaeca33SAlex Deucher 	int index;
6804eaeca33SAlex Deucher 	union set_pixel_clock args;
6814eaeca33SAlex Deucher 	u32 pll_clock = mode->clock;
6824eaeca33SAlex Deucher 	u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
6834eaeca33SAlex Deucher 	struct radeon_pll *pll;
6844eaeca33SAlex Deucher 	u32 adjusted_clock;
685bcc1c2a1SAlex Deucher 	int encoder_mode = 0;
6864eaeca33SAlex Deucher 
6874eaeca33SAlex Deucher 	memset(&args, 0, sizeof(args));
6884eaeca33SAlex Deucher 
6894eaeca33SAlex Deucher 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
6904eaeca33SAlex Deucher 		if (encoder->crtc == crtc) {
6914eaeca33SAlex Deucher 			radeon_encoder = to_radeon_encoder(encoder);
692bcc1c2a1SAlex Deucher 			encoder_mode = atombios_get_encoder_mode(encoder);
6934eaeca33SAlex Deucher 			break;
6944eaeca33SAlex Deucher 		}
6954eaeca33SAlex Deucher 	}
6964eaeca33SAlex Deucher 
6974eaeca33SAlex Deucher 	if (!radeon_encoder)
6984eaeca33SAlex Deucher 		return;
6994eaeca33SAlex Deucher 
700bcc1c2a1SAlex Deucher 	switch (radeon_crtc->pll_id) {
701bcc1c2a1SAlex Deucher 	case ATOM_PPLL1:
7024eaeca33SAlex Deucher 		pll = &rdev->clock.p1pll;
703bcc1c2a1SAlex Deucher 		break;
704bcc1c2a1SAlex Deucher 	case ATOM_PPLL2:
7054eaeca33SAlex Deucher 		pll = &rdev->clock.p2pll;
706bcc1c2a1SAlex Deucher 		break;
707bcc1c2a1SAlex Deucher 	case ATOM_DCPLL:
708bcc1c2a1SAlex Deucher 	case ATOM_PPLL_INVALID:
709bcc1c2a1SAlex Deucher 		pll = &rdev->clock.dcpll;
710bcc1c2a1SAlex Deucher 		break;
711bcc1c2a1SAlex Deucher 	}
7124eaeca33SAlex Deucher 
7134eaeca33SAlex Deucher 	/* adjust pixel clock as needed */
7144eaeca33SAlex Deucher 	adjusted_clock = atombios_adjust_pll(crtc, mode, pll);
7152606c886SAlex Deucher 
7162606c886SAlex Deucher 	radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
717fc10332bSAlex Deucher 			   &ref_div, &post_div);
718771fe6b9SJerome Glisse 
71939deb2d6SDave Airlie 	index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
720a084e6eeSAlex Deucher 	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
721a084e6eeSAlex Deucher 				   &crev))
722a084e6eeSAlex Deucher 		return;
723771fe6b9SJerome Glisse 
724771fe6b9SJerome Glisse 	switch (frev) {
725771fe6b9SJerome Glisse 	case 1:
726771fe6b9SJerome Glisse 		switch (crev) {
727771fe6b9SJerome Glisse 		case 1:
7284eaeca33SAlex Deucher 			args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
7294eaeca33SAlex Deucher 			args.v1.usRefDiv = cpu_to_le16(ref_div);
7304eaeca33SAlex Deucher 			args.v1.usFbDiv = cpu_to_le16(fb_div);
7314eaeca33SAlex Deucher 			args.v1.ucFracFbDiv = frac_fb_div;
7324eaeca33SAlex Deucher 			args.v1.ucPostDiv = post_div;
733bcc1c2a1SAlex Deucher 			args.v1.ucPpll = radeon_crtc->pll_id;
7344eaeca33SAlex Deucher 			args.v1.ucCRTC = radeon_crtc->crtc_id;
7354eaeca33SAlex Deucher 			args.v1.ucRefDivSrc = 1;
736771fe6b9SJerome Glisse 			break;
737771fe6b9SJerome Glisse 		case 2:
7384eaeca33SAlex Deucher 			args.v2.usPixelClock = cpu_to_le16(mode->clock / 10);
7394eaeca33SAlex Deucher 			args.v2.usRefDiv = cpu_to_le16(ref_div);
7404eaeca33SAlex Deucher 			args.v2.usFbDiv = cpu_to_le16(fb_div);
7414eaeca33SAlex Deucher 			args.v2.ucFracFbDiv = frac_fb_div;
7424eaeca33SAlex Deucher 			args.v2.ucPostDiv = post_div;
743bcc1c2a1SAlex Deucher 			args.v2.ucPpll = radeon_crtc->pll_id;
7444eaeca33SAlex Deucher 			args.v2.ucCRTC = radeon_crtc->crtc_id;
7454eaeca33SAlex Deucher 			args.v2.ucRefDivSrc = 1;
746771fe6b9SJerome Glisse 			break;
747771fe6b9SJerome Glisse 		case 3:
7484eaeca33SAlex Deucher 			args.v3.usPixelClock = cpu_to_le16(mode->clock / 10);
7494eaeca33SAlex Deucher 			args.v3.usRefDiv = cpu_to_le16(ref_div);
7504eaeca33SAlex Deucher 			args.v3.usFbDiv = cpu_to_le16(fb_div);
7514eaeca33SAlex Deucher 			args.v3.ucFracFbDiv = frac_fb_div;
7524eaeca33SAlex Deucher 			args.v3.ucPostDiv = post_div;
753bcc1c2a1SAlex Deucher 			args.v3.ucPpll = radeon_crtc->pll_id;
754bcc1c2a1SAlex Deucher 			args.v3.ucMiscInfo = (radeon_crtc->pll_id << 2);
7554eaeca33SAlex Deucher 			args.v3.ucTransmitterId = radeon_encoder->encoder_id;
756bcc1c2a1SAlex Deucher 			args.v3.ucEncoderMode = encoder_mode;
757bcc1c2a1SAlex Deucher 			break;
758bcc1c2a1SAlex Deucher 		case 5:
759bcc1c2a1SAlex Deucher 			args.v5.ucCRTC = radeon_crtc->crtc_id;
760bcc1c2a1SAlex Deucher 			args.v5.usPixelClock = cpu_to_le16(mode->clock / 10);
761bcc1c2a1SAlex Deucher 			args.v5.ucRefDiv = ref_div;
762bcc1c2a1SAlex Deucher 			args.v5.usFbDiv = cpu_to_le16(fb_div);
763bcc1c2a1SAlex Deucher 			args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
764bcc1c2a1SAlex Deucher 			args.v5.ucPostDiv = post_div;
765bcc1c2a1SAlex Deucher 			args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
766bcc1c2a1SAlex Deucher 			args.v5.ucTransmitterID = radeon_encoder->encoder_id;
767bcc1c2a1SAlex Deucher 			args.v5.ucEncoderMode = encoder_mode;
768bcc1c2a1SAlex Deucher 			args.v5.ucPpll = radeon_crtc->pll_id;
769771fe6b9SJerome Glisse 			break;
770771fe6b9SJerome Glisse 		default:
771771fe6b9SJerome Glisse 			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
772771fe6b9SJerome Glisse 			return;
773771fe6b9SJerome Glisse 		}
774771fe6b9SJerome Glisse 		break;
775771fe6b9SJerome Glisse 	default:
776771fe6b9SJerome Glisse 		DRM_ERROR("Unknown table version %d %d\n", frev, crev);
777771fe6b9SJerome Glisse 		return;
778771fe6b9SJerome Glisse 	}
779771fe6b9SJerome Glisse 
780771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
781771fe6b9SJerome Glisse }
782771fe6b9SJerome Glisse 
783bcc1c2a1SAlex Deucher static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y,
784bcc1c2a1SAlex Deucher 				   struct drm_framebuffer *old_fb)
785bcc1c2a1SAlex Deucher {
786bcc1c2a1SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
787bcc1c2a1SAlex Deucher 	struct drm_device *dev = crtc->dev;
788bcc1c2a1SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
789bcc1c2a1SAlex Deucher 	struct radeon_framebuffer *radeon_fb;
790bcc1c2a1SAlex Deucher 	struct drm_gem_object *obj;
791bcc1c2a1SAlex Deucher 	struct radeon_bo *rbo;
792bcc1c2a1SAlex Deucher 	uint64_t fb_location;
793bcc1c2a1SAlex Deucher 	uint32_t fb_format, fb_pitch_pixels, tiling_flags;
794bcc1c2a1SAlex Deucher 	int r;
795bcc1c2a1SAlex Deucher 
796bcc1c2a1SAlex Deucher 	/* no fb bound */
797bcc1c2a1SAlex Deucher 	if (!crtc->fb) {
798bcc1c2a1SAlex Deucher 		DRM_DEBUG("No FB bound\n");
799bcc1c2a1SAlex Deucher 		return 0;
800bcc1c2a1SAlex Deucher 	}
801bcc1c2a1SAlex Deucher 
802bcc1c2a1SAlex Deucher 	radeon_fb = to_radeon_framebuffer(crtc->fb);
803bcc1c2a1SAlex Deucher 
804bcc1c2a1SAlex Deucher 	/* Pin framebuffer & get tilling informations */
805bcc1c2a1SAlex Deucher 	obj = radeon_fb->obj;
806bcc1c2a1SAlex Deucher 	rbo = obj->driver_private;
807bcc1c2a1SAlex Deucher 	r = radeon_bo_reserve(rbo, false);
808bcc1c2a1SAlex Deucher 	if (unlikely(r != 0))
809bcc1c2a1SAlex Deucher 		return r;
810bcc1c2a1SAlex Deucher 	r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
811bcc1c2a1SAlex Deucher 	if (unlikely(r != 0)) {
812bcc1c2a1SAlex Deucher 		radeon_bo_unreserve(rbo);
813bcc1c2a1SAlex Deucher 		return -EINVAL;
814bcc1c2a1SAlex Deucher 	}
815bcc1c2a1SAlex Deucher 	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
816bcc1c2a1SAlex Deucher 	radeon_bo_unreserve(rbo);
817bcc1c2a1SAlex Deucher 
818bcc1c2a1SAlex Deucher 	switch (crtc->fb->bits_per_pixel) {
819bcc1c2a1SAlex Deucher 	case 8:
820bcc1c2a1SAlex Deucher 		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) |
821bcc1c2a1SAlex Deucher 			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED));
822bcc1c2a1SAlex Deucher 		break;
823bcc1c2a1SAlex Deucher 	case 15:
824bcc1c2a1SAlex Deucher 		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
825bcc1c2a1SAlex Deucher 			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555));
826bcc1c2a1SAlex Deucher 		break;
827bcc1c2a1SAlex Deucher 	case 16:
828bcc1c2a1SAlex Deucher 		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) |
829bcc1c2a1SAlex Deucher 			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565));
830bcc1c2a1SAlex Deucher 		break;
831bcc1c2a1SAlex Deucher 	case 24:
832bcc1c2a1SAlex Deucher 	case 32:
833bcc1c2a1SAlex Deucher 		fb_format = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) |
834bcc1c2a1SAlex Deucher 			     EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888));
835bcc1c2a1SAlex Deucher 		break;
836bcc1c2a1SAlex Deucher 	default:
837bcc1c2a1SAlex Deucher 		DRM_ERROR("Unsupported screen depth %d\n",
838bcc1c2a1SAlex Deucher 			  crtc->fb->bits_per_pixel);
839bcc1c2a1SAlex Deucher 		return -EINVAL;
840bcc1c2a1SAlex Deucher 	}
841bcc1c2a1SAlex Deucher 
842bcc1c2a1SAlex Deucher 	switch (radeon_crtc->crtc_id) {
843bcc1c2a1SAlex Deucher 	case 0:
844bcc1c2a1SAlex Deucher 		WREG32(AVIVO_D1VGA_CONTROL, 0);
845bcc1c2a1SAlex Deucher 		break;
846bcc1c2a1SAlex Deucher 	case 1:
847bcc1c2a1SAlex Deucher 		WREG32(AVIVO_D2VGA_CONTROL, 0);
848bcc1c2a1SAlex Deucher 		break;
849bcc1c2a1SAlex Deucher 	case 2:
850bcc1c2a1SAlex Deucher 		WREG32(EVERGREEN_D3VGA_CONTROL, 0);
851bcc1c2a1SAlex Deucher 		break;
852bcc1c2a1SAlex Deucher 	case 3:
853bcc1c2a1SAlex Deucher 		WREG32(EVERGREEN_D4VGA_CONTROL, 0);
854bcc1c2a1SAlex Deucher 		break;
855bcc1c2a1SAlex Deucher 	case 4:
856bcc1c2a1SAlex Deucher 		WREG32(EVERGREEN_D5VGA_CONTROL, 0);
857bcc1c2a1SAlex Deucher 		break;
858bcc1c2a1SAlex Deucher 	case 5:
859bcc1c2a1SAlex Deucher 		WREG32(EVERGREEN_D6VGA_CONTROL, 0);
860bcc1c2a1SAlex Deucher 		break;
861bcc1c2a1SAlex Deucher 	default:
862bcc1c2a1SAlex Deucher 		break;
863bcc1c2a1SAlex Deucher 	}
864bcc1c2a1SAlex Deucher 
865bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
866bcc1c2a1SAlex Deucher 	       upper_32_bits(fb_location));
867bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset,
868bcc1c2a1SAlex Deucher 	       upper_32_bits(fb_location));
869bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
870bcc1c2a1SAlex Deucher 	       (u32)fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
871bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
872bcc1c2a1SAlex Deucher 	       (u32) fb_location & EVERGREEN_GRPH_SURFACE_ADDRESS_MASK);
873bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
874bcc1c2a1SAlex Deucher 
875bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
876bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
877bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_X_START + radeon_crtc->crtc_offset, 0);
878bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_Y_START + radeon_crtc->crtc_offset, 0);
879bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
880bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
881bcc1c2a1SAlex Deucher 
882bcc1c2a1SAlex Deucher 	fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
883bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
884bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
885bcc1c2a1SAlex Deucher 
886bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
887bcc1c2a1SAlex Deucher 	       crtc->mode.vdisplay);
888bcc1c2a1SAlex Deucher 	x &= ~3;
889bcc1c2a1SAlex Deucher 	y &= ~1;
890bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset,
891bcc1c2a1SAlex Deucher 	       (x << 16) | y);
892bcc1c2a1SAlex Deucher 	WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
893bcc1c2a1SAlex Deucher 	       (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
894bcc1c2a1SAlex Deucher 
895bcc1c2a1SAlex Deucher 	if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
896bcc1c2a1SAlex Deucher 		WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset,
897bcc1c2a1SAlex Deucher 		       EVERGREEN_INTERLEAVE_EN);
898bcc1c2a1SAlex Deucher 	else
899bcc1c2a1SAlex Deucher 		WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
900bcc1c2a1SAlex Deucher 
901bcc1c2a1SAlex Deucher 	if (old_fb && old_fb != crtc->fb) {
902bcc1c2a1SAlex Deucher 		radeon_fb = to_radeon_framebuffer(old_fb);
903bcc1c2a1SAlex Deucher 		rbo = radeon_fb->obj->driver_private;
904bcc1c2a1SAlex Deucher 		r = radeon_bo_reserve(rbo, false);
905bcc1c2a1SAlex Deucher 		if (unlikely(r != 0))
906bcc1c2a1SAlex Deucher 			return r;
907bcc1c2a1SAlex Deucher 		radeon_bo_unpin(rbo);
908bcc1c2a1SAlex Deucher 		radeon_bo_unreserve(rbo);
909bcc1c2a1SAlex Deucher 	}
910bcc1c2a1SAlex Deucher 
911bcc1c2a1SAlex Deucher 	/* Bytes per pixel may have changed */
912bcc1c2a1SAlex Deucher 	radeon_bandwidth_update(rdev);
913bcc1c2a1SAlex Deucher 
914bcc1c2a1SAlex Deucher 	return 0;
915bcc1c2a1SAlex Deucher }
916bcc1c2a1SAlex Deucher 
91754f088a9SAlex Deucher static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
918771fe6b9SJerome Glisse 			       struct drm_framebuffer *old_fb)
919771fe6b9SJerome Glisse {
920771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
921771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
922771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
923771fe6b9SJerome Glisse 	struct radeon_framebuffer *radeon_fb;
924771fe6b9SJerome Glisse 	struct drm_gem_object *obj;
9254c788679SJerome Glisse 	struct radeon_bo *rbo;
926771fe6b9SJerome Glisse 	uint64_t fb_location;
927e024e110SDave Airlie 	uint32_t fb_format, fb_pitch_pixels, tiling_flags;
9284c788679SJerome Glisse 	int r;
929771fe6b9SJerome Glisse 
9302de3b484SJerome Glisse 	/* no fb bound */
9312de3b484SJerome Glisse 	if (!crtc->fb) {
9322de3b484SJerome Glisse 		DRM_DEBUG("No FB bound\n");
9332de3b484SJerome Glisse 		return 0;
9342de3b484SJerome Glisse 	}
935771fe6b9SJerome Glisse 
936771fe6b9SJerome Glisse 	radeon_fb = to_radeon_framebuffer(crtc->fb);
937771fe6b9SJerome Glisse 
9384c788679SJerome Glisse 	/* Pin framebuffer & get tilling informations */
939771fe6b9SJerome Glisse 	obj = radeon_fb->obj;
9404c788679SJerome Glisse 	rbo = obj->driver_private;
9414c788679SJerome Glisse 	r = radeon_bo_reserve(rbo, false);
9424c788679SJerome Glisse 	if (unlikely(r != 0))
9434c788679SJerome Glisse 		return r;
9444c788679SJerome Glisse 	r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
9454c788679SJerome Glisse 	if (unlikely(r != 0)) {
9464c788679SJerome Glisse 		radeon_bo_unreserve(rbo);
947771fe6b9SJerome Glisse 		return -EINVAL;
948771fe6b9SJerome Glisse 	}
9494c788679SJerome Glisse 	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
9504c788679SJerome Glisse 	radeon_bo_unreserve(rbo);
951771fe6b9SJerome Glisse 
952771fe6b9SJerome Glisse 	switch (crtc->fb->bits_per_pixel) {
95341456df2SDave Airlie 	case 8:
95441456df2SDave Airlie 		fb_format =
95541456df2SDave Airlie 		    AVIVO_D1GRPH_CONTROL_DEPTH_8BPP |
95641456df2SDave Airlie 		    AVIVO_D1GRPH_CONTROL_8BPP_INDEXED;
95741456df2SDave Airlie 		break;
958771fe6b9SJerome Glisse 	case 15:
959771fe6b9SJerome Glisse 		fb_format =
960771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
961771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555;
962771fe6b9SJerome Glisse 		break;
963771fe6b9SJerome Glisse 	case 16:
964771fe6b9SJerome Glisse 		fb_format =
965771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
966771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_16BPP_RGB565;
967771fe6b9SJerome Glisse 		break;
968771fe6b9SJerome Glisse 	case 24:
969771fe6b9SJerome Glisse 	case 32:
970771fe6b9SJerome Glisse 		fb_format =
971771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
972771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888;
973771fe6b9SJerome Glisse 		break;
974771fe6b9SJerome Glisse 	default:
975771fe6b9SJerome Glisse 		DRM_ERROR("Unsupported screen depth %d\n",
976771fe6b9SJerome Glisse 			  crtc->fb->bits_per_pixel);
977771fe6b9SJerome Glisse 		return -EINVAL;
978771fe6b9SJerome Glisse 	}
979771fe6b9SJerome Glisse 
980cf2f05d3SDave Airlie 	if (tiling_flags & RADEON_TILING_MACRO)
981cf2f05d3SDave Airlie 		fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE;
982cf2f05d3SDave Airlie 
983e024e110SDave Airlie 	if (tiling_flags & RADEON_TILING_MICRO)
984e024e110SDave Airlie 		fb_format |= AVIVO_D1GRPH_TILED;
985e024e110SDave Airlie 
986771fe6b9SJerome Glisse 	if (radeon_crtc->crtc_id == 0)
987771fe6b9SJerome Glisse 		WREG32(AVIVO_D1VGA_CONTROL, 0);
988771fe6b9SJerome Glisse 	else
989771fe6b9SJerome Glisse 		WREG32(AVIVO_D2VGA_CONTROL, 0);
990c290dadfSAlex Deucher 
991c290dadfSAlex Deucher 	if (rdev->family >= CHIP_RV770) {
992c290dadfSAlex Deucher 		if (radeon_crtc->crtc_id) {
993c290dadfSAlex Deucher 			WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0);
994c290dadfSAlex Deucher 			WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0);
995c290dadfSAlex Deucher 		} else {
996c290dadfSAlex Deucher 			WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0);
997c290dadfSAlex Deucher 			WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0);
998c290dadfSAlex Deucher 		}
999c290dadfSAlex Deucher 	}
1000771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
1001771fe6b9SJerome Glisse 	       (u32) fb_location);
1002771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS +
1003771fe6b9SJerome Glisse 	       radeon_crtc->crtc_offset, (u32) fb_location);
1004771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
1005771fe6b9SJerome Glisse 
1006771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
1007771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
1008771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0);
1009771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0);
1010771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
1011771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
1012771fe6b9SJerome Glisse 
1013771fe6b9SJerome Glisse 	fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
1014771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
1015771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
1016771fe6b9SJerome Glisse 
1017771fe6b9SJerome Glisse 	WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
1018771fe6b9SJerome Glisse 	       crtc->mode.vdisplay);
1019771fe6b9SJerome Glisse 	x &= ~3;
1020771fe6b9SJerome Glisse 	y &= ~1;
1021771fe6b9SJerome Glisse 	WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset,
1022771fe6b9SJerome Glisse 	       (x << 16) | y);
1023771fe6b9SJerome Glisse 	WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
1024771fe6b9SJerome Glisse 	       (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
1025771fe6b9SJerome Glisse 
1026771fe6b9SJerome Glisse 	if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
1027771fe6b9SJerome Glisse 		WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
1028771fe6b9SJerome Glisse 		       AVIVO_D1MODE_INTERLEAVE_EN);
1029771fe6b9SJerome Glisse 	else
1030771fe6b9SJerome Glisse 		WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
1031771fe6b9SJerome Glisse 
1032771fe6b9SJerome Glisse 	if (old_fb && old_fb != crtc->fb) {
1033771fe6b9SJerome Glisse 		radeon_fb = to_radeon_framebuffer(old_fb);
10344c788679SJerome Glisse 		rbo = radeon_fb->obj->driver_private;
10354c788679SJerome Glisse 		r = radeon_bo_reserve(rbo, false);
10364c788679SJerome Glisse 		if (unlikely(r != 0))
10374c788679SJerome Glisse 			return r;
10384c788679SJerome Glisse 		radeon_bo_unpin(rbo);
10394c788679SJerome Glisse 		radeon_bo_unreserve(rbo);
1040771fe6b9SJerome Glisse 	}
1041f30f37deSMichel Dänzer 
1042f30f37deSMichel Dänzer 	/* Bytes per pixel may have changed */
1043f30f37deSMichel Dänzer 	radeon_bandwidth_update(rdev);
1044f30f37deSMichel Dänzer 
1045771fe6b9SJerome Glisse 	return 0;
1046771fe6b9SJerome Glisse }
1047771fe6b9SJerome Glisse 
104854f088a9SAlex Deucher int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
104954f088a9SAlex Deucher 			   struct drm_framebuffer *old_fb)
105054f088a9SAlex Deucher {
105154f088a9SAlex Deucher 	struct drm_device *dev = crtc->dev;
105254f088a9SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
105354f088a9SAlex Deucher 
1054bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev))
1055bcc1c2a1SAlex Deucher 		return evergreen_crtc_set_base(crtc, x, y, old_fb);
1056bcc1c2a1SAlex Deucher 	else if (ASIC_IS_AVIVO(rdev))
105754f088a9SAlex Deucher 		return avivo_crtc_set_base(crtc, x, y, old_fb);
105854f088a9SAlex Deucher 	else
105954f088a9SAlex Deucher 		return radeon_crtc_set_base(crtc, x, y, old_fb);
106054f088a9SAlex Deucher }
106154f088a9SAlex Deucher 
1062615e0cb6SAlex Deucher /* properly set additional regs when using atombios */
1063615e0cb6SAlex Deucher static void radeon_legacy_atom_fixup(struct drm_crtc *crtc)
1064615e0cb6SAlex Deucher {
1065615e0cb6SAlex Deucher 	struct drm_device *dev = crtc->dev;
1066615e0cb6SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
1067615e0cb6SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1068615e0cb6SAlex Deucher 	u32 disp_merge_cntl;
1069615e0cb6SAlex Deucher 
1070615e0cb6SAlex Deucher 	switch (radeon_crtc->crtc_id) {
1071615e0cb6SAlex Deucher 	case 0:
1072615e0cb6SAlex Deucher 		disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL);
1073615e0cb6SAlex Deucher 		disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
1074615e0cb6SAlex Deucher 		WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl);
1075615e0cb6SAlex Deucher 		break;
1076615e0cb6SAlex Deucher 	case 1:
1077615e0cb6SAlex Deucher 		disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL);
1078615e0cb6SAlex Deucher 		disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN;
1079615e0cb6SAlex Deucher 		WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl);
1080615e0cb6SAlex Deucher 		WREG32(RADEON_FP_H2_SYNC_STRT_WID,   RREG32(RADEON_CRTC2_H_SYNC_STRT_WID));
1081615e0cb6SAlex Deucher 		WREG32(RADEON_FP_V2_SYNC_STRT_WID,   RREG32(RADEON_CRTC2_V_SYNC_STRT_WID));
1082615e0cb6SAlex Deucher 		break;
1083615e0cb6SAlex Deucher 	}
1084615e0cb6SAlex Deucher }
1085615e0cb6SAlex Deucher 
1086bcc1c2a1SAlex Deucher static int radeon_atom_pick_pll(struct drm_crtc *crtc)
1087bcc1c2a1SAlex Deucher {
1088bcc1c2a1SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1089bcc1c2a1SAlex Deucher 	struct drm_device *dev = crtc->dev;
1090bcc1c2a1SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
1091bcc1c2a1SAlex Deucher 	struct drm_encoder *test_encoder;
1092bcc1c2a1SAlex Deucher 	struct drm_crtc *test_crtc;
1093bcc1c2a1SAlex Deucher 	uint32_t pll_in_use = 0;
1094bcc1c2a1SAlex Deucher 
1095bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev)) {
1096bcc1c2a1SAlex Deucher 		/* if crtc is driving DP and we have an ext clock, use that */
1097bcc1c2a1SAlex Deucher 		list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
1098bcc1c2a1SAlex Deucher 			if (test_encoder->crtc && (test_encoder->crtc == crtc)) {
1099bcc1c2a1SAlex Deucher 				if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) {
1100bcc1c2a1SAlex Deucher 					if (rdev->clock.dp_extclk)
1101bcc1c2a1SAlex Deucher 						return ATOM_PPLL_INVALID;
1102bcc1c2a1SAlex Deucher 				}
1103bcc1c2a1SAlex Deucher 			}
1104bcc1c2a1SAlex Deucher 		}
1105bcc1c2a1SAlex Deucher 
1106bcc1c2a1SAlex Deucher 		/* otherwise, pick one of the plls */
1107bcc1c2a1SAlex Deucher 		list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
1108bcc1c2a1SAlex Deucher 			struct radeon_crtc *radeon_test_crtc;
1109bcc1c2a1SAlex Deucher 
1110bcc1c2a1SAlex Deucher 			if (crtc == test_crtc)
1111bcc1c2a1SAlex Deucher 				continue;
1112bcc1c2a1SAlex Deucher 
1113bcc1c2a1SAlex Deucher 			radeon_test_crtc = to_radeon_crtc(test_crtc);
1114bcc1c2a1SAlex Deucher 			if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) &&
1115bcc1c2a1SAlex Deucher 			    (radeon_test_crtc->pll_id <= ATOM_PPLL2))
1116bcc1c2a1SAlex Deucher 				pll_in_use |= (1 << radeon_test_crtc->pll_id);
1117bcc1c2a1SAlex Deucher 		}
1118bcc1c2a1SAlex Deucher 		if (!(pll_in_use & 1))
1119bcc1c2a1SAlex Deucher 			return ATOM_PPLL1;
1120bcc1c2a1SAlex Deucher 		return ATOM_PPLL2;
1121bcc1c2a1SAlex Deucher 	} else
1122bcc1c2a1SAlex Deucher 		return radeon_crtc->crtc_id;
1123bcc1c2a1SAlex Deucher 
1124bcc1c2a1SAlex Deucher }
1125bcc1c2a1SAlex Deucher 
1126771fe6b9SJerome Glisse int atombios_crtc_mode_set(struct drm_crtc *crtc,
1127771fe6b9SJerome Glisse 			   struct drm_display_mode *mode,
1128771fe6b9SJerome Glisse 			   struct drm_display_mode *adjusted_mode,
1129771fe6b9SJerome Glisse 			   int x, int y, struct drm_framebuffer *old_fb)
1130771fe6b9SJerome Glisse {
1131771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1132771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
1133771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
1134771fe6b9SJerome Glisse 
1135771fe6b9SJerome Glisse 	/* TODO color tiling */
1136771fe6b9SJerome Glisse 
1137b792210eSAlex Deucher 	atombios_disable_ss(crtc);
1138bcc1c2a1SAlex Deucher 	/* always set DCPLL */
1139bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev))
1140bcc1c2a1SAlex Deucher 		atombios_crtc_set_dcpll(crtc);
1141771fe6b9SJerome Glisse 	atombios_crtc_set_pll(crtc, adjusted_mode);
1142b792210eSAlex Deucher 	atombios_enable_ss(crtc);
1143771fe6b9SJerome Glisse 
1144bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev))
1145bcc1c2a1SAlex Deucher 		atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
1146bcc1c2a1SAlex Deucher 	else if (ASIC_IS_AVIVO(rdev))
1147bcc1c2a1SAlex Deucher 		atombios_crtc_set_timing(crtc, adjusted_mode);
1148771fe6b9SJerome Glisse 	else {
1149bcc1c2a1SAlex Deucher 		atombios_crtc_set_timing(crtc, adjusted_mode);
11505a9bcaccSAlex Deucher 		if (radeon_crtc->crtc_id == 0)
11515a9bcaccSAlex Deucher 			atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
1152615e0cb6SAlex Deucher 		radeon_legacy_atom_fixup(crtc);
1153771fe6b9SJerome Glisse 	}
1154bcc1c2a1SAlex Deucher 	atombios_crtc_set_base(crtc, x, y, old_fb);
1155c93bb85bSJerome Glisse 	atombios_overscan_setup(crtc, mode, adjusted_mode);
1156c93bb85bSJerome Glisse 	atombios_scaler_setup(crtc);
1157771fe6b9SJerome Glisse 	return 0;
1158771fe6b9SJerome Glisse }
1159771fe6b9SJerome Glisse 
1160771fe6b9SJerome Glisse static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
1161771fe6b9SJerome Glisse 				     struct drm_display_mode *mode,
1162771fe6b9SJerome Glisse 				     struct drm_display_mode *adjusted_mode)
1163771fe6b9SJerome Glisse {
116403214bd5SAlex Deucher 	struct drm_device *dev = crtc->dev;
116503214bd5SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
116603214bd5SAlex Deucher 
116703214bd5SAlex Deucher 	/* adjust pm to upcoming mode change */
116803214bd5SAlex Deucher 	radeon_pm_compute_clocks(rdev);
116903214bd5SAlex Deucher 
1170c93bb85bSJerome Glisse 	if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
1171c93bb85bSJerome Glisse 		return false;
1172771fe6b9SJerome Glisse 	return true;
1173771fe6b9SJerome Glisse }
1174771fe6b9SJerome Glisse 
1175771fe6b9SJerome Glisse static void atombios_crtc_prepare(struct drm_crtc *crtc)
1176771fe6b9SJerome Glisse {
1177267364acSAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1178267364acSAlex Deucher 
1179267364acSAlex Deucher 	/* pick pll */
1180267364acSAlex Deucher 	radeon_crtc->pll_id = radeon_atom_pick_pll(crtc);
1181267364acSAlex Deucher 
118237b4390eSAlex Deucher 	atombios_lock_crtc(crtc, ATOM_ENABLE);
1183a348c84dSAlex Deucher 	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
1184771fe6b9SJerome Glisse }
1185771fe6b9SJerome Glisse 
1186771fe6b9SJerome Glisse static void atombios_crtc_commit(struct drm_crtc *crtc)
1187771fe6b9SJerome Glisse {
1188771fe6b9SJerome Glisse 	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
118937b4390eSAlex Deucher 	atombios_lock_crtc(crtc, ATOM_DISABLE);
1190771fe6b9SJerome Glisse }
1191771fe6b9SJerome Glisse 
1192771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
1193771fe6b9SJerome Glisse 	.dpms = atombios_crtc_dpms,
1194771fe6b9SJerome Glisse 	.mode_fixup = atombios_crtc_mode_fixup,
1195771fe6b9SJerome Glisse 	.mode_set = atombios_crtc_mode_set,
1196771fe6b9SJerome Glisse 	.mode_set_base = atombios_crtc_set_base,
1197771fe6b9SJerome Glisse 	.prepare = atombios_crtc_prepare,
1198771fe6b9SJerome Glisse 	.commit = atombios_crtc_commit,
1199068143d3SDave Airlie 	.load_lut = radeon_crtc_load_lut,
1200771fe6b9SJerome Glisse };
1201771fe6b9SJerome Glisse 
1202771fe6b9SJerome Glisse void radeon_atombios_init_crtc(struct drm_device *dev,
1203771fe6b9SJerome Glisse 			       struct radeon_crtc *radeon_crtc)
1204771fe6b9SJerome Glisse {
1205bcc1c2a1SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
1206bcc1c2a1SAlex Deucher 
1207bcc1c2a1SAlex Deucher 	if (ASIC_IS_DCE4(rdev)) {
1208bcc1c2a1SAlex Deucher 		switch (radeon_crtc->crtc_id) {
1209bcc1c2a1SAlex Deucher 		case 0:
1210bcc1c2a1SAlex Deucher 		default:
121112d7798fSAlex Deucher 			radeon_crtc->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET;
1212bcc1c2a1SAlex Deucher 			break;
1213bcc1c2a1SAlex Deucher 		case 1:
121412d7798fSAlex Deucher 			radeon_crtc->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET;
1215bcc1c2a1SAlex Deucher 			break;
1216bcc1c2a1SAlex Deucher 		case 2:
121712d7798fSAlex Deucher 			radeon_crtc->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET;
1218bcc1c2a1SAlex Deucher 			break;
1219bcc1c2a1SAlex Deucher 		case 3:
122012d7798fSAlex Deucher 			radeon_crtc->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET;
1221bcc1c2a1SAlex Deucher 			break;
1222bcc1c2a1SAlex Deucher 		case 4:
122312d7798fSAlex Deucher 			radeon_crtc->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET;
1224bcc1c2a1SAlex Deucher 			break;
1225bcc1c2a1SAlex Deucher 		case 5:
122612d7798fSAlex Deucher 			radeon_crtc->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET;
1227bcc1c2a1SAlex Deucher 			break;
1228bcc1c2a1SAlex Deucher 		}
1229bcc1c2a1SAlex Deucher 	} else {
1230771fe6b9SJerome Glisse 		if (radeon_crtc->crtc_id == 1)
1231771fe6b9SJerome Glisse 			radeon_crtc->crtc_offset =
1232771fe6b9SJerome Glisse 				AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL;
1233bcc1c2a1SAlex Deucher 		else
1234bcc1c2a1SAlex Deucher 			radeon_crtc->crtc_offset = 0;
1235bcc1c2a1SAlex Deucher 	}
1236bcc1c2a1SAlex Deucher 	radeon_crtc->pll_id = -1;
1237771fe6b9SJerome Glisse 	drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
1238771fe6b9SJerome Glisse }
1239