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:
2485f9a0eb5SAlex Deucher 		atombios_enable_crtc(crtc, 1);
249771fe6b9SJerome Glisse 		if (ASIC_IS_DCE3(rdev))
250771fe6b9SJerome Glisse 			atombios_enable_crtc_memreq(crtc, 1);
251771fe6b9SJerome Glisse 		atombios_blank_crtc(crtc, 0);
252500b7587SAlex Deucher 		drm_vblank_post_modeset(dev, radeon_crtc->crtc_id);
253500b7587SAlex Deucher 		radeon_crtc_load_lut(crtc);
254771fe6b9SJerome Glisse 		break;
255771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_STANDBY:
256771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_SUSPEND:
257771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_OFF:
258500b7587SAlex Deucher 		drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id);
259771fe6b9SJerome Glisse 		atombios_blank_crtc(crtc, 1);
260771fe6b9SJerome Glisse 		if (ASIC_IS_DCE3(rdev))
261771fe6b9SJerome Glisse 			atombios_enable_crtc_memreq(crtc, 0);
2625f9a0eb5SAlex Deucher 		atombios_enable_crtc(crtc, 0);
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));
2795a9bcaccSAlex Deucher 	args.usH_Size = cpu_to_le16(mode->crtc_hdisplay);
2805a9bcaccSAlex Deucher 	args.usH_Blanking_Time =
2815a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay);
2825a9bcaccSAlex Deucher 	args.usV_Size = cpu_to_le16(mode->crtc_vdisplay);
2835a9bcaccSAlex Deucher 	args.usV_Blanking_Time =
2845a9bcaccSAlex Deucher 	    cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay);
2855a9bcaccSAlex Deucher 	args.usH_SyncOffset =
2865a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay);
2875a9bcaccSAlex Deucher 	args.usH_SyncWidth =
2885a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
2895a9bcaccSAlex Deucher 	args.usV_SyncOffset =
2905a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay);
2915a9bcaccSAlex Deucher 	args.usV_SyncWidth =
2925a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
2935a9bcaccSAlex Deucher 	/*args.ucH_Border = mode->hborder;*/
2945a9bcaccSAlex Deucher 	/*args.ucV_Border = mode->vborder;*/
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 
310771fe6b9SJerome Glisse 	printk("executing set crtc dtd timing\n");
3115a9bcaccSAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
312771fe6b9SJerome Glisse }
313771fe6b9SJerome Glisse 
3145a9bcaccSAlex Deucher static void atombios_crtc_set_timing(struct drm_crtc *crtc,
3155a9bcaccSAlex Deucher 				     struct drm_display_mode *mode)
316771fe6b9SJerome Glisse {
3175a9bcaccSAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
318771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
319771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
3205a9bcaccSAlex Deucher 	SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args;
321771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing);
3225a9bcaccSAlex Deucher 	u16 misc = 0;
323771fe6b9SJerome Glisse 
3245a9bcaccSAlex Deucher 	memset(&args, 0, sizeof(args));
3255a9bcaccSAlex Deucher 	args.usH_Total = cpu_to_le16(mode->crtc_htotal);
3265a9bcaccSAlex Deucher 	args.usH_Disp = cpu_to_le16(mode->crtc_hdisplay);
3275a9bcaccSAlex Deucher 	args.usH_SyncStart = cpu_to_le16(mode->crtc_hsync_start);
3285a9bcaccSAlex Deucher 	args.usH_SyncWidth =
3295a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start);
3305a9bcaccSAlex Deucher 	args.usV_Total = cpu_to_le16(mode->crtc_vtotal);
3315a9bcaccSAlex Deucher 	args.usV_Disp = cpu_to_le16(mode->crtc_vdisplay);
3325a9bcaccSAlex Deucher 	args.usV_SyncStart = cpu_to_le16(mode->crtc_vsync_start);
3335a9bcaccSAlex Deucher 	args.usV_SyncWidth =
3345a9bcaccSAlex Deucher 		cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start);
3355a9bcaccSAlex Deucher 
3365a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
3375a9bcaccSAlex Deucher 		misc |= ATOM_VSYNC_POLARITY;
3385a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
3395a9bcaccSAlex Deucher 		misc |= ATOM_HSYNC_POLARITY;
3405a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_CSYNC)
3415a9bcaccSAlex Deucher 		misc |= ATOM_COMPOSITESYNC;
3425a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
3435a9bcaccSAlex Deucher 		misc |= ATOM_INTERLACE;
3445a9bcaccSAlex Deucher 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
3455a9bcaccSAlex Deucher 		misc |= ATOM_DOUBLE_CLOCK_MODE;
3465a9bcaccSAlex Deucher 
3475a9bcaccSAlex Deucher 	args.susModeMiscInfo.usAccess = cpu_to_le16(misc);
3485a9bcaccSAlex Deucher 	args.ucCRTC = radeon_crtc->crtc_id;
349771fe6b9SJerome Glisse 
350771fe6b9SJerome Glisse 	printk("executing set crtc timing\n");
3515a9bcaccSAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
352771fe6b9SJerome Glisse }
353771fe6b9SJerome Glisse 
354ebbe1cb9SAlex Deucher static void atombios_set_ss(struct drm_crtc *crtc, int enable)
355ebbe1cb9SAlex Deucher {
356ebbe1cb9SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
357ebbe1cb9SAlex Deucher 	struct drm_device *dev = crtc->dev;
358ebbe1cb9SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
359ebbe1cb9SAlex Deucher 	struct drm_encoder *encoder = NULL;
360ebbe1cb9SAlex Deucher 	struct radeon_encoder *radeon_encoder = NULL;
361ebbe1cb9SAlex Deucher 	struct radeon_encoder_atom_dig *dig = NULL;
362ebbe1cb9SAlex Deucher 	int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
363ebbe1cb9SAlex Deucher 	ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION args;
364ebbe1cb9SAlex Deucher 	ENABLE_LVDS_SS_PARAMETERS legacy_args;
365ebbe1cb9SAlex Deucher 	uint16_t percentage = 0;
366ebbe1cb9SAlex Deucher 	uint8_t type = 0, step = 0, delay = 0, range = 0;
367ebbe1cb9SAlex Deucher 
368ebbe1cb9SAlex Deucher 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
369ebbe1cb9SAlex Deucher 		if (encoder->crtc == crtc) {
370ebbe1cb9SAlex Deucher 			radeon_encoder = to_radeon_encoder(encoder);
371ebbe1cb9SAlex Deucher 			/* only enable spread spectrum on LVDS */
372d11aa88bSAlex Deucher 			if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
373d11aa88bSAlex Deucher 				dig = radeon_encoder->enc_priv;
374ebbe1cb9SAlex Deucher 				if (dig && dig->ss) {
375ebbe1cb9SAlex Deucher 					percentage = dig->ss->percentage;
376ebbe1cb9SAlex Deucher 					type = dig->ss->type;
377ebbe1cb9SAlex Deucher 					step = dig->ss->step;
378ebbe1cb9SAlex Deucher 					delay = dig->ss->delay;
379ebbe1cb9SAlex Deucher 					range = dig->ss->range;
380ebbe1cb9SAlex Deucher 				} else if (enable)
381ebbe1cb9SAlex Deucher 					return;
382d11aa88bSAlex Deucher 			} else if (enable)
383d11aa88bSAlex Deucher 				return;
384ebbe1cb9SAlex Deucher 			break;
385ebbe1cb9SAlex Deucher 		}
386ebbe1cb9SAlex Deucher 	}
387ebbe1cb9SAlex Deucher 
388ebbe1cb9SAlex Deucher 	if (!radeon_encoder)
389ebbe1cb9SAlex Deucher 		return;
390ebbe1cb9SAlex Deucher 
391ebbe1cb9SAlex Deucher 	if (ASIC_IS_AVIVO(rdev)) {
392ebbe1cb9SAlex Deucher 		memset(&args, 0, sizeof(args));
393d11aa88bSAlex Deucher 		args.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
394ebbe1cb9SAlex Deucher 		args.ucSpreadSpectrumType = type;
395ebbe1cb9SAlex Deucher 		args.ucSpreadSpectrumStep = step;
396ebbe1cb9SAlex Deucher 		args.ucSpreadSpectrumDelay = delay;
397ebbe1cb9SAlex Deucher 		args.ucSpreadSpectrumRange = range;
398ebbe1cb9SAlex Deucher 		args.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
399ebbe1cb9SAlex Deucher 		args.ucEnable = enable;
400ebbe1cb9SAlex Deucher 		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
401ebbe1cb9SAlex Deucher 	} else {
402ebbe1cb9SAlex Deucher 		memset(&legacy_args, 0, sizeof(legacy_args));
403d11aa88bSAlex Deucher 		legacy_args.usSpreadSpectrumPercentage = cpu_to_le16(percentage);
404ebbe1cb9SAlex Deucher 		legacy_args.ucSpreadSpectrumType = type;
405ebbe1cb9SAlex Deucher 		legacy_args.ucSpreadSpectrumStepSize_Delay = (step & 3) << 2;
406ebbe1cb9SAlex Deucher 		legacy_args.ucSpreadSpectrumStepSize_Delay |= (delay & 7) << 4;
407ebbe1cb9SAlex Deucher 		legacy_args.ucEnable = enable;
408ebbe1cb9SAlex Deucher 		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&legacy_args);
409ebbe1cb9SAlex Deucher 	}
410ebbe1cb9SAlex Deucher }
411ebbe1cb9SAlex Deucher 
412771fe6b9SJerome Glisse void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
413771fe6b9SJerome Glisse {
414771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
415771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
416771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
417771fe6b9SJerome Glisse 	struct drm_encoder *encoder = NULL;
418771fe6b9SJerome Glisse 	struct radeon_encoder *radeon_encoder = NULL;
419771fe6b9SJerome Glisse 	uint8_t frev, crev;
4202606c886SAlex Deucher 	int index;
421771fe6b9SJerome Glisse 	SET_PIXEL_CLOCK_PS_ALLOCATION args;
422771fe6b9SJerome Glisse 	PIXEL_CLOCK_PARAMETERS *spc1_ptr;
423771fe6b9SJerome Glisse 	PIXEL_CLOCK_PARAMETERS_V2 *spc2_ptr;
424771fe6b9SJerome Glisse 	PIXEL_CLOCK_PARAMETERS_V3 *spc3_ptr;
4252606c886SAlex Deucher 	uint32_t pll_clock = mode->clock;
4262606c886SAlex Deucher 	uint32_t adjusted_clock;
427771fe6b9SJerome Glisse 	uint32_t ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
428771fe6b9SJerome Glisse 	struct radeon_pll *pll;
429fc10332bSAlex Deucher 
430fc10332bSAlex Deucher 	if (radeon_crtc->crtc_id == 0)
431fc10332bSAlex Deucher 		pll = &rdev->clock.p1pll;
432fc10332bSAlex Deucher 	else
433fc10332bSAlex Deucher 		pll = &rdev->clock.p2pll;
434771fe6b9SJerome Glisse 
435771fe6b9SJerome Glisse 	memset(&args, 0, sizeof(args));
436771fe6b9SJerome Glisse 
437771fe6b9SJerome Glisse 	if (ASIC_IS_AVIVO(rdev)) {
438eb1300bcSAlex Deucher 		if ((rdev->family == CHIP_RS600) ||
439eb1300bcSAlex Deucher 		    (rdev->family == CHIP_RS690) ||
440eb1300bcSAlex Deucher 		    (rdev->family == CHIP_RS740))
441fc10332bSAlex Deucher 			pll->flags |= (RADEON_PLL_USE_FRAC_FB_DIV |
442eb1300bcSAlex Deucher 				       RADEON_PLL_PREFER_CLOSEST_LOWER);
443eb1300bcSAlex Deucher 
444771fe6b9SJerome Glisse 		if (ASIC_IS_DCE32(rdev) && mode->clock > 200000)	/* range limits??? */
445fc10332bSAlex Deucher 			pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
446771fe6b9SJerome Glisse 		else
447fc10332bSAlex Deucher 			pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
448771fe6b9SJerome Glisse 	} else {
449fc10332bSAlex Deucher 		pll->flags |= RADEON_PLL_LEGACY;
450771fe6b9SJerome Glisse 
451771fe6b9SJerome Glisse 		if (mode->clock > 200000)	/* range limits??? */
452fc10332bSAlex Deucher 			pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
453771fe6b9SJerome Glisse 		else
454fc10332bSAlex Deucher 			pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
455771fe6b9SJerome Glisse 
456771fe6b9SJerome Glisse 	}
457771fe6b9SJerome Glisse 
458771fe6b9SJerome Glisse 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
459771fe6b9SJerome Glisse 		if (encoder->crtc == crtc) {
460771fe6b9SJerome Glisse 			if (!ASIC_IS_AVIVO(rdev)) {
461771fe6b9SJerome Glisse 				if (encoder->encoder_type !=
462771fe6b9SJerome Glisse 				    DRM_MODE_ENCODER_DAC)
463fc10332bSAlex Deucher 					pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
4642a008d0cSAlex Deucher 				if (encoder->encoder_type ==
4652a008d0cSAlex Deucher 					DRM_MODE_ENCODER_LVDS)
466fc10332bSAlex Deucher 					pll->flags |= RADEON_PLL_USE_REF_DIV;
467771fe6b9SJerome Glisse 			}
468771fe6b9SJerome Glisse 			radeon_encoder = to_radeon_encoder(encoder);
4693ce0a23dSJerome Glisse 			break;
470771fe6b9SJerome Glisse 		}
471771fe6b9SJerome Glisse 	}
472771fe6b9SJerome Glisse 
4732606c886SAlex Deucher 	/* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock
4742606c886SAlex Deucher 	 * accordingly based on the encoder/transmitter to work around
4752606c886SAlex Deucher 	 * special hw requirements.
4762606c886SAlex Deucher 	 */
4772606c886SAlex Deucher 	if (ASIC_IS_DCE3(rdev)) {
4782606c886SAlex Deucher 		ADJUST_DISPLAY_PLL_PS_ALLOCATION adjust_pll_args;
4792606c886SAlex Deucher 
4802606c886SAlex Deucher 		if (!encoder)
4812606c886SAlex Deucher 			return;
4822606c886SAlex Deucher 
4832606c886SAlex Deucher 		memset(&adjust_pll_args, 0, sizeof(adjust_pll_args));
4842606c886SAlex Deucher 		adjust_pll_args.usPixelClock = cpu_to_le16(mode->clock / 10);
4852606c886SAlex Deucher 		adjust_pll_args.ucTransmitterID = radeon_encoder->encoder_id;
4862606c886SAlex Deucher 		adjust_pll_args.ucEncodeMode = atombios_get_encoder_mode(encoder);
4872606c886SAlex Deucher 
4882606c886SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll);
4892606c886SAlex Deucher 		atom_execute_table(rdev->mode_info.atom_context,
4902606c886SAlex Deucher 				   index, (uint32_t *)&adjust_pll_args);
4912606c886SAlex Deucher 		adjusted_clock = le16_to_cpu(adjust_pll_args.usPixelClock) * 10;
492d56ef9c8SAlex Deucher 	} else {
493d56ef9c8SAlex Deucher 		/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
494d56ef9c8SAlex Deucher 		if (ASIC_IS_AVIVO(rdev) &&
495d56ef9c8SAlex Deucher 		    (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1))
496d56ef9c8SAlex Deucher 			adjusted_clock = mode->clock * 2;
497d56ef9c8SAlex Deucher 		else
4982606c886SAlex Deucher 			adjusted_clock = mode->clock;
499d56ef9c8SAlex Deucher 	}
5002606c886SAlex Deucher 
501b27b6375SAlex Deucher 	if (ASIC_IS_AVIVO(rdev)) {
502b27b6375SAlex Deucher 		if (radeon_new_pll)
503b27b6375SAlex Deucher 			radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock,
504b27b6375SAlex Deucher 						 &fb_div, &frac_fb_div,
505fc10332bSAlex Deucher 						 &ref_div, &post_div);
506b27b6375SAlex Deucher 		else
507b27b6375SAlex Deucher 			radeon_compute_pll(pll, adjusted_clock, &pll_clock,
508b27b6375SAlex Deucher 					   &fb_div, &frac_fb_div,
509fc10332bSAlex Deucher 					   &ref_div, &post_div);
510b27b6375SAlex Deucher 	} else
5112606c886SAlex Deucher 		radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div,
512fc10332bSAlex Deucher 				   &ref_div, &post_div);
513771fe6b9SJerome Glisse 
51439deb2d6SDave Airlie 	index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
515771fe6b9SJerome Glisse 	atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
516771fe6b9SJerome Glisse 			      &crev);
517771fe6b9SJerome Glisse 
518771fe6b9SJerome Glisse 	switch (frev) {
519771fe6b9SJerome Glisse 	case 1:
520771fe6b9SJerome Glisse 		switch (crev) {
521771fe6b9SJerome Glisse 		case 1:
522771fe6b9SJerome Glisse 			spc1_ptr = (PIXEL_CLOCK_PARAMETERS *) & args.sPCLKInput;
5232606c886SAlex Deucher 			spc1_ptr->usPixelClock = cpu_to_le16(mode->clock / 10);
524771fe6b9SJerome Glisse 			spc1_ptr->usRefDiv = cpu_to_le16(ref_div);
525771fe6b9SJerome Glisse 			spc1_ptr->usFbDiv = cpu_to_le16(fb_div);
526771fe6b9SJerome Glisse 			spc1_ptr->ucFracFbDiv = frac_fb_div;
527771fe6b9SJerome Glisse 			spc1_ptr->ucPostDiv = post_div;
528771fe6b9SJerome Glisse 			spc1_ptr->ucPpll =
529771fe6b9SJerome Glisse 			    radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
530771fe6b9SJerome Glisse 			spc1_ptr->ucCRTC = radeon_crtc->crtc_id;
531771fe6b9SJerome Glisse 			spc1_ptr->ucRefDivSrc = 1;
532771fe6b9SJerome Glisse 			break;
533771fe6b9SJerome Glisse 		case 2:
534771fe6b9SJerome Glisse 			spc2_ptr =
535771fe6b9SJerome Glisse 			    (PIXEL_CLOCK_PARAMETERS_V2 *) & args.sPCLKInput;
5362606c886SAlex Deucher 			spc2_ptr->usPixelClock = cpu_to_le16(mode->clock / 10);
537771fe6b9SJerome Glisse 			spc2_ptr->usRefDiv = cpu_to_le16(ref_div);
538771fe6b9SJerome Glisse 			spc2_ptr->usFbDiv = cpu_to_le16(fb_div);
539771fe6b9SJerome Glisse 			spc2_ptr->ucFracFbDiv = frac_fb_div;
540771fe6b9SJerome Glisse 			spc2_ptr->ucPostDiv = post_div;
541771fe6b9SJerome Glisse 			spc2_ptr->ucPpll =
542771fe6b9SJerome Glisse 			    radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
543771fe6b9SJerome Glisse 			spc2_ptr->ucCRTC = radeon_crtc->crtc_id;
544771fe6b9SJerome Glisse 			spc2_ptr->ucRefDivSrc = 1;
545771fe6b9SJerome Glisse 			break;
546771fe6b9SJerome Glisse 		case 3:
547771fe6b9SJerome Glisse 			if (!encoder)
548771fe6b9SJerome Glisse 				return;
549771fe6b9SJerome Glisse 			spc3_ptr =
550771fe6b9SJerome Glisse 			    (PIXEL_CLOCK_PARAMETERS_V3 *) & args.sPCLKInput;
5512606c886SAlex Deucher 			spc3_ptr->usPixelClock = cpu_to_le16(mode->clock / 10);
552771fe6b9SJerome Glisse 			spc3_ptr->usRefDiv = cpu_to_le16(ref_div);
553771fe6b9SJerome Glisse 			spc3_ptr->usFbDiv = cpu_to_le16(fb_div);
554771fe6b9SJerome Glisse 			spc3_ptr->ucFracFbDiv = frac_fb_div;
555771fe6b9SJerome Glisse 			spc3_ptr->ucPostDiv = post_div;
556771fe6b9SJerome Glisse 			spc3_ptr->ucPpll =
557771fe6b9SJerome Glisse 			    radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
558771fe6b9SJerome Glisse 			spc3_ptr->ucMiscInfo = (radeon_crtc->crtc_id << 2);
559771fe6b9SJerome Glisse 			spc3_ptr->ucTransmitterId = radeon_encoder->encoder_id;
560771fe6b9SJerome Glisse 			spc3_ptr->ucEncoderMode =
561771fe6b9SJerome Glisse 			    atombios_get_encoder_mode(encoder);
562771fe6b9SJerome Glisse 			break;
563771fe6b9SJerome Glisse 		default:
564771fe6b9SJerome Glisse 			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
565771fe6b9SJerome Glisse 			return;
566771fe6b9SJerome Glisse 		}
567771fe6b9SJerome Glisse 		break;
568771fe6b9SJerome Glisse 	default:
569771fe6b9SJerome Glisse 		DRM_ERROR("Unknown table version %d %d\n", frev, crev);
570771fe6b9SJerome Glisse 		return;
571771fe6b9SJerome Glisse 	}
572771fe6b9SJerome Glisse 
573771fe6b9SJerome Glisse 	printk("executing set pll\n");
574771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
575771fe6b9SJerome Glisse }
576771fe6b9SJerome Glisse 
57754f088a9SAlex Deucher static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y,
578771fe6b9SJerome Glisse 			       struct drm_framebuffer *old_fb)
579771fe6b9SJerome Glisse {
580771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
581771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
582771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
583771fe6b9SJerome Glisse 	struct radeon_framebuffer *radeon_fb;
584771fe6b9SJerome Glisse 	struct drm_gem_object *obj;
5854c788679SJerome Glisse 	struct radeon_bo *rbo;
586771fe6b9SJerome Glisse 	uint64_t fb_location;
587e024e110SDave Airlie 	uint32_t fb_format, fb_pitch_pixels, tiling_flags;
5884c788679SJerome Glisse 	int r;
589771fe6b9SJerome Glisse 
5902de3b484SJerome Glisse 	/* no fb bound */
5912de3b484SJerome Glisse 	if (!crtc->fb) {
5922de3b484SJerome Glisse 		DRM_DEBUG("No FB bound\n");
5932de3b484SJerome Glisse 		return 0;
5942de3b484SJerome Glisse 	}
595771fe6b9SJerome Glisse 
596771fe6b9SJerome Glisse 	radeon_fb = to_radeon_framebuffer(crtc->fb);
597771fe6b9SJerome Glisse 
5984c788679SJerome Glisse 	/* Pin framebuffer & get tilling informations */
599771fe6b9SJerome Glisse 	obj = radeon_fb->obj;
6004c788679SJerome Glisse 	rbo = obj->driver_private;
6014c788679SJerome Glisse 	r = radeon_bo_reserve(rbo, false);
6024c788679SJerome Glisse 	if (unlikely(r != 0))
6034c788679SJerome Glisse 		return r;
6044c788679SJerome Glisse 	r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_location);
6054c788679SJerome Glisse 	if (unlikely(r != 0)) {
6064c788679SJerome Glisse 		radeon_bo_unreserve(rbo);
607771fe6b9SJerome Glisse 		return -EINVAL;
608771fe6b9SJerome Glisse 	}
6094c788679SJerome Glisse 	radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
6104c788679SJerome Glisse 	radeon_bo_unreserve(rbo);
611771fe6b9SJerome Glisse 
612771fe6b9SJerome Glisse 	switch (crtc->fb->bits_per_pixel) {
61341456df2SDave Airlie 	case 8:
61441456df2SDave Airlie 		fb_format =
61541456df2SDave Airlie 		    AVIVO_D1GRPH_CONTROL_DEPTH_8BPP |
61641456df2SDave Airlie 		    AVIVO_D1GRPH_CONTROL_8BPP_INDEXED;
61741456df2SDave Airlie 		break;
618771fe6b9SJerome Glisse 	case 15:
619771fe6b9SJerome Glisse 		fb_format =
620771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
621771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555;
622771fe6b9SJerome Glisse 		break;
623771fe6b9SJerome Glisse 	case 16:
624771fe6b9SJerome Glisse 		fb_format =
625771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
626771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_16BPP_RGB565;
627771fe6b9SJerome Glisse 		break;
628771fe6b9SJerome Glisse 	case 24:
629771fe6b9SJerome Glisse 	case 32:
630771fe6b9SJerome Glisse 		fb_format =
631771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
632771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888;
633771fe6b9SJerome Glisse 		break;
634771fe6b9SJerome Glisse 	default:
635771fe6b9SJerome Glisse 		DRM_ERROR("Unsupported screen depth %d\n",
636771fe6b9SJerome Glisse 			  crtc->fb->bits_per_pixel);
637771fe6b9SJerome Glisse 		return -EINVAL;
638771fe6b9SJerome Glisse 	}
639771fe6b9SJerome Glisse 
640cf2f05d3SDave Airlie 	if (tiling_flags & RADEON_TILING_MACRO)
641cf2f05d3SDave Airlie 		fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE;
642cf2f05d3SDave Airlie 
643e024e110SDave Airlie 	if (tiling_flags & RADEON_TILING_MICRO)
644e024e110SDave Airlie 		fb_format |= AVIVO_D1GRPH_TILED;
645e024e110SDave Airlie 
646771fe6b9SJerome Glisse 	if (radeon_crtc->crtc_id == 0)
647771fe6b9SJerome Glisse 		WREG32(AVIVO_D1VGA_CONTROL, 0);
648771fe6b9SJerome Glisse 	else
649771fe6b9SJerome Glisse 		WREG32(AVIVO_D2VGA_CONTROL, 0);
650c290dadfSAlex Deucher 
651c290dadfSAlex Deucher 	if (rdev->family >= CHIP_RV770) {
652c290dadfSAlex Deucher 		if (radeon_crtc->crtc_id) {
653c290dadfSAlex Deucher 			WREG32(R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0);
654c290dadfSAlex Deucher 			WREG32(R700_D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0);
655c290dadfSAlex Deucher 		} else {
656c290dadfSAlex Deucher 			WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, 0);
657c290dadfSAlex Deucher 			WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, 0);
658c290dadfSAlex Deucher 		}
659c290dadfSAlex Deucher 	}
660771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
661771fe6b9SJerome Glisse 	       (u32) fb_location);
662771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS +
663771fe6b9SJerome Glisse 	       radeon_crtc->crtc_offset, (u32) fb_location);
664771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
665771fe6b9SJerome Glisse 
666771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
667771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
668771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0);
669771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0);
670771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
671771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
672771fe6b9SJerome Glisse 
673771fe6b9SJerome Glisse 	fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
674771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
675771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
676771fe6b9SJerome Glisse 
677771fe6b9SJerome Glisse 	WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
678771fe6b9SJerome Glisse 	       crtc->mode.vdisplay);
679771fe6b9SJerome Glisse 	x &= ~3;
680771fe6b9SJerome Glisse 	y &= ~1;
681771fe6b9SJerome Glisse 	WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset,
682771fe6b9SJerome Glisse 	       (x << 16) | y);
683771fe6b9SJerome Glisse 	WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
684771fe6b9SJerome Glisse 	       (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
685771fe6b9SJerome Glisse 
686771fe6b9SJerome Glisse 	if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
687771fe6b9SJerome Glisse 		WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
688771fe6b9SJerome Glisse 		       AVIVO_D1MODE_INTERLEAVE_EN);
689771fe6b9SJerome Glisse 	else
690771fe6b9SJerome Glisse 		WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
691771fe6b9SJerome Glisse 
692771fe6b9SJerome Glisse 	if (old_fb && old_fb != crtc->fb) {
693771fe6b9SJerome Glisse 		radeon_fb = to_radeon_framebuffer(old_fb);
6944c788679SJerome Glisse 		rbo = radeon_fb->obj->driver_private;
6954c788679SJerome Glisse 		r = radeon_bo_reserve(rbo, false);
6964c788679SJerome Glisse 		if (unlikely(r != 0))
6974c788679SJerome Glisse 			return r;
6984c788679SJerome Glisse 		radeon_bo_unpin(rbo);
6994c788679SJerome Glisse 		radeon_bo_unreserve(rbo);
700771fe6b9SJerome Glisse 	}
701f30f37deSMichel Dänzer 
702f30f37deSMichel Dänzer 	/* Bytes per pixel may have changed */
703f30f37deSMichel Dänzer 	radeon_bandwidth_update(rdev);
704f30f37deSMichel Dänzer 
705771fe6b9SJerome Glisse 	return 0;
706771fe6b9SJerome Glisse }
707771fe6b9SJerome Glisse 
70854f088a9SAlex Deucher int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
70954f088a9SAlex Deucher 			   struct drm_framebuffer *old_fb)
71054f088a9SAlex Deucher {
71154f088a9SAlex Deucher 	struct drm_device *dev = crtc->dev;
71254f088a9SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
71354f088a9SAlex Deucher 
71454f088a9SAlex Deucher 	if (ASIC_IS_AVIVO(rdev))
71554f088a9SAlex Deucher 		return avivo_crtc_set_base(crtc, x, y, old_fb);
71654f088a9SAlex Deucher 	else
71754f088a9SAlex Deucher 		return radeon_crtc_set_base(crtc, x, y, old_fb);
71854f088a9SAlex Deucher }
71954f088a9SAlex Deucher 
720615e0cb6SAlex Deucher /* properly set additional regs when using atombios */
721615e0cb6SAlex Deucher static void radeon_legacy_atom_fixup(struct drm_crtc *crtc)
722615e0cb6SAlex Deucher {
723615e0cb6SAlex Deucher 	struct drm_device *dev = crtc->dev;
724615e0cb6SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
725615e0cb6SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
726615e0cb6SAlex Deucher 	u32 disp_merge_cntl;
727615e0cb6SAlex Deucher 
728615e0cb6SAlex Deucher 	switch (radeon_crtc->crtc_id) {
729615e0cb6SAlex Deucher 	case 0:
730615e0cb6SAlex Deucher 		disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL);
731615e0cb6SAlex Deucher 		disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
732615e0cb6SAlex Deucher 		WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl);
733615e0cb6SAlex Deucher 		break;
734615e0cb6SAlex Deucher 	case 1:
735615e0cb6SAlex Deucher 		disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL);
736615e0cb6SAlex Deucher 		disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN;
737615e0cb6SAlex Deucher 		WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl);
738615e0cb6SAlex Deucher 		WREG32(RADEON_FP_H2_SYNC_STRT_WID,   RREG32(RADEON_CRTC2_H_SYNC_STRT_WID));
739615e0cb6SAlex Deucher 		WREG32(RADEON_FP_V2_SYNC_STRT_WID,   RREG32(RADEON_CRTC2_V_SYNC_STRT_WID));
740615e0cb6SAlex Deucher 		break;
741615e0cb6SAlex Deucher 	}
742615e0cb6SAlex Deucher }
743615e0cb6SAlex Deucher 
744771fe6b9SJerome Glisse int atombios_crtc_mode_set(struct drm_crtc *crtc,
745771fe6b9SJerome Glisse 			   struct drm_display_mode *mode,
746771fe6b9SJerome Glisse 			   struct drm_display_mode *adjusted_mode,
747771fe6b9SJerome Glisse 			   int x, int y, struct drm_framebuffer *old_fb)
748771fe6b9SJerome Glisse {
749771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
750771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
751771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
752771fe6b9SJerome Glisse 
753771fe6b9SJerome Glisse 	/* TODO color tiling */
754771fe6b9SJerome Glisse 
755ebbe1cb9SAlex Deucher 	atombios_set_ss(crtc, 0);
756771fe6b9SJerome Glisse 	atombios_crtc_set_pll(crtc, adjusted_mode);
757ebbe1cb9SAlex Deucher 	atombios_set_ss(crtc, 1);
7585a9bcaccSAlex Deucher 	atombios_crtc_set_timing(crtc, adjusted_mode);
759771fe6b9SJerome Glisse 
760771fe6b9SJerome Glisse 	if (ASIC_IS_AVIVO(rdev))
761771fe6b9SJerome Glisse 		atombios_crtc_set_base(crtc, x, y, old_fb);
762771fe6b9SJerome Glisse 	else {
7635a9bcaccSAlex Deucher 		if (radeon_crtc->crtc_id == 0)
7645a9bcaccSAlex Deucher 			atombios_set_crtc_dtd_timing(crtc, adjusted_mode);
76554f088a9SAlex Deucher 		atombios_crtc_set_base(crtc, x, y, old_fb);
766615e0cb6SAlex Deucher 		radeon_legacy_atom_fixup(crtc);
767771fe6b9SJerome Glisse 	}
768c93bb85bSJerome Glisse 	atombios_overscan_setup(crtc, mode, adjusted_mode);
769c93bb85bSJerome Glisse 	atombios_scaler_setup(crtc);
770771fe6b9SJerome Glisse 	return 0;
771771fe6b9SJerome Glisse }
772771fe6b9SJerome Glisse 
773771fe6b9SJerome Glisse static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
774771fe6b9SJerome Glisse 				     struct drm_display_mode *mode,
775771fe6b9SJerome Glisse 				     struct drm_display_mode *adjusted_mode)
776771fe6b9SJerome Glisse {
777c93bb85bSJerome Glisse 	if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode))
778c93bb85bSJerome Glisse 		return false;
779771fe6b9SJerome Glisse 	return true;
780771fe6b9SJerome Glisse }
781771fe6b9SJerome Glisse 
782771fe6b9SJerome Glisse static void atombios_crtc_prepare(struct drm_crtc *crtc)
783771fe6b9SJerome Glisse {
784771fe6b9SJerome Glisse 	atombios_lock_crtc(crtc, 1);
785a348c84dSAlex Deucher 	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
786771fe6b9SJerome Glisse }
787771fe6b9SJerome Glisse 
788771fe6b9SJerome Glisse static void atombios_crtc_commit(struct drm_crtc *crtc)
789771fe6b9SJerome Glisse {
790771fe6b9SJerome Glisse 	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
791771fe6b9SJerome Glisse 	atombios_lock_crtc(crtc, 0);
792771fe6b9SJerome Glisse }
793771fe6b9SJerome Glisse 
794771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
795771fe6b9SJerome Glisse 	.dpms = atombios_crtc_dpms,
796771fe6b9SJerome Glisse 	.mode_fixup = atombios_crtc_mode_fixup,
797771fe6b9SJerome Glisse 	.mode_set = atombios_crtc_mode_set,
798771fe6b9SJerome Glisse 	.mode_set_base = atombios_crtc_set_base,
799771fe6b9SJerome Glisse 	.prepare = atombios_crtc_prepare,
800771fe6b9SJerome Glisse 	.commit = atombios_crtc_commit,
801068143d3SDave Airlie 	.load_lut = radeon_crtc_load_lut,
802771fe6b9SJerome Glisse };
803771fe6b9SJerome Glisse 
804771fe6b9SJerome Glisse void radeon_atombios_init_crtc(struct drm_device *dev,
805771fe6b9SJerome Glisse 			       struct radeon_crtc *radeon_crtc)
806771fe6b9SJerome Glisse {
807771fe6b9SJerome Glisse 	if (radeon_crtc->crtc_id == 1)
808771fe6b9SJerome Glisse 		radeon_crtc->crtc_offset =
809771fe6b9SJerome Glisse 		    AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL;
810771fe6b9SJerome Glisse 	drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
811771fe6b9SJerome Glisse }
812