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 
34771fe6b9SJerome Glisse static void atombios_lock_crtc(struct drm_crtc *crtc, int lock)
35771fe6b9SJerome Glisse {
36771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
37771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
38771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
39771fe6b9SJerome Glisse 	int index =
40771fe6b9SJerome Glisse 	    GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
41771fe6b9SJerome Glisse 	ENABLE_CRTC_PS_ALLOCATION args;
42771fe6b9SJerome Glisse 
43771fe6b9SJerome Glisse 	memset(&args, 0, sizeof(args));
44771fe6b9SJerome Glisse 
45771fe6b9SJerome Glisse 	args.ucCRTC = radeon_crtc->crtc_id;
46771fe6b9SJerome Glisse 	args.ucEnable = lock;
47771fe6b9SJerome Glisse 
48771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
49771fe6b9SJerome Glisse }
50771fe6b9SJerome Glisse 
51771fe6b9SJerome Glisse static void atombios_enable_crtc(struct drm_crtc *crtc, int state)
52771fe6b9SJerome Glisse {
53771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
54771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
55771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
56771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
57771fe6b9SJerome Glisse 	ENABLE_CRTC_PS_ALLOCATION args;
58771fe6b9SJerome Glisse 
59771fe6b9SJerome Glisse 	memset(&args, 0, sizeof(args));
60771fe6b9SJerome Glisse 
61771fe6b9SJerome Glisse 	args.ucCRTC = radeon_crtc->crtc_id;
62771fe6b9SJerome Glisse 	args.ucEnable = state;
63771fe6b9SJerome Glisse 
64771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
65771fe6b9SJerome Glisse }
66771fe6b9SJerome Glisse 
67771fe6b9SJerome Glisse static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state)
68771fe6b9SJerome Glisse {
69771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
70771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
71771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
72771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq);
73771fe6b9SJerome Glisse 	ENABLE_CRTC_PS_ALLOCATION args;
74771fe6b9SJerome Glisse 
75771fe6b9SJerome Glisse 	memset(&args, 0, sizeof(args));
76771fe6b9SJerome Glisse 
77771fe6b9SJerome Glisse 	args.ucCRTC = radeon_crtc->crtc_id;
78771fe6b9SJerome Glisse 	args.ucEnable = state;
79771fe6b9SJerome Glisse 
80771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
81771fe6b9SJerome Glisse }
82771fe6b9SJerome Glisse 
83771fe6b9SJerome Glisse static void atombios_blank_crtc(struct drm_crtc *crtc, int state)
84771fe6b9SJerome Glisse {
85771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
86771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
87771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
88771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
89771fe6b9SJerome Glisse 	BLANK_CRTC_PS_ALLOCATION args;
90771fe6b9SJerome Glisse 
91771fe6b9SJerome Glisse 	memset(&args, 0, sizeof(args));
92771fe6b9SJerome Glisse 
93771fe6b9SJerome Glisse 	args.ucCRTC = radeon_crtc->crtc_id;
94771fe6b9SJerome Glisse 	args.ucBlanking = state;
95771fe6b9SJerome Glisse 
96771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
97771fe6b9SJerome Glisse }
98771fe6b9SJerome Glisse 
99771fe6b9SJerome Glisse void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
100771fe6b9SJerome Glisse {
101771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
102771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
103771fe6b9SJerome Glisse 
104771fe6b9SJerome Glisse 	switch (mode) {
105771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_ON:
106771fe6b9SJerome Glisse 		if (ASIC_IS_DCE3(rdev))
107771fe6b9SJerome Glisse 			atombios_enable_crtc_memreq(crtc, 1);
108771fe6b9SJerome Glisse 		atombios_enable_crtc(crtc, 1);
109771fe6b9SJerome Glisse 		atombios_blank_crtc(crtc, 0);
110771fe6b9SJerome Glisse 		break;
111771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_STANDBY:
112771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_SUSPEND:
113771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_OFF:
114771fe6b9SJerome Glisse 		atombios_blank_crtc(crtc, 1);
115771fe6b9SJerome Glisse 		atombios_enable_crtc(crtc, 0);
116771fe6b9SJerome Glisse 		if (ASIC_IS_DCE3(rdev))
117771fe6b9SJerome Glisse 			atombios_enable_crtc_memreq(crtc, 0);
118771fe6b9SJerome Glisse 		break;
119771fe6b9SJerome Glisse 	}
120771fe6b9SJerome Glisse 
121771fe6b9SJerome Glisse 	if (mode != DRM_MODE_DPMS_OFF) {
122771fe6b9SJerome Glisse 		radeon_crtc_load_lut(crtc);
123771fe6b9SJerome Glisse 	}
124771fe6b9SJerome Glisse }
125771fe6b9SJerome Glisse 
126771fe6b9SJerome Glisse static void
127771fe6b9SJerome Glisse atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
128771fe6b9SJerome Glisse 			     SET_CRTC_USING_DTD_TIMING_PARAMETERS * crtc_param)
129771fe6b9SJerome Glisse {
130771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
131771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
132771fe6b9SJerome Glisse 	SET_CRTC_USING_DTD_TIMING_PARAMETERS conv_param;
133771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
134771fe6b9SJerome Glisse 
135771fe6b9SJerome Glisse 	conv_param.usH_Size = cpu_to_le16(crtc_param->usH_Size);
136771fe6b9SJerome Glisse 	conv_param.usH_Blanking_Time =
137771fe6b9SJerome Glisse 	    cpu_to_le16(crtc_param->usH_Blanking_Time);
138771fe6b9SJerome Glisse 	conv_param.usV_Size = cpu_to_le16(crtc_param->usV_Size);
139771fe6b9SJerome Glisse 	conv_param.usV_Blanking_Time =
140771fe6b9SJerome Glisse 	    cpu_to_le16(crtc_param->usV_Blanking_Time);
141771fe6b9SJerome Glisse 	conv_param.usH_SyncOffset = cpu_to_le16(crtc_param->usH_SyncOffset);
142771fe6b9SJerome Glisse 	conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth);
143771fe6b9SJerome Glisse 	conv_param.usV_SyncOffset = cpu_to_le16(crtc_param->usV_SyncOffset);
144771fe6b9SJerome Glisse 	conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth);
145771fe6b9SJerome Glisse 	conv_param.susModeMiscInfo.usAccess =
146771fe6b9SJerome Glisse 	    cpu_to_le16(crtc_param->susModeMiscInfo.usAccess);
147771fe6b9SJerome Glisse 	conv_param.ucCRTC = crtc_param->ucCRTC;
148771fe6b9SJerome Glisse 
149771fe6b9SJerome Glisse 	printk("executing set crtc dtd timing\n");
150771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&conv_param);
151771fe6b9SJerome Glisse }
152771fe6b9SJerome Glisse 
153771fe6b9SJerome Glisse void atombios_crtc_set_timing(struct drm_crtc *crtc,
154771fe6b9SJerome Glisse 			      SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION *
155771fe6b9SJerome Glisse 			      crtc_param)
156771fe6b9SJerome Glisse {
157771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
158771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
159771fe6b9SJerome Glisse 	SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION conv_param;
160771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing);
161771fe6b9SJerome Glisse 
162771fe6b9SJerome Glisse 	conv_param.usH_Total = cpu_to_le16(crtc_param->usH_Total);
163771fe6b9SJerome Glisse 	conv_param.usH_Disp = cpu_to_le16(crtc_param->usH_Disp);
164771fe6b9SJerome Glisse 	conv_param.usH_SyncStart = cpu_to_le16(crtc_param->usH_SyncStart);
165771fe6b9SJerome Glisse 	conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth);
166771fe6b9SJerome Glisse 	conv_param.usV_Total = cpu_to_le16(crtc_param->usV_Total);
167771fe6b9SJerome Glisse 	conv_param.usV_Disp = cpu_to_le16(crtc_param->usV_Disp);
168771fe6b9SJerome Glisse 	conv_param.usV_SyncStart = cpu_to_le16(crtc_param->usV_SyncStart);
169771fe6b9SJerome Glisse 	conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth);
170771fe6b9SJerome Glisse 	conv_param.susModeMiscInfo.usAccess =
171771fe6b9SJerome Glisse 	    cpu_to_le16(crtc_param->susModeMiscInfo.usAccess);
172771fe6b9SJerome Glisse 	conv_param.ucCRTC = crtc_param->ucCRTC;
173771fe6b9SJerome Glisse 	conv_param.ucOverscanRight = crtc_param->ucOverscanRight;
174771fe6b9SJerome Glisse 	conv_param.ucOverscanLeft = crtc_param->ucOverscanLeft;
175771fe6b9SJerome Glisse 	conv_param.ucOverscanBottom = crtc_param->ucOverscanBottom;
176771fe6b9SJerome Glisse 	conv_param.ucOverscanTop = crtc_param->ucOverscanTop;
177771fe6b9SJerome Glisse 	conv_param.ucReserved = crtc_param->ucReserved;
178771fe6b9SJerome Glisse 
179771fe6b9SJerome Glisse 	printk("executing set crtc timing\n");
180771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&conv_param);
181771fe6b9SJerome Glisse }
182771fe6b9SJerome Glisse 
183771fe6b9SJerome Glisse void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
184771fe6b9SJerome Glisse {
185771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
186771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
187771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
188771fe6b9SJerome Glisse 	struct drm_encoder *encoder = NULL;
189771fe6b9SJerome Glisse 	struct radeon_encoder *radeon_encoder = NULL;
190771fe6b9SJerome Glisse 	uint8_t frev, crev;
191771fe6b9SJerome Glisse 	int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
192771fe6b9SJerome Glisse 	SET_PIXEL_CLOCK_PS_ALLOCATION args;
193771fe6b9SJerome Glisse 	PIXEL_CLOCK_PARAMETERS *spc1_ptr;
194771fe6b9SJerome Glisse 	PIXEL_CLOCK_PARAMETERS_V2 *spc2_ptr;
195771fe6b9SJerome Glisse 	PIXEL_CLOCK_PARAMETERS_V3 *spc3_ptr;
196771fe6b9SJerome Glisse 	uint32_t sclock = mode->clock;
197771fe6b9SJerome Glisse 	uint32_t ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
198771fe6b9SJerome Glisse 	struct radeon_pll *pll;
199771fe6b9SJerome Glisse 	int pll_flags = 0;
200771fe6b9SJerome Glisse 
201771fe6b9SJerome Glisse 	memset(&args, 0, sizeof(args));
202771fe6b9SJerome Glisse 
203771fe6b9SJerome Glisse 	if (ASIC_IS_AVIVO(rdev)) {
204771fe6b9SJerome Glisse 		uint32_t ss_cntl;
205771fe6b9SJerome Glisse 
206eb1300bcSAlex Deucher 		if ((rdev->family == CHIP_RS600) ||
207eb1300bcSAlex Deucher 		    (rdev->family == CHIP_RS690) ||
208eb1300bcSAlex Deucher 		    (rdev->family == CHIP_RS740))
209eb1300bcSAlex Deucher 			pll_flags |= (RADEON_PLL_USE_FRAC_FB_DIV |
210eb1300bcSAlex Deucher 				      RADEON_PLL_PREFER_CLOSEST_LOWER);
211eb1300bcSAlex Deucher 
212771fe6b9SJerome Glisse 		if (ASIC_IS_DCE32(rdev) && mode->clock > 200000)	/* range limits??? */
213771fe6b9SJerome Glisse 			pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
214771fe6b9SJerome Glisse 		else
215771fe6b9SJerome Glisse 			pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
216771fe6b9SJerome Glisse 
217771fe6b9SJerome Glisse 		/* disable spread spectrum clocking for now -- thanks Hedy Lamarr */
218771fe6b9SJerome Glisse 		if (radeon_crtc->crtc_id == 0) {
219771fe6b9SJerome Glisse 			ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL);
220771fe6b9SJerome Glisse 			WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl & ~1);
221771fe6b9SJerome Glisse 		} else {
222771fe6b9SJerome Glisse 			ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL);
223771fe6b9SJerome Glisse 			WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl & ~1);
224771fe6b9SJerome Glisse 		}
225771fe6b9SJerome Glisse 	} else {
226771fe6b9SJerome Glisse 		pll_flags |= RADEON_PLL_LEGACY;
227771fe6b9SJerome Glisse 
228771fe6b9SJerome Glisse 		if (mode->clock > 200000)	/* range limits??? */
229771fe6b9SJerome Glisse 			pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
230771fe6b9SJerome Glisse 		else
231771fe6b9SJerome Glisse 			pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
232771fe6b9SJerome Glisse 
233771fe6b9SJerome Glisse 	}
234771fe6b9SJerome Glisse 
235771fe6b9SJerome Glisse 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
236771fe6b9SJerome Glisse 		if (encoder->crtc == crtc) {
237771fe6b9SJerome Glisse 			if (!ASIC_IS_AVIVO(rdev)) {
238771fe6b9SJerome Glisse 				if (encoder->encoder_type !=
239771fe6b9SJerome Glisse 				    DRM_MODE_ENCODER_DAC)
240771fe6b9SJerome Glisse 					pll_flags |= RADEON_PLL_NO_ODD_POST_DIV;
241771fe6b9SJerome Glisse 				if (!ASIC_IS_AVIVO(rdev)
242771fe6b9SJerome Glisse 				    && (encoder->encoder_type ==
243771fe6b9SJerome Glisse 					DRM_MODE_ENCODER_LVDS))
244771fe6b9SJerome Glisse 					pll_flags |= RADEON_PLL_USE_REF_DIV;
245771fe6b9SJerome Glisse 			}
246771fe6b9SJerome Glisse 			radeon_encoder = to_radeon_encoder(encoder);
247771fe6b9SJerome Glisse 		}
248771fe6b9SJerome Glisse 	}
249771fe6b9SJerome Glisse 
250771fe6b9SJerome Glisse 	if (radeon_crtc->crtc_id == 0)
251771fe6b9SJerome Glisse 		pll = &rdev->clock.p1pll;
252771fe6b9SJerome Glisse 	else
253771fe6b9SJerome Glisse 		pll = &rdev->clock.p2pll;
254771fe6b9SJerome Glisse 
255771fe6b9SJerome Glisse 	radeon_compute_pll(pll, mode->clock, &sclock, &fb_div, &frac_fb_div,
256771fe6b9SJerome Glisse 			   &ref_div, &post_div, pll_flags);
257771fe6b9SJerome Glisse 
258771fe6b9SJerome Glisse 	atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
259771fe6b9SJerome Glisse 			      &crev);
260771fe6b9SJerome Glisse 
261771fe6b9SJerome Glisse 	switch (frev) {
262771fe6b9SJerome Glisse 	case 1:
263771fe6b9SJerome Glisse 		switch (crev) {
264771fe6b9SJerome Glisse 		case 1:
265771fe6b9SJerome Glisse 			spc1_ptr = (PIXEL_CLOCK_PARAMETERS *) & args.sPCLKInput;
266771fe6b9SJerome Glisse 			spc1_ptr->usPixelClock = cpu_to_le16(sclock);
267771fe6b9SJerome Glisse 			spc1_ptr->usRefDiv = cpu_to_le16(ref_div);
268771fe6b9SJerome Glisse 			spc1_ptr->usFbDiv = cpu_to_le16(fb_div);
269771fe6b9SJerome Glisse 			spc1_ptr->ucFracFbDiv = frac_fb_div;
270771fe6b9SJerome Glisse 			spc1_ptr->ucPostDiv = post_div;
271771fe6b9SJerome Glisse 			spc1_ptr->ucPpll =
272771fe6b9SJerome Glisse 			    radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
273771fe6b9SJerome Glisse 			spc1_ptr->ucCRTC = radeon_crtc->crtc_id;
274771fe6b9SJerome Glisse 			spc1_ptr->ucRefDivSrc = 1;
275771fe6b9SJerome Glisse 			break;
276771fe6b9SJerome Glisse 		case 2:
277771fe6b9SJerome Glisse 			spc2_ptr =
278771fe6b9SJerome Glisse 			    (PIXEL_CLOCK_PARAMETERS_V2 *) & args.sPCLKInput;
279771fe6b9SJerome Glisse 			spc2_ptr->usPixelClock = cpu_to_le16(sclock);
280771fe6b9SJerome Glisse 			spc2_ptr->usRefDiv = cpu_to_le16(ref_div);
281771fe6b9SJerome Glisse 			spc2_ptr->usFbDiv = cpu_to_le16(fb_div);
282771fe6b9SJerome Glisse 			spc2_ptr->ucFracFbDiv = frac_fb_div;
283771fe6b9SJerome Glisse 			spc2_ptr->ucPostDiv = post_div;
284771fe6b9SJerome Glisse 			spc2_ptr->ucPpll =
285771fe6b9SJerome Glisse 			    radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
286771fe6b9SJerome Glisse 			spc2_ptr->ucCRTC = radeon_crtc->crtc_id;
287771fe6b9SJerome Glisse 			spc2_ptr->ucRefDivSrc = 1;
288771fe6b9SJerome Glisse 			break;
289771fe6b9SJerome Glisse 		case 3:
290771fe6b9SJerome Glisse 			if (!encoder)
291771fe6b9SJerome Glisse 				return;
292771fe6b9SJerome Glisse 			spc3_ptr =
293771fe6b9SJerome Glisse 			    (PIXEL_CLOCK_PARAMETERS_V3 *) & args.sPCLKInput;
294771fe6b9SJerome Glisse 			spc3_ptr->usPixelClock = cpu_to_le16(sclock);
295771fe6b9SJerome Glisse 			spc3_ptr->usRefDiv = cpu_to_le16(ref_div);
296771fe6b9SJerome Glisse 			spc3_ptr->usFbDiv = cpu_to_le16(fb_div);
297771fe6b9SJerome Glisse 			spc3_ptr->ucFracFbDiv = frac_fb_div;
298771fe6b9SJerome Glisse 			spc3_ptr->ucPostDiv = post_div;
299771fe6b9SJerome Glisse 			spc3_ptr->ucPpll =
300771fe6b9SJerome Glisse 			    radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
301771fe6b9SJerome Glisse 			spc3_ptr->ucMiscInfo = (radeon_crtc->crtc_id << 2);
302771fe6b9SJerome Glisse 			spc3_ptr->ucTransmitterId = radeon_encoder->encoder_id;
303771fe6b9SJerome Glisse 			spc3_ptr->ucEncoderMode =
304771fe6b9SJerome Glisse 			    atombios_get_encoder_mode(encoder);
305771fe6b9SJerome Glisse 			break;
306771fe6b9SJerome Glisse 		default:
307771fe6b9SJerome Glisse 			DRM_ERROR("Unknown table version %d %d\n", frev, crev);
308771fe6b9SJerome Glisse 			return;
309771fe6b9SJerome Glisse 		}
310771fe6b9SJerome Glisse 		break;
311771fe6b9SJerome Glisse 	default:
312771fe6b9SJerome Glisse 		DRM_ERROR("Unknown table version %d %d\n", frev, crev);
313771fe6b9SJerome Glisse 		return;
314771fe6b9SJerome Glisse 	}
315771fe6b9SJerome Glisse 
316771fe6b9SJerome Glisse 	printk("executing set pll\n");
317771fe6b9SJerome Glisse 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
318771fe6b9SJerome Glisse }
319771fe6b9SJerome Glisse 
320771fe6b9SJerome Glisse int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
321771fe6b9SJerome Glisse 			   struct drm_framebuffer *old_fb)
322771fe6b9SJerome Glisse {
323771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
324771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
325771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
326771fe6b9SJerome Glisse 	struct radeon_framebuffer *radeon_fb;
327771fe6b9SJerome Glisse 	struct drm_gem_object *obj;
328771fe6b9SJerome Glisse 	struct drm_radeon_gem_object *obj_priv;
329771fe6b9SJerome Glisse 	uint64_t fb_location;
330e024e110SDave Airlie 	uint32_t fb_format, fb_pitch_pixels, tiling_flags;
331771fe6b9SJerome Glisse 
332771fe6b9SJerome Glisse 	if (!crtc->fb)
333771fe6b9SJerome Glisse 		return -EINVAL;
334771fe6b9SJerome Glisse 
335771fe6b9SJerome Glisse 	radeon_fb = to_radeon_framebuffer(crtc->fb);
336771fe6b9SJerome Glisse 
337771fe6b9SJerome Glisse 	obj = radeon_fb->obj;
338771fe6b9SJerome Glisse 	obj_priv = obj->driver_private;
339771fe6b9SJerome Glisse 
340771fe6b9SJerome Glisse 	if (radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &fb_location)) {
341771fe6b9SJerome Glisse 		return -EINVAL;
342771fe6b9SJerome Glisse 	}
343771fe6b9SJerome Glisse 
344771fe6b9SJerome Glisse 	switch (crtc->fb->bits_per_pixel) {
345771fe6b9SJerome Glisse 	case 15:
346771fe6b9SJerome Glisse 		fb_format =
347771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
348771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555;
349771fe6b9SJerome Glisse 		break;
350771fe6b9SJerome Glisse 	case 16:
351771fe6b9SJerome Glisse 		fb_format =
352771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
353771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_16BPP_RGB565;
354771fe6b9SJerome Glisse 		break;
355771fe6b9SJerome Glisse 	case 24:
356771fe6b9SJerome Glisse 	case 32:
357771fe6b9SJerome Glisse 		fb_format =
358771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
359771fe6b9SJerome Glisse 		    AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888;
360771fe6b9SJerome Glisse 		break;
361771fe6b9SJerome Glisse 	default:
362771fe6b9SJerome Glisse 		DRM_ERROR("Unsupported screen depth %d\n",
363771fe6b9SJerome Glisse 			  crtc->fb->bits_per_pixel);
364771fe6b9SJerome Glisse 		return -EINVAL;
365771fe6b9SJerome Glisse 	}
366771fe6b9SJerome Glisse 
367e024e110SDave Airlie 	radeon_object_get_tiling_flags(obj->driver_private,
368e024e110SDave Airlie 				       &tiling_flags, NULL);
369e024e110SDave Airlie 	if (tiling_flags & RADEON_TILING_MACRO)
370e024e110SDave Airlie 		fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE;
371e024e110SDave Airlie 
372e024e110SDave Airlie 	if (tiling_flags & RADEON_TILING_MICRO)
373e024e110SDave Airlie 		fb_format |= AVIVO_D1GRPH_TILED;
374e024e110SDave Airlie 
375771fe6b9SJerome Glisse 	if (radeon_crtc->crtc_id == 0)
376771fe6b9SJerome Glisse 		WREG32(AVIVO_D1VGA_CONTROL, 0);
377771fe6b9SJerome Glisse 	else
378771fe6b9SJerome Glisse 		WREG32(AVIVO_D2VGA_CONTROL, 0);
379771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
380771fe6b9SJerome Glisse 	       (u32) fb_location);
381771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS +
382771fe6b9SJerome Glisse 	       radeon_crtc->crtc_offset, (u32) fb_location);
383771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
384771fe6b9SJerome Glisse 
385771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
386771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
387771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0);
388771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0);
389771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
390771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
391771fe6b9SJerome Glisse 
392771fe6b9SJerome Glisse 	fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
393771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
394771fe6b9SJerome Glisse 	WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
395771fe6b9SJerome Glisse 
396771fe6b9SJerome Glisse 	WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
397771fe6b9SJerome Glisse 	       crtc->mode.vdisplay);
398771fe6b9SJerome Glisse 	x &= ~3;
399771fe6b9SJerome Glisse 	y &= ~1;
400771fe6b9SJerome Glisse 	WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset,
401771fe6b9SJerome Glisse 	       (x << 16) | y);
402771fe6b9SJerome Glisse 	WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
403771fe6b9SJerome Glisse 	       (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
404771fe6b9SJerome Glisse 
405771fe6b9SJerome Glisse 	if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
406771fe6b9SJerome Glisse 		WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
407771fe6b9SJerome Glisse 		       AVIVO_D1MODE_INTERLEAVE_EN);
408771fe6b9SJerome Glisse 	else
409771fe6b9SJerome Glisse 		WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
410771fe6b9SJerome Glisse 
411771fe6b9SJerome Glisse 	if (old_fb && old_fb != crtc->fb) {
412771fe6b9SJerome Glisse 		radeon_fb = to_radeon_framebuffer(old_fb);
413771fe6b9SJerome Glisse 		radeon_gem_object_unpin(radeon_fb->obj);
414771fe6b9SJerome Glisse 	}
415771fe6b9SJerome Glisse 	return 0;
416771fe6b9SJerome Glisse }
417771fe6b9SJerome Glisse 
418771fe6b9SJerome Glisse int atombios_crtc_mode_set(struct drm_crtc *crtc,
419771fe6b9SJerome Glisse 			   struct drm_display_mode *mode,
420771fe6b9SJerome Glisse 			   struct drm_display_mode *adjusted_mode,
421771fe6b9SJerome Glisse 			   int x, int y, struct drm_framebuffer *old_fb)
422771fe6b9SJerome Glisse {
423771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
424771fe6b9SJerome Glisse 	struct drm_device *dev = crtc->dev;
425771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
426771fe6b9SJerome Glisse 	struct drm_encoder *encoder;
427771fe6b9SJerome Glisse 	SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing;
428771fe6b9SJerome Glisse 
429771fe6b9SJerome Glisse 	/* TODO color tiling */
430771fe6b9SJerome Glisse 	memset(&crtc_timing, 0, sizeof(crtc_timing));
431771fe6b9SJerome Glisse 
432771fe6b9SJerome Glisse 	/* TODO tv */
433771fe6b9SJerome Glisse 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
434771fe6b9SJerome Glisse 
435771fe6b9SJerome Glisse 	}
436771fe6b9SJerome Glisse 
437771fe6b9SJerome Glisse 	crtc_timing.ucCRTC = radeon_crtc->crtc_id;
438771fe6b9SJerome Glisse 	crtc_timing.usH_Total = adjusted_mode->crtc_htotal;
439771fe6b9SJerome Glisse 	crtc_timing.usH_Disp = adjusted_mode->crtc_hdisplay;
440771fe6b9SJerome Glisse 	crtc_timing.usH_SyncStart = adjusted_mode->crtc_hsync_start;
441771fe6b9SJerome Glisse 	crtc_timing.usH_SyncWidth =
442771fe6b9SJerome Glisse 	    adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
443771fe6b9SJerome Glisse 
444771fe6b9SJerome Glisse 	crtc_timing.usV_Total = adjusted_mode->crtc_vtotal;
445771fe6b9SJerome Glisse 	crtc_timing.usV_Disp = adjusted_mode->crtc_vdisplay;
446771fe6b9SJerome Glisse 	crtc_timing.usV_SyncStart = adjusted_mode->crtc_vsync_start;
447771fe6b9SJerome Glisse 	crtc_timing.usV_SyncWidth =
448771fe6b9SJerome Glisse 	    adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
449771fe6b9SJerome Glisse 
450771fe6b9SJerome Glisse 	if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
451771fe6b9SJerome Glisse 		crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY;
452771fe6b9SJerome Glisse 
453771fe6b9SJerome Glisse 	if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
454771fe6b9SJerome Glisse 		crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY;
455771fe6b9SJerome Glisse 
456771fe6b9SJerome Glisse 	if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC)
457771fe6b9SJerome Glisse 		crtc_timing.susModeMiscInfo.usAccess |= ATOM_COMPOSITESYNC;
458771fe6b9SJerome Glisse 
459771fe6b9SJerome Glisse 	if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
460771fe6b9SJerome Glisse 		crtc_timing.susModeMiscInfo.usAccess |= ATOM_INTERLACE;
461771fe6b9SJerome Glisse 
462771fe6b9SJerome Glisse 	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
463771fe6b9SJerome Glisse 		crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE;
464771fe6b9SJerome Glisse 
465771fe6b9SJerome Glisse 	atombios_crtc_set_pll(crtc, adjusted_mode);
466771fe6b9SJerome Glisse 	atombios_crtc_set_timing(crtc, &crtc_timing);
467771fe6b9SJerome Glisse 
468771fe6b9SJerome Glisse 	if (ASIC_IS_AVIVO(rdev))
469771fe6b9SJerome Glisse 		atombios_crtc_set_base(crtc, x, y, old_fb);
470771fe6b9SJerome Glisse 	else {
471771fe6b9SJerome Glisse 		if (radeon_crtc->crtc_id == 0) {
472771fe6b9SJerome Glisse 			SET_CRTC_USING_DTD_TIMING_PARAMETERS crtc_dtd_timing;
473771fe6b9SJerome Glisse 			memset(&crtc_dtd_timing, 0, sizeof(crtc_dtd_timing));
474771fe6b9SJerome Glisse 
475771fe6b9SJerome Glisse 			/* setup FP shadow regs on R4xx */
476771fe6b9SJerome Glisse 			crtc_dtd_timing.ucCRTC = radeon_crtc->crtc_id;
477771fe6b9SJerome Glisse 			crtc_dtd_timing.usH_Size = adjusted_mode->crtc_hdisplay;
478771fe6b9SJerome Glisse 			crtc_dtd_timing.usV_Size = adjusted_mode->crtc_vdisplay;
479771fe6b9SJerome Glisse 			crtc_dtd_timing.usH_Blanking_Time =
480771fe6b9SJerome Glisse 			    adjusted_mode->crtc_hblank_end -
481771fe6b9SJerome Glisse 			    adjusted_mode->crtc_hdisplay;
482771fe6b9SJerome Glisse 			crtc_dtd_timing.usV_Blanking_Time =
483771fe6b9SJerome Glisse 			    adjusted_mode->crtc_vblank_end -
484771fe6b9SJerome Glisse 			    adjusted_mode->crtc_vdisplay;
485771fe6b9SJerome Glisse 			crtc_dtd_timing.usH_SyncOffset =
486771fe6b9SJerome Glisse 			    adjusted_mode->crtc_hsync_start -
487771fe6b9SJerome Glisse 			    adjusted_mode->crtc_hdisplay;
488771fe6b9SJerome Glisse 			crtc_dtd_timing.usV_SyncOffset =
489771fe6b9SJerome Glisse 			    adjusted_mode->crtc_vsync_start -
490771fe6b9SJerome Glisse 			    adjusted_mode->crtc_vdisplay;
491771fe6b9SJerome Glisse 			crtc_dtd_timing.usH_SyncWidth =
492771fe6b9SJerome Glisse 			    adjusted_mode->crtc_hsync_end -
493771fe6b9SJerome Glisse 			    adjusted_mode->crtc_hsync_start;
494771fe6b9SJerome Glisse 			crtc_dtd_timing.usV_SyncWidth =
495771fe6b9SJerome Glisse 			    adjusted_mode->crtc_vsync_end -
496771fe6b9SJerome Glisse 			    adjusted_mode->crtc_vsync_start;
497771fe6b9SJerome Glisse 			/* crtc_dtd_timing.ucH_Border = adjusted_mode->crtc_hborder; */
498771fe6b9SJerome Glisse 			/* crtc_dtd_timing.ucV_Border = adjusted_mode->crtc_vborder; */
499771fe6b9SJerome Glisse 
500771fe6b9SJerome Glisse 			if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
501771fe6b9SJerome Glisse 				crtc_dtd_timing.susModeMiscInfo.usAccess |=
502771fe6b9SJerome Glisse 				    ATOM_VSYNC_POLARITY;
503771fe6b9SJerome Glisse 
504771fe6b9SJerome Glisse 			if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
505771fe6b9SJerome Glisse 				crtc_dtd_timing.susModeMiscInfo.usAccess |=
506771fe6b9SJerome Glisse 				    ATOM_HSYNC_POLARITY;
507771fe6b9SJerome Glisse 
508771fe6b9SJerome Glisse 			if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC)
509771fe6b9SJerome Glisse 				crtc_dtd_timing.susModeMiscInfo.usAccess |=
510771fe6b9SJerome Glisse 				    ATOM_COMPOSITESYNC;
511771fe6b9SJerome Glisse 
512771fe6b9SJerome Glisse 			if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
513771fe6b9SJerome Glisse 				crtc_dtd_timing.susModeMiscInfo.usAccess |=
514771fe6b9SJerome Glisse 				    ATOM_INTERLACE;
515771fe6b9SJerome Glisse 
516771fe6b9SJerome Glisse 			if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
517771fe6b9SJerome Glisse 				crtc_dtd_timing.susModeMiscInfo.usAccess |=
518771fe6b9SJerome Glisse 				    ATOM_DOUBLE_CLOCK_MODE;
519771fe6b9SJerome Glisse 
520771fe6b9SJerome Glisse 			atombios_set_crtc_dtd_timing(crtc, &crtc_dtd_timing);
521771fe6b9SJerome Glisse 		}
522771fe6b9SJerome Glisse 		radeon_crtc_set_base(crtc, x, y, old_fb);
523771fe6b9SJerome Glisse 		radeon_legacy_atom_set_surface(crtc);
524771fe6b9SJerome Glisse 	}
525771fe6b9SJerome Glisse 	return 0;
526771fe6b9SJerome Glisse }
527771fe6b9SJerome Glisse 
528771fe6b9SJerome Glisse static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
529771fe6b9SJerome Glisse 				     struct drm_display_mode *mode,
530771fe6b9SJerome Glisse 				     struct drm_display_mode *adjusted_mode)
531771fe6b9SJerome Glisse {
532771fe6b9SJerome Glisse 	return true;
533771fe6b9SJerome Glisse }
534771fe6b9SJerome Glisse 
535771fe6b9SJerome Glisse static void atombios_crtc_prepare(struct drm_crtc *crtc)
536771fe6b9SJerome Glisse {
537771fe6b9SJerome Glisse 	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
538771fe6b9SJerome Glisse 	atombios_lock_crtc(crtc, 1);
539771fe6b9SJerome Glisse }
540771fe6b9SJerome Glisse 
541771fe6b9SJerome Glisse static void atombios_crtc_commit(struct drm_crtc *crtc)
542771fe6b9SJerome Glisse {
543771fe6b9SJerome Glisse 	atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
544771fe6b9SJerome Glisse 	atombios_lock_crtc(crtc, 0);
545771fe6b9SJerome Glisse }
546771fe6b9SJerome Glisse 
547771fe6b9SJerome Glisse static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
548771fe6b9SJerome Glisse 	.dpms = atombios_crtc_dpms,
549771fe6b9SJerome Glisse 	.mode_fixup = atombios_crtc_mode_fixup,
550771fe6b9SJerome Glisse 	.mode_set = atombios_crtc_mode_set,
551771fe6b9SJerome Glisse 	.mode_set_base = atombios_crtc_set_base,
552771fe6b9SJerome Glisse 	.prepare = atombios_crtc_prepare,
553771fe6b9SJerome Glisse 	.commit = atombios_crtc_commit,
554771fe6b9SJerome Glisse };
555771fe6b9SJerome Glisse 
556771fe6b9SJerome Glisse void radeon_atombios_init_crtc(struct drm_device *dev,
557771fe6b9SJerome Glisse 			       struct radeon_crtc *radeon_crtc)
558771fe6b9SJerome Glisse {
559771fe6b9SJerome Glisse 	if (radeon_crtc->crtc_id == 1)
560771fe6b9SJerome Glisse 		radeon_crtc->crtc_offset =
561771fe6b9SJerome Glisse 		    AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL;
562771fe6b9SJerome Glisse 	drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
563771fe6b9SJerome Glisse }
564771fe6b9SJerome Glisse 
565771fe6b9SJerome Glisse void radeon_init_disp_bw_avivo(struct drm_device *dev,
566771fe6b9SJerome Glisse 			       struct drm_display_mode *mode1,
567771fe6b9SJerome Glisse 			       uint32_t pixel_bytes1,
568771fe6b9SJerome Glisse 			       struct drm_display_mode *mode2,
569771fe6b9SJerome Glisse 			       uint32_t pixel_bytes2)
570771fe6b9SJerome Glisse {
571771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
572771fe6b9SJerome Glisse 	fixed20_12 min_mem_eff;
573771fe6b9SJerome Glisse 	fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff;
574771fe6b9SJerome Glisse 	fixed20_12 sclk_ff, mclk_ff;
575771fe6b9SJerome Glisse 	uint32_t dc_lb_memory_split, temp;
576771fe6b9SJerome Glisse 
577771fe6b9SJerome Glisse 	min_mem_eff.full = rfixed_const_8(0);
578771fe6b9SJerome Glisse 	if (rdev->disp_priority == 2) {
579771fe6b9SJerome Glisse 		uint32_t mc_init_misc_lat_timer = 0;
580771fe6b9SJerome Glisse 		if (rdev->family == CHIP_RV515)
581771fe6b9SJerome Glisse 			mc_init_misc_lat_timer =
582771fe6b9SJerome Glisse 			    RREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER);
583771fe6b9SJerome Glisse 		else if (rdev->family == CHIP_RS690)
584771fe6b9SJerome Glisse 			mc_init_misc_lat_timer =
585771fe6b9SJerome Glisse 			    RREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER);
586771fe6b9SJerome Glisse 
587771fe6b9SJerome Glisse 		mc_init_misc_lat_timer &=
588771fe6b9SJerome Glisse 		    ~(R300_MC_DISP1R_INIT_LAT_MASK <<
589771fe6b9SJerome Glisse 		      R300_MC_DISP1R_INIT_LAT_SHIFT);
590771fe6b9SJerome Glisse 		mc_init_misc_lat_timer &=
591771fe6b9SJerome Glisse 		    ~(R300_MC_DISP0R_INIT_LAT_MASK <<
592771fe6b9SJerome Glisse 		      R300_MC_DISP0R_INIT_LAT_SHIFT);
593771fe6b9SJerome Glisse 
594771fe6b9SJerome Glisse 		if (mode2)
595771fe6b9SJerome Glisse 			mc_init_misc_lat_timer |=
596771fe6b9SJerome Glisse 			    (1 << R300_MC_DISP1R_INIT_LAT_SHIFT);
597771fe6b9SJerome Glisse 		if (mode1)
598771fe6b9SJerome Glisse 			mc_init_misc_lat_timer |=
599771fe6b9SJerome Glisse 			    (1 << R300_MC_DISP0R_INIT_LAT_SHIFT);
600771fe6b9SJerome Glisse 
601771fe6b9SJerome Glisse 		if (rdev->family == CHIP_RV515)
602771fe6b9SJerome Glisse 			WREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER,
603771fe6b9SJerome Glisse 				  mc_init_misc_lat_timer);
604771fe6b9SJerome Glisse 		else if (rdev->family == CHIP_RS690)
605771fe6b9SJerome Glisse 			WREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER,
606771fe6b9SJerome Glisse 				  mc_init_misc_lat_timer);
607771fe6b9SJerome Glisse 	}
608771fe6b9SJerome Glisse 
609771fe6b9SJerome Glisse 	/*
610771fe6b9SJerome Glisse 	 * determine is there is enough bw for current mode
611771fe6b9SJerome Glisse 	 */
612771fe6b9SJerome Glisse 	temp_ff.full = rfixed_const(100);
613771fe6b9SJerome Glisse 	mclk_ff.full = rfixed_const(rdev->clock.default_mclk);
614771fe6b9SJerome Glisse 	mclk_ff.full = rfixed_div(mclk_ff, temp_ff);
615771fe6b9SJerome Glisse 	sclk_ff.full = rfixed_const(rdev->clock.default_sclk);
616771fe6b9SJerome Glisse 	sclk_ff.full = rfixed_div(sclk_ff, temp_ff);
617771fe6b9SJerome Glisse 
618771fe6b9SJerome Glisse 	temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1);
619771fe6b9SJerome Glisse 	temp_ff.full = rfixed_const(temp);
620771fe6b9SJerome Glisse 	mem_bw.full = rfixed_mul(mclk_ff, temp_ff);
621771fe6b9SJerome Glisse 	mem_bw.full = rfixed_mul(mem_bw, min_mem_eff);
622771fe6b9SJerome Glisse 
623771fe6b9SJerome Glisse 	pix_clk.full = 0;
624771fe6b9SJerome Glisse 	pix_clk2.full = 0;
625771fe6b9SJerome Glisse 	peak_disp_bw.full = 0;
626771fe6b9SJerome Glisse 	if (mode1) {
627771fe6b9SJerome Glisse 		temp_ff.full = rfixed_const(1000);
628771fe6b9SJerome Glisse 		pix_clk.full = rfixed_const(mode1->clock);	/* convert to fixed point */
629771fe6b9SJerome Glisse 		pix_clk.full = rfixed_div(pix_clk, temp_ff);
630771fe6b9SJerome Glisse 		temp_ff.full = rfixed_const(pixel_bytes1);
631771fe6b9SJerome Glisse 		peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff);
632771fe6b9SJerome Glisse 	}
633771fe6b9SJerome Glisse 	if (mode2) {
634771fe6b9SJerome Glisse 		temp_ff.full = rfixed_const(1000);
635771fe6b9SJerome Glisse 		pix_clk2.full = rfixed_const(mode2->clock);	/* convert to fixed point */
636771fe6b9SJerome Glisse 		pix_clk2.full = rfixed_div(pix_clk2, temp_ff);
637771fe6b9SJerome Glisse 		temp_ff.full = rfixed_const(pixel_bytes2);
638771fe6b9SJerome Glisse 		peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff);
639771fe6b9SJerome Glisse 	}
640771fe6b9SJerome Glisse 
641771fe6b9SJerome Glisse 	if (peak_disp_bw.full >= mem_bw.full) {
642771fe6b9SJerome Glisse 		DRM_ERROR
643771fe6b9SJerome Glisse 		    ("You may not have enough display bandwidth for current mode\n"
644771fe6b9SJerome Glisse 		     "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n");
645771fe6b9SJerome Glisse 		printk("peak disp bw %d, mem_bw %d\n",
646771fe6b9SJerome Glisse 		       rfixed_trunc(peak_disp_bw), rfixed_trunc(mem_bw));
647771fe6b9SJerome Glisse 	}
648771fe6b9SJerome Glisse 
649771fe6b9SJerome Glisse 	/*
650771fe6b9SJerome Glisse 	 * Line Buffer Setup
651771fe6b9SJerome Glisse 	 * There is a single line buffer shared by both display controllers.
652771fe6b9SJerome Glisse 	 * DC_LB_MEMORY_SPLIT controls how that line buffer is shared between the display
653771fe6b9SJerome Glisse 	 * controllers.  The paritioning can either be done manually or via one of four
654771fe6b9SJerome Glisse 	 * preset allocations specified in bits 1:0:
655771fe6b9SJerome Glisse 	 * 0 - line buffer is divided in half and shared between each display controller
656771fe6b9SJerome Glisse 	 * 1 - D1 gets 3/4 of the line buffer, D2 gets 1/4
657771fe6b9SJerome Glisse 	 * 2 - D1 gets the whole buffer
658771fe6b9SJerome Glisse 	 * 3 - D1 gets 1/4 of the line buffer, D2 gets 3/4
659771fe6b9SJerome Glisse 	 * Setting bit 2 of DC_LB_MEMORY_SPLIT controls switches to manual allocation mode.
660771fe6b9SJerome Glisse 	 * In manual allocation mode, D1 always starts at 0, D1 end/2 is specified in bits
661771fe6b9SJerome Glisse 	 * 14:4; D2 allocation follows D1.
662771fe6b9SJerome Glisse 	 */
663771fe6b9SJerome Glisse 
664771fe6b9SJerome Glisse 	/* is auto or manual better ? */
665771fe6b9SJerome Glisse 	dc_lb_memory_split =
666771fe6b9SJerome Glisse 	    RREG32(AVIVO_DC_LB_MEMORY_SPLIT) & ~AVIVO_DC_LB_MEMORY_SPLIT_MASK;
667771fe6b9SJerome Glisse 	dc_lb_memory_split &= ~AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE;
668771fe6b9SJerome Glisse #if 1
669771fe6b9SJerome Glisse 	/* auto */
670771fe6b9SJerome Glisse 	if (mode1 && mode2) {
671771fe6b9SJerome Glisse 		if (mode1->hdisplay > mode2->hdisplay) {
672771fe6b9SJerome Glisse 			if (mode1->hdisplay > 2560)
673771fe6b9SJerome Glisse 				dc_lb_memory_split |=
674771fe6b9SJerome Glisse 				    AVIVO_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q;
675771fe6b9SJerome Glisse 			else
676771fe6b9SJerome Glisse 				dc_lb_memory_split |=
677771fe6b9SJerome Glisse 				    AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
678771fe6b9SJerome Glisse 		} else if (mode2->hdisplay > mode1->hdisplay) {
679771fe6b9SJerome Glisse 			if (mode2->hdisplay > 2560)
680771fe6b9SJerome Glisse 				dc_lb_memory_split |=
681771fe6b9SJerome Glisse 				    AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
682771fe6b9SJerome Glisse 			else
683771fe6b9SJerome Glisse 				dc_lb_memory_split |=
684771fe6b9SJerome Glisse 				    AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
685771fe6b9SJerome Glisse 		} else
686771fe6b9SJerome Glisse 			dc_lb_memory_split |=
687771fe6b9SJerome Glisse 			    AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
688771fe6b9SJerome Glisse 	} else if (mode1) {
689771fe6b9SJerome Glisse 		dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_ONLY;
690771fe6b9SJerome Glisse 	} else if (mode2) {
691771fe6b9SJerome Glisse 		dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
692771fe6b9SJerome Glisse 	}
693771fe6b9SJerome Glisse #else
694771fe6b9SJerome Glisse 	/* manual */
695771fe6b9SJerome Glisse 	dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE;
696771fe6b9SJerome Glisse 	dc_lb_memory_split &=
697771fe6b9SJerome Glisse 	    ~(AVIVO_DC_LB_DISP1_END_ADR_MASK <<
698771fe6b9SJerome Glisse 	      AVIVO_DC_LB_DISP1_END_ADR_SHIFT);
699771fe6b9SJerome Glisse 	if (mode1) {
700771fe6b9SJerome Glisse 		dc_lb_memory_split |=
701771fe6b9SJerome Glisse 		    ((((mode1->hdisplay / 2) + 64) & AVIVO_DC_LB_DISP1_END_ADR_MASK)
702771fe6b9SJerome Glisse 		     << AVIVO_DC_LB_DISP1_END_ADR_SHIFT);
703771fe6b9SJerome Glisse 	} else if (mode2) {
704771fe6b9SJerome Glisse 		dc_lb_memory_split |= (0 << AVIVO_DC_LB_DISP1_END_ADR_SHIFT);
705771fe6b9SJerome Glisse 	}
706771fe6b9SJerome Glisse #endif
707771fe6b9SJerome Glisse 	WREG32(AVIVO_DC_LB_MEMORY_SPLIT, dc_lb_memory_split);
708771fe6b9SJerome Glisse }
709