xref: /openbmc/linux/drivers/gpu/drm/radeon/radeon_legacy_encoders.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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  */
26f9183127SSam Ravnborg 
27f9183127SSam Ravnborg #include <linux/backlight.h>
282ef79416SThomas Zimmermann #include <linux/pci.h>
29f9183127SSam Ravnborg 
30f9183127SSam Ravnborg #include <drm/drm_device.h>
31f9183127SSam Ravnborg #include <drm/drm_file.h>
32f7d17cd4SThomas Zimmermann #include <drm/drm_modeset_helper_vtables.h>
33f9183127SSam Ravnborg #include <drm/drm_util.h>
34760285e7SDavid Howells #include <drm/radeon_drm.h>
35f9183127SSam Ravnborg 
361eb67781SHans de Goede #include <acpi/video.h>
371eb67781SHans de Goede 
38771fe6b9SJerome Glisse #include "radeon.h"
39297b1286SBaoyou Xie #include "radeon_asic.h"
401ae79be1SLee Jones #include "radeon_legacy_encoders.h"
41771fe6b9SJerome Glisse #include "atom.h"
4263ec0119SMichel Dänzer #ifdef CONFIG_PMAC_BACKLIGHT
4363ec0119SMichel Dänzer #include <asm/backlight.h>
4463ec0119SMichel Dänzer #endif
45771fe6b9SJerome Glisse 
radeon_legacy_encoder_disable(struct drm_encoder * encoder)464ce001abSDave Airlie static void radeon_legacy_encoder_disable(struct drm_encoder *encoder)
474ce001abSDave Airlie {
484ce001abSDave Airlie 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
49319d1e14SJani Nikula 	const struct drm_encoder_helper_funcs *encoder_funcs;
504ce001abSDave Airlie 
514ce001abSDave Airlie 	encoder_funcs = encoder->helper_private;
524ce001abSDave Airlie 	encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
534ce001abSDave Airlie 	radeon_encoder->active_device = 0;
544ce001abSDave Airlie }
55771fe6b9SJerome Glisse 
radeon_legacy_lvds_update(struct drm_encoder * encoder,int mode)5663ec0119SMichel Dänzer static void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode)
57771fe6b9SJerome Glisse {
58771fe6b9SJerome Glisse 	struct drm_device *dev = encoder->dev;
59771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
60771fe6b9SJerome Glisse 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
61771fe6b9SJerome Glisse 	uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man;
62771fe6b9SJerome Glisse 	int panel_pwr_delay = 2000;
633890ddf5SAlex Deucher 	bool is_mac = false;
6463ec0119SMichel Dänzer 	uint8_t backlight_level;
65d9fdaafbSDave Airlie 	DRM_DEBUG_KMS("\n");
66771fe6b9SJerome Glisse 
6763ec0119SMichel Dänzer 	lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
6863ec0119SMichel Dänzer 	backlight_level = (lvds_gen_cntl >> RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
6963ec0119SMichel Dänzer 
70771fe6b9SJerome Glisse 	if (radeon_encoder->enc_priv) {
71771fe6b9SJerome Glisse 		if (rdev->is_atom_bios) {
72771fe6b9SJerome Glisse 			struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
73771fe6b9SJerome Glisse 			panel_pwr_delay = lvds->panel_pwr_delay;
7463ec0119SMichel Dänzer 			if (lvds->bl_dev)
7563ec0119SMichel Dänzer 				backlight_level = lvds->backlight_level;
76771fe6b9SJerome Glisse 		} else {
77771fe6b9SJerome Glisse 			struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
78771fe6b9SJerome Glisse 			panel_pwr_delay = lvds->panel_pwr_delay;
7963ec0119SMichel Dänzer 			if (lvds->bl_dev)
8063ec0119SMichel Dänzer 				backlight_level = lvds->backlight_level;
81771fe6b9SJerome Glisse 		}
82771fe6b9SJerome Glisse 	}
83771fe6b9SJerome Glisse 
843890ddf5SAlex Deucher 	/* macs (and possibly some x86 oem systems?) wire up LVDS strangely
853890ddf5SAlex Deucher 	 * Taken from radeonfb.
863890ddf5SAlex Deucher 	 */
873890ddf5SAlex Deucher 	if ((rdev->mode_info.connector_table == CT_IBOOK) ||
883890ddf5SAlex Deucher 	    (rdev->mode_info.connector_table == CT_POWERBOOK_EXTERNAL) ||
893890ddf5SAlex Deucher 	    (rdev->mode_info.connector_table == CT_POWERBOOK_INTERNAL) ||
903890ddf5SAlex Deucher 	    (rdev->mode_info.connector_table == CT_POWERBOOK_VGA))
913890ddf5SAlex Deucher 		is_mac = true;
923890ddf5SAlex Deucher 
93771fe6b9SJerome Glisse 	switch (mode) {
94771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_ON:
95771fe6b9SJerome Glisse 		disp_pwr_man = RREG32(RADEON_DISP_PWR_MAN);
96771fe6b9SJerome Glisse 		disp_pwr_man |= RADEON_AUTO_PWRUP_EN;
97771fe6b9SJerome Glisse 		WREG32(RADEON_DISP_PWR_MAN, disp_pwr_man);
98771fe6b9SJerome Glisse 		lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL);
99771fe6b9SJerome Glisse 		lvds_pll_cntl |= RADEON_LVDS_PLL_EN;
100771fe6b9SJerome Glisse 		WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
1014de833c3SArnd Bergmann 		mdelay(1);
102771fe6b9SJerome Glisse 
103771fe6b9SJerome Glisse 		lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL);
104771fe6b9SJerome Glisse 		lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET;
105771fe6b9SJerome Glisse 		WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
106771fe6b9SJerome Glisse 
10763ec0119SMichel Dänzer 		lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS |
10863ec0119SMichel Dänzer 				   RADEON_LVDS_BL_MOD_LEVEL_MASK);
10963ec0119SMichel Dänzer 		lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN |
11063ec0119SMichel Dänzer 				  RADEON_LVDS_DIGON | RADEON_LVDS_BLON |
11163ec0119SMichel Dänzer 				  (backlight_level << RADEON_LVDS_BL_MOD_LEVEL_SHIFT));
1123890ddf5SAlex Deucher 		if (is_mac)
1133890ddf5SAlex Deucher 			lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN;
1144de833c3SArnd Bergmann 		mdelay(panel_pwr_delay);
115771fe6b9SJerome Glisse 		WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
116771fe6b9SJerome Glisse 		break;
117771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_STANDBY:
118771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_SUSPEND:
119771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_OFF:
120771fe6b9SJerome Glisse 		pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
121771fe6b9SJerome Glisse 		WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb);
122771fe6b9SJerome Glisse 		lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS;
1233890ddf5SAlex Deucher 		if (is_mac) {
1243890ddf5SAlex Deucher 			lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_EN;
1253890ddf5SAlex Deucher 			WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
1263890ddf5SAlex Deucher 			lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_EN);
1273890ddf5SAlex Deucher 		} else {
1283890ddf5SAlex Deucher 			WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
129771fe6b9SJerome Glisse 			lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON);
1303890ddf5SAlex Deucher 		}
1314de833c3SArnd Bergmann 		mdelay(panel_pwr_delay);
132771fe6b9SJerome Glisse 		WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
133771fe6b9SJerome Glisse 		WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
1344de833c3SArnd Bergmann 		mdelay(panel_pwr_delay);
135771fe6b9SJerome Glisse 		break;
136771fe6b9SJerome Glisse 	}
137771fe6b9SJerome Glisse 
138771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
139771fe6b9SJerome Glisse 		radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
140771fe6b9SJerome Glisse 	else
141771fe6b9SJerome Glisse 		radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
142c913e23aSRafał Miłecki 
143771fe6b9SJerome Glisse }
144771fe6b9SJerome Glisse 
radeon_legacy_lvds_dpms(struct drm_encoder * encoder,int mode)14563ec0119SMichel Dänzer static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
14663ec0119SMichel Dänzer {
14763ec0119SMichel Dänzer 	struct radeon_device *rdev = encoder->dev->dev_private;
14863ec0119SMichel Dänzer 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
14963ec0119SMichel Dänzer 	DRM_DEBUG("\n");
15063ec0119SMichel Dänzer 
15163ec0119SMichel Dänzer 	if (radeon_encoder->enc_priv) {
15263ec0119SMichel Dänzer 		if (rdev->is_atom_bios) {
15363ec0119SMichel Dänzer 			struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
15463ec0119SMichel Dänzer 			lvds->dpms_mode = mode;
15563ec0119SMichel Dänzer 		} else {
15663ec0119SMichel Dänzer 			struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
15763ec0119SMichel Dänzer 			lvds->dpms_mode = mode;
15863ec0119SMichel Dänzer 		}
15963ec0119SMichel Dänzer 	}
16063ec0119SMichel Dänzer 
16163ec0119SMichel Dänzer 	radeon_legacy_lvds_update(encoder, mode);
16263ec0119SMichel Dänzer }
16363ec0119SMichel Dänzer 
radeon_legacy_lvds_prepare(struct drm_encoder * encoder)164771fe6b9SJerome Glisse static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder)
165771fe6b9SJerome Glisse {
166771fe6b9SJerome Glisse 	struct radeon_device *rdev = encoder->dev->dev_private;
167771fe6b9SJerome Glisse 
168771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
169771fe6b9SJerome Glisse 		radeon_atom_output_lock(encoder, true);
170771fe6b9SJerome Glisse 	else
171771fe6b9SJerome Glisse 		radeon_combios_output_lock(encoder, true);
172771fe6b9SJerome Glisse 	radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF);
173771fe6b9SJerome Glisse }
174771fe6b9SJerome Glisse 
radeon_legacy_lvds_commit(struct drm_encoder * encoder)175771fe6b9SJerome Glisse static void radeon_legacy_lvds_commit(struct drm_encoder *encoder)
176771fe6b9SJerome Glisse {
177771fe6b9SJerome Glisse 	struct radeon_device *rdev = encoder->dev->dev_private;
178771fe6b9SJerome Glisse 
179771fe6b9SJerome Glisse 	radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_ON);
180771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
181771fe6b9SJerome Glisse 		radeon_atom_output_lock(encoder, false);
182771fe6b9SJerome Glisse 	else
183771fe6b9SJerome Glisse 		radeon_combios_output_lock(encoder, false);
184771fe6b9SJerome Glisse }
185771fe6b9SJerome Glisse 
radeon_legacy_lvds_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)186771fe6b9SJerome Glisse static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder,
187771fe6b9SJerome Glisse 					struct drm_display_mode *mode,
188771fe6b9SJerome Glisse 					struct drm_display_mode *adjusted_mode)
189771fe6b9SJerome Glisse {
190771fe6b9SJerome Glisse 	struct drm_device *dev = encoder->dev;
191771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
192771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
193771fe6b9SJerome Glisse 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
194771fe6b9SJerome Glisse 	uint32_t lvds_pll_cntl, lvds_gen_cntl, lvds_ss_gen_cntl;
195771fe6b9SJerome Glisse 
196d9fdaafbSDave Airlie 	DRM_DEBUG_KMS("\n");
197771fe6b9SJerome Glisse 
198771fe6b9SJerome Glisse 	lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL);
199771fe6b9SJerome Glisse 	lvds_pll_cntl &= ~RADEON_LVDS_PLL_EN;
200771fe6b9SJerome Glisse 
201771fe6b9SJerome Glisse 	lvds_ss_gen_cntl = RREG32(RADEON_LVDS_SS_GEN_CNTL);
20232f48ffeSAlex Deucher 	if (rdev->is_atom_bios) {
20332f48ffeSAlex Deucher 		/* LVDS_GEN_CNTL parameters are computed in LVDSEncoderControl
20432f48ffeSAlex Deucher 		 * need to call that on resume to set up the reg properly.
20532f48ffeSAlex Deucher 		 */
20632f48ffeSAlex Deucher 		radeon_encoder->pixel_clock = adjusted_mode->clock;
20732f48ffeSAlex Deucher 		atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_ENABLE);
20832f48ffeSAlex Deucher 		lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
20932f48ffeSAlex Deucher 	} else {
210771fe6b9SJerome Glisse 		struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv;
211771fe6b9SJerome Glisse 		if (lvds) {
212d9fdaafbSDave Airlie 			DRM_DEBUG_KMS("bios LVDS_GEN_CNTL: 0x%x\n", lvds->lvds_gen_cntl);
213771fe6b9SJerome Glisse 			lvds_gen_cntl = lvds->lvds_gen_cntl;
214771fe6b9SJerome Glisse 			lvds_ss_gen_cntl &= ~((0xf << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) |
215771fe6b9SJerome Glisse 					      (0xf << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT));
216771fe6b9SJerome Glisse 			lvds_ss_gen_cntl |= ((lvds->panel_digon_delay << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) |
217771fe6b9SJerome Glisse 					     (lvds->panel_blon_delay << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT));
218771fe6b9SJerome Glisse 		} else
219771fe6b9SJerome Glisse 			lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
22032f48ffeSAlex Deucher 	}
221771fe6b9SJerome Glisse 	lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS;
222771fe6b9SJerome Glisse 	lvds_gen_cntl &= ~(RADEON_LVDS_ON |
223771fe6b9SJerome Glisse 			   RADEON_LVDS_BLON |
224771fe6b9SJerome Glisse 			   RADEON_LVDS_EN |
225771fe6b9SJerome Glisse 			   RADEON_LVDS_RST_FM);
226771fe6b9SJerome Glisse 
227771fe6b9SJerome Glisse 	if (ASIC_IS_R300(rdev))
228771fe6b9SJerome Glisse 		lvds_pll_cntl &= ~(R300_LVDS_SRC_SEL_MASK);
229771fe6b9SJerome Glisse 
230771fe6b9SJerome Glisse 	if (radeon_crtc->crtc_id == 0) {
231771fe6b9SJerome Glisse 		if (ASIC_IS_R300(rdev)) {
232c93bb85bSJerome Glisse 			if (radeon_encoder->rmx_type != RMX_OFF)
233771fe6b9SJerome Glisse 				lvds_pll_cntl |= R300_LVDS_SRC_SEL_RMX;
234771fe6b9SJerome Glisse 		} else
235771fe6b9SJerome Glisse 			lvds_gen_cntl &= ~RADEON_LVDS_SEL_CRTC2;
236771fe6b9SJerome Glisse 	} else {
237771fe6b9SJerome Glisse 		if (ASIC_IS_R300(rdev))
238771fe6b9SJerome Glisse 			lvds_pll_cntl |= R300_LVDS_SRC_SEL_CRTC2;
239771fe6b9SJerome Glisse 		else
240771fe6b9SJerome Glisse 			lvds_gen_cntl |= RADEON_LVDS_SEL_CRTC2;
241771fe6b9SJerome Glisse 	}
242771fe6b9SJerome Glisse 
243771fe6b9SJerome Glisse 	WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
244771fe6b9SJerome Glisse 	WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
245771fe6b9SJerome Glisse 	WREG32(RADEON_LVDS_SS_GEN_CNTL, lvds_ss_gen_cntl);
246771fe6b9SJerome Glisse 
247771fe6b9SJerome Glisse 	if (rdev->family == CHIP_RV410)
248771fe6b9SJerome Glisse 		WREG32(RADEON_CLOCK_CNTL_INDEX, 0);
249771fe6b9SJerome Glisse 
250771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
251771fe6b9SJerome Glisse 		radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
252771fe6b9SJerome Glisse 	else
253771fe6b9SJerome Glisse 		radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
254771fe6b9SJerome Glisse }
255771fe6b9SJerome Glisse 
radeon_legacy_mode_fixup(struct drm_encoder * encoder,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)25680297e87SAlex Deucher static bool radeon_legacy_mode_fixup(struct drm_encoder *encoder,
257e811f5aeSLaurent Pinchart 				     const struct drm_display_mode *mode,
258771fe6b9SJerome Glisse 				     struct drm_display_mode *adjusted_mode)
259771fe6b9SJerome Glisse {
260771fe6b9SJerome Glisse 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
261771fe6b9SJerome Glisse 
2628c2a6d73SAlex Deucher 	/* set the active encoder to connector routing */
2638c2a6d73SAlex Deucher 	radeon_encoder_set_active_device(encoder);
264771fe6b9SJerome Glisse 	drm_mode_set_crtcinfo(adjusted_mode, 0);
265771fe6b9SJerome Glisse 
26680297e87SAlex Deucher 	/* get the native mode for LVDS */
2673515387bSAlex Deucher 	if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT))
2683515387bSAlex Deucher 		radeon_panel_mode_fixup(encoder, adjusted_mode);
269771fe6b9SJerome Glisse 
270771fe6b9SJerome Glisse 	return true;
271771fe6b9SJerome Glisse }
272771fe6b9SJerome Glisse 
273771fe6b9SJerome Glisse static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = {
274771fe6b9SJerome Glisse 	.dpms = radeon_legacy_lvds_dpms,
27580297e87SAlex Deucher 	.mode_fixup = radeon_legacy_mode_fixup,
276771fe6b9SJerome Glisse 	.prepare = radeon_legacy_lvds_prepare,
277771fe6b9SJerome Glisse 	.mode_set = radeon_legacy_lvds_mode_set,
278771fe6b9SJerome Glisse 	.commit = radeon_legacy_lvds_commit,
2794ce001abSDave Airlie 	.disable = radeon_legacy_encoder_disable,
280771fe6b9SJerome Glisse };
281771fe6b9SJerome Glisse 
2826d92f81dSAlex Deucher u8
radeon_legacy_get_backlight_level(struct radeon_encoder * radeon_encoder)2836d92f81dSAlex Deucher radeon_legacy_get_backlight_level(struct radeon_encoder *radeon_encoder)
28463ec0119SMichel Dänzer {
2856d92f81dSAlex Deucher 	struct drm_device *dev = radeon_encoder->base.dev;
2866d92f81dSAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
2876d92f81dSAlex Deucher 	u8 backlight_level;
2886d92f81dSAlex Deucher 
2896d92f81dSAlex Deucher 	backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
2906d92f81dSAlex Deucher 			   RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
2916d92f81dSAlex Deucher 
2926d92f81dSAlex Deucher 	return backlight_level;
2936d92f81dSAlex Deucher }
2946d92f81dSAlex Deucher 
29537e9b6a6SAlex Deucher void
radeon_legacy_set_backlight_level(struct radeon_encoder * radeon_encoder,u8 level)29637e9b6a6SAlex Deucher radeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level)
29763ec0119SMichel Dänzer {
29863ec0119SMichel Dänzer 	struct drm_device *dev = radeon_encoder->base.dev;
29963ec0119SMichel Dänzer 	struct radeon_device *rdev = dev->dev_private;
30063ec0119SMichel Dänzer 	int dpms_mode = DRM_MODE_DPMS_ON;
30163ec0119SMichel Dänzer 
30263ec0119SMichel Dänzer 	if (radeon_encoder->enc_priv) {
30363ec0119SMichel Dänzer 		if (rdev->is_atom_bios) {
30463ec0119SMichel Dänzer 			struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
30537e9b6a6SAlex Deucher 			if (lvds->backlight_level > 0)
30663ec0119SMichel Dänzer 				dpms_mode = lvds->dpms_mode;
30737e9b6a6SAlex Deucher 			else
30837e9b6a6SAlex Deucher 				dpms_mode = DRM_MODE_DPMS_OFF;
30937e9b6a6SAlex Deucher 			lvds->backlight_level = level;
31063ec0119SMichel Dänzer 		} else {
31163ec0119SMichel Dänzer 			struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
31237e9b6a6SAlex Deucher 			if (lvds->backlight_level > 0)
31363ec0119SMichel Dänzer 				dpms_mode = lvds->dpms_mode;
31437e9b6a6SAlex Deucher 			else
31537e9b6a6SAlex Deucher 				dpms_mode = DRM_MODE_DPMS_OFF;
31637e9b6a6SAlex Deucher 			lvds->backlight_level = level;
31763ec0119SMichel Dänzer 		}
31863ec0119SMichel Dänzer 	}
31963ec0119SMichel Dänzer 
32063ec0119SMichel Dänzer 	radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode);
32137e9b6a6SAlex Deucher }
32237e9b6a6SAlex Deucher 
radeon_legacy_lvds_level(struct backlight_device * bd)323cd23492aSAlex Deucher static uint8_t radeon_legacy_lvds_level(struct backlight_device *bd)
324cd23492aSAlex Deucher {
325cd23492aSAlex Deucher 	struct radeon_backlight_privdata *pdata = bl_get_data(bd);
326cd23492aSAlex Deucher 	uint8_t level;
327cd23492aSAlex Deucher 
328cd23492aSAlex Deucher 	/* Convert brightness to hardware level */
329cd23492aSAlex Deucher 	if (bd->props.brightness < 0)
330cd23492aSAlex Deucher 		level = 0;
331cd23492aSAlex Deucher 	else if (bd->props.brightness > RADEON_MAX_BL_LEVEL)
332cd23492aSAlex Deucher 		level = RADEON_MAX_BL_LEVEL;
333cd23492aSAlex Deucher 	else
334cd23492aSAlex Deucher 		level = bd->props.brightness;
335cd23492aSAlex Deucher 
336cd23492aSAlex Deucher 	if (pdata->negative)
337cd23492aSAlex Deucher 		level = RADEON_MAX_BL_LEVEL - level;
338cd23492aSAlex Deucher 
339cd23492aSAlex Deucher 	return level;
340cd23492aSAlex Deucher }
341cd23492aSAlex Deucher 
radeon_legacy_backlight_update_status(struct backlight_device * bd)34237e9b6a6SAlex Deucher static int radeon_legacy_backlight_update_status(struct backlight_device *bd)
34337e9b6a6SAlex Deucher {
34437e9b6a6SAlex Deucher 	struct radeon_backlight_privdata *pdata = bl_get_data(bd);
34537e9b6a6SAlex Deucher 	struct radeon_encoder *radeon_encoder = pdata->encoder;
34637e9b6a6SAlex Deucher 
34737e9b6a6SAlex Deucher 	radeon_legacy_set_backlight_level(radeon_encoder,
34837e9b6a6SAlex Deucher 					  radeon_legacy_lvds_level(bd));
34963ec0119SMichel Dänzer 
35063ec0119SMichel Dänzer 	return 0;
35163ec0119SMichel Dänzer }
35263ec0119SMichel Dänzer 
radeon_legacy_backlight_get_brightness(struct backlight_device * bd)35363ec0119SMichel Dänzer static int radeon_legacy_backlight_get_brightness(struct backlight_device *bd)
35463ec0119SMichel Dänzer {
35563ec0119SMichel Dänzer 	struct radeon_backlight_privdata *pdata = bl_get_data(bd);
35663ec0119SMichel Dänzer 	struct radeon_encoder *radeon_encoder = pdata->encoder;
35763ec0119SMichel Dänzer 	struct drm_device *dev = radeon_encoder->base.dev;
35863ec0119SMichel Dänzer 	struct radeon_device *rdev = dev->dev_private;
35963ec0119SMichel Dänzer 	uint8_t backlight_level;
36063ec0119SMichel Dänzer 
36163ec0119SMichel Dänzer 	backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
36263ec0119SMichel Dänzer 			   RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
36363ec0119SMichel Dänzer 
36491030880SAlex Deucher 	return pdata->negative ? RADEON_MAX_BL_LEVEL - backlight_level : backlight_level;
36563ec0119SMichel Dänzer }
36663ec0119SMichel Dänzer 
36763ec0119SMichel Dänzer static const struct backlight_ops radeon_backlight_ops = {
36863ec0119SMichel Dänzer 	.get_brightness = radeon_legacy_backlight_get_brightness,
36963ec0119SMichel Dänzer 	.update_status	= radeon_legacy_backlight_update_status,
37063ec0119SMichel Dänzer };
37163ec0119SMichel Dänzer 
radeon_legacy_backlight_init(struct radeon_encoder * radeon_encoder,struct drm_connector * drm_connector)37263ec0119SMichel Dänzer void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
37363ec0119SMichel Dänzer 				  struct drm_connector *drm_connector)
37463ec0119SMichel Dänzer {
37563ec0119SMichel Dänzer 	struct drm_device *dev = radeon_encoder->base.dev;
37663ec0119SMichel Dänzer 	struct radeon_device *rdev = dev->dev_private;
37763ec0119SMichel Dänzer 	struct backlight_device *bd;
37863ec0119SMichel Dänzer 	struct backlight_properties props;
37963ec0119SMichel Dänzer 	struct radeon_backlight_privdata *pdata;
38063ec0119SMichel Dänzer 	uint8_t backlight_level;
381614499b4SAlex Deucher 	char bl_name[16];
38263ec0119SMichel Dänzer 
38363ec0119SMichel Dänzer 	if (!radeon_encoder->enc_priv)
38463ec0119SMichel Dänzer 		return;
38563ec0119SMichel Dänzer 
38663ec0119SMichel Dänzer #ifdef CONFIG_PMAC_BACKLIGHT
38763ec0119SMichel Dänzer 	if (!pmac_has_backlight_type("ati") &&
38863ec0119SMichel Dänzer 	    !pmac_has_backlight_type("mnca"))
38963ec0119SMichel Dänzer 		return;
39063ec0119SMichel Dänzer #endif
39163ec0119SMichel Dänzer 
3921eb67781SHans de Goede 	if (!acpi_video_backlight_use_native()) {
3931eb67781SHans de Goede 		drm_info(dev, "Skipping radeon legacy LVDS backlight registration\n");
3941eb67781SHans de Goede 		return;
3951eb67781SHans de Goede 	}
3961eb67781SHans de Goede 
39763ec0119SMichel Dänzer 	pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL);
39863ec0119SMichel Dänzer 	if (!pdata) {
39963ec0119SMichel Dänzer 		DRM_ERROR("Memory allocation failed\n");
40063ec0119SMichel Dänzer 		goto error;
40163ec0119SMichel Dänzer 	}
40263ec0119SMichel Dänzer 
403af437cfdSCorentin Chary 	memset(&props, 0, sizeof(props));
40491030880SAlex Deucher 	props.max_brightness = RADEON_MAX_BL_LEVEL;
40563ec0119SMichel Dänzer 	props.type = BACKLIGHT_RAW;
406614499b4SAlex Deucher 	snprintf(bl_name, sizeof(bl_name),
407614499b4SAlex Deucher 		 "radeon_bl%d", dev->primary->index);
4085bdebb18SDave Airlie 	bd = backlight_device_register(bl_name, drm_connector->kdev,
40963ec0119SMichel Dänzer 				       pdata, &radeon_backlight_ops, &props);
41063ec0119SMichel Dänzer 	if (IS_ERR(bd)) {
41163ec0119SMichel Dänzer 		DRM_ERROR("Backlight registration failed\n");
41263ec0119SMichel Dänzer 		goto error;
41363ec0119SMichel Dänzer 	}
41463ec0119SMichel Dänzer 
41563ec0119SMichel Dänzer 	pdata->encoder = radeon_encoder;
41663ec0119SMichel Dänzer 
41763ec0119SMichel Dänzer 	backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >>
41863ec0119SMichel Dänzer 			   RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff;
41963ec0119SMichel Dänzer 
42063ec0119SMichel Dänzer 	/* First, try to detect backlight level sense based on the assumption
42163ec0119SMichel Dänzer 	 * that firmware set it up at full brightness
42263ec0119SMichel Dänzer 	 */
42363ec0119SMichel Dänzer 	if (backlight_level == 0)
42463ec0119SMichel Dänzer 		pdata->negative = true;
42563ec0119SMichel Dänzer 	else if (backlight_level == 0xff)
42663ec0119SMichel Dänzer 		pdata->negative = false;
42763ec0119SMichel Dänzer 	else {
42863ec0119SMichel Dänzer 		/* XXX hack... maybe some day we can figure out in what direction
42963ec0119SMichel Dänzer 		 * backlight should work on a given panel?
43063ec0119SMichel Dänzer 		 */
43163ec0119SMichel Dänzer 		pdata->negative = (rdev->family != CHIP_RV200 &&
43263ec0119SMichel Dänzer 				   rdev->family != CHIP_RV250 &&
43363ec0119SMichel Dänzer 				   rdev->family != CHIP_RV280 &&
43463ec0119SMichel Dänzer 				   rdev->family != CHIP_RV350);
43563ec0119SMichel Dänzer 
43663ec0119SMichel Dänzer #ifdef CONFIG_PMAC_BACKLIGHT
43763ec0119SMichel Dänzer 		pdata->negative = (pdata->negative ||
43863ec0119SMichel Dänzer 				   of_machine_is_compatible("PowerBook4,3") ||
43963ec0119SMichel Dänzer 				   of_machine_is_compatible("PowerBook6,3") ||
44063ec0119SMichel Dänzer 				   of_machine_is_compatible("PowerBook6,5"));
44163ec0119SMichel Dänzer #endif
44263ec0119SMichel Dänzer 	}
44363ec0119SMichel Dänzer 
44463ec0119SMichel Dänzer 	if (rdev->is_atom_bios) {
44563ec0119SMichel Dänzer 		struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
44663ec0119SMichel Dänzer 		lvds->bl_dev = bd;
44763ec0119SMichel Dänzer 	} else {
44863ec0119SMichel Dänzer 		struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
44963ec0119SMichel Dänzer 		lvds->bl_dev = bd;
45063ec0119SMichel Dänzer 	}
45163ec0119SMichel Dänzer 
45263ec0119SMichel Dänzer 	bd->props.brightness = radeon_legacy_backlight_get_brightness(bd);
45363ec0119SMichel Dänzer 	bd->props.power = FB_BLANK_UNBLANK;
45463ec0119SMichel Dänzer 	backlight_update_status(bd);
45563ec0119SMichel Dänzer 
45663ec0119SMichel Dänzer 	DRM_INFO("radeon legacy LVDS backlight initialized\n");
4574cee6a90SAlex Deucher 	rdev->mode_info.bl_encoder = radeon_encoder;
45863ec0119SMichel Dänzer 
45963ec0119SMichel Dänzer 	return;
46063ec0119SMichel Dänzer 
46163ec0119SMichel Dänzer error:
46263ec0119SMichel Dänzer 	kfree(pdata);
46363ec0119SMichel Dänzer 	return;
46463ec0119SMichel Dänzer }
46563ec0119SMichel Dänzer 
radeon_legacy_backlight_exit(struct radeon_encoder * radeon_encoder)46663ec0119SMichel Dänzer static void radeon_legacy_backlight_exit(struct radeon_encoder *radeon_encoder)
46763ec0119SMichel Dänzer {
46863ec0119SMichel Dänzer 	struct drm_device *dev = radeon_encoder->base.dev;
46963ec0119SMichel Dänzer 	struct radeon_device *rdev = dev->dev_private;
47063ec0119SMichel Dänzer 	struct backlight_device *bd = NULL;
47163ec0119SMichel Dänzer 
47263ec0119SMichel Dänzer 	if (!radeon_encoder->enc_priv)
47363ec0119SMichel Dänzer 		return;
47463ec0119SMichel Dänzer 
47563ec0119SMichel Dänzer 	if (rdev->is_atom_bios) {
47663ec0119SMichel Dänzer 		struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
47763ec0119SMichel Dänzer 		bd = lvds->bl_dev;
47863ec0119SMichel Dänzer 		lvds->bl_dev = NULL;
47963ec0119SMichel Dänzer 	} else {
48063ec0119SMichel Dänzer 		struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
48163ec0119SMichel Dänzer 		bd = lvds->bl_dev;
48263ec0119SMichel Dänzer 		lvds->bl_dev = NULL;
48363ec0119SMichel Dänzer 	}
48463ec0119SMichel Dänzer 
48563ec0119SMichel Dänzer 	if (bd) {
48691030880SAlex Deucher 		struct radeon_backlight_privdata *pdata;
48763ec0119SMichel Dänzer 
48863ec0119SMichel Dänzer 		pdata = bl_get_data(bd);
48963ec0119SMichel Dänzer 		backlight_device_unregister(bd);
49063ec0119SMichel Dänzer 		kfree(pdata);
49163ec0119SMichel Dänzer 
49263ec0119SMichel Dänzer 		DRM_INFO("radeon legacy LVDS backlight unloaded\n");
49363ec0119SMichel Dänzer 	}
49463ec0119SMichel Dänzer }
49563ec0119SMichel Dänzer 
radeon_lvds_enc_destroy(struct drm_encoder * encoder)49663ec0119SMichel Dänzer static void radeon_lvds_enc_destroy(struct drm_encoder *encoder)
49763ec0119SMichel Dänzer {
49863ec0119SMichel Dänzer 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
49963ec0119SMichel Dänzer 
50063ec0119SMichel Dänzer 	if (radeon_encoder->enc_priv) {
50163ec0119SMichel Dänzer 		radeon_legacy_backlight_exit(radeon_encoder);
50263ec0119SMichel Dänzer 		kfree(radeon_encoder->enc_priv);
50363ec0119SMichel Dänzer 	}
50463ec0119SMichel Dänzer 	drm_encoder_cleanup(encoder);
50563ec0119SMichel Dänzer 	kfree(radeon_encoder);
50663ec0119SMichel Dänzer }
507771fe6b9SJerome Glisse 
508771fe6b9SJerome Glisse static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = {
50963ec0119SMichel Dänzer 	.destroy = radeon_lvds_enc_destroy,
510771fe6b9SJerome Glisse };
511771fe6b9SJerome Glisse 
radeon_legacy_primary_dac_dpms(struct drm_encoder * encoder,int mode)512771fe6b9SJerome Glisse static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode)
513771fe6b9SJerome Glisse {
514771fe6b9SJerome Glisse 	struct drm_device *dev = encoder->dev;
515771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
516771fe6b9SJerome Glisse 	uint32_t crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
517771fe6b9SJerome Glisse 	uint32_t dac_cntl = RREG32(RADEON_DAC_CNTL);
518771fe6b9SJerome Glisse 	uint32_t dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL);
519771fe6b9SJerome Glisse 
520d9fdaafbSDave Airlie 	DRM_DEBUG_KMS("\n");
521771fe6b9SJerome Glisse 
522771fe6b9SJerome Glisse 	switch (mode) {
523771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_ON:
524771fe6b9SJerome Glisse 		crtc_ext_cntl |= RADEON_CRTC_CRT_ON;
525771fe6b9SJerome Glisse 		dac_cntl &= ~RADEON_DAC_PDWN;
526771fe6b9SJerome Glisse 		dac_macro_cntl &= ~(RADEON_DAC_PDWN_R |
527771fe6b9SJerome Glisse 				    RADEON_DAC_PDWN_G |
528771fe6b9SJerome Glisse 				    RADEON_DAC_PDWN_B);
529771fe6b9SJerome Glisse 		break;
530771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_STANDBY:
531771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_SUSPEND:
532771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_OFF:
533771fe6b9SJerome Glisse 		crtc_ext_cntl &= ~RADEON_CRTC_CRT_ON;
534771fe6b9SJerome Glisse 		dac_cntl |= RADEON_DAC_PDWN;
535771fe6b9SJerome Glisse 		dac_macro_cntl |= (RADEON_DAC_PDWN_R |
536771fe6b9SJerome Glisse 				   RADEON_DAC_PDWN_G |
537771fe6b9SJerome Glisse 				   RADEON_DAC_PDWN_B);
538771fe6b9SJerome Glisse 		break;
539771fe6b9SJerome Glisse 	}
540771fe6b9SJerome Glisse 
541f8c4d701SEgbert Eich 	/* handled in radeon_crtc_dpms() */
542f8c4d701SEgbert Eich 	if (!(rdev->flags & RADEON_SINGLE_CRTC))
543771fe6b9SJerome Glisse 		WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
544771fe6b9SJerome Glisse 	WREG32(RADEON_DAC_CNTL, dac_cntl);
545771fe6b9SJerome Glisse 	WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl);
546771fe6b9SJerome Glisse 
547771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
548771fe6b9SJerome Glisse 		radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
549771fe6b9SJerome Glisse 	else
550771fe6b9SJerome Glisse 		radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
551c913e23aSRafał Miłecki 
552771fe6b9SJerome Glisse }
553771fe6b9SJerome Glisse 
radeon_legacy_primary_dac_prepare(struct drm_encoder * encoder)554771fe6b9SJerome Glisse static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder)
555771fe6b9SJerome Glisse {
556771fe6b9SJerome Glisse 	struct radeon_device *rdev = encoder->dev->dev_private;
557771fe6b9SJerome Glisse 
558771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
559771fe6b9SJerome Glisse 		radeon_atom_output_lock(encoder, true);
560771fe6b9SJerome Glisse 	else
561771fe6b9SJerome Glisse 		radeon_combios_output_lock(encoder, true);
562771fe6b9SJerome Glisse 	radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_OFF);
563771fe6b9SJerome Glisse }
564771fe6b9SJerome Glisse 
radeon_legacy_primary_dac_commit(struct drm_encoder * encoder)565771fe6b9SJerome Glisse static void radeon_legacy_primary_dac_commit(struct drm_encoder *encoder)
566771fe6b9SJerome Glisse {
567771fe6b9SJerome Glisse 	struct radeon_device *rdev = encoder->dev->dev_private;
568771fe6b9SJerome Glisse 
569771fe6b9SJerome Glisse 	radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_ON);
570771fe6b9SJerome Glisse 
571771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
572771fe6b9SJerome Glisse 		radeon_atom_output_lock(encoder, false);
573771fe6b9SJerome Glisse 	else
574771fe6b9SJerome Glisse 		radeon_combios_output_lock(encoder, false);
575771fe6b9SJerome Glisse }
576771fe6b9SJerome Glisse 
radeon_legacy_primary_dac_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)577771fe6b9SJerome Glisse static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder,
578771fe6b9SJerome Glisse 					       struct drm_display_mode *mode,
579771fe6b9SJerome Glisse 					       struct drm_display_mode *adjusted_mode)
580771fe6b9SJerome Glisse {
581771fe6b9SJerome Glisse 	struct drm_device *dev = encoder->dev;
582771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
583771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
584771fe6b9SJerome Glisse 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
585771fe6b9SJerome Glisse 	uint32_t disp_output_cntl, dac_cntl, dac2_cntl, dac_macro_cntl;
586771fe6b9SJerome Glisse 
587d9fdaafbSDave Airlie 	DRM_DEBUG_KMS("\n");
588771fe6b9SJerome Glisse 
589771fe6b9SJerome Glisse 	if (radeon_crtc->crtc_id == 0) {
590771fe6b9SJerome Glisse 		if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) {
591771fe6b9SJerome Glisse 			disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL) &
592771fe6b9SJerome Glisse 				~(RADEON_DISP_DAC_SOURCE_MASK);
593771fe6b9SJerome Glisse 			WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
594771fe6b9SJerome Glisse 		} else {
595771fe6b9SJerome Glisse 			dac2_cntl = RREG32(RADEON_DAC_CNTL2)  & ~(RADEON_DAC2_DAC_CLK_SEL);
596771fe6b9SJerome Glisse 			WREG32(RADEON_DAC_CNTL2, dac2_cntl);
597771fe6b9SJerome Glisse 		}
598771fe6b9SJerome Glisse 	} else {
599771fe6b9SJerome Glisse 		if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) {
600771fe6b9SJerome Glisse 			disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL) &
601771fe6b9SJerome Glisse 				~(RADEON_DISP_DAC_SOURCE_MASK);
602771fe6b9SJerome Glisse 			disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2;
603771fe6b9SJerome Glisse 			WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
604771fe6b9SJerome Glisse 		} else {
605771fe6b9SJerome Glisse 			dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC_CLK_SEL;
606771fe6b9SJerome Glisse 			WREG32(RADEON_DAC_CNTL2, dac2_cntl);
607771fe6b9SJerome Glisse 		}
608771fe6b9SJerome Glisse 	}
609771fe6b9SJerome Glisse 
610771fe6b9SJerome Glisse 	dac_cntl = (RADEON_DAC_MASK_ALL |
611771fe6b9SJerome Glisse 		    RADEON_DAC_VGA_ADR_EN |
612771fe6b9SJerome Glisse 		    /* TODO 6-bits */
613771fe6b9SJerome Glisse 		    RADEON_DAC_8BIT_EN);
614771fe6b9SJerome Glisse 
615771fe6b9SJerome Glisse 	WREG32_P(RADEON_DAC_CNTL,
616771fe6b9SJerome Glisse 		       dac_cntl,
617771fe6b9SJerome Glisse 		       RADEON_DAC_RANGE_CNTL |
618771fe6b9SJerome Glisse 		       RADEON_DAC_BLANKING);
619771fe6b9SJerome Glisse 
620771fe6b9SJerome Glisse 	if (radeon_encoder->enc_priv) {
621771fe6b9SJerome Glisse 		struct radeon_encoder_primary_dac *p_dac = (struct radeon_encoder_primary_dac *)radeon_encoder->enc_priv;
622771fe6b9SJerome Glisse 		dac_macro_cntl = p_dac->ps2_pdac_adj;
623771fe6b9SJerome Glisse 	} else
624771fe6b9SJerome Glisse 		dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL);
625771fe6b9SJerome Glisse 	dac_macro_cntl |= RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B;
626771fe6b9SJerome Glisse 	WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl);
627771fe6b9SJerome Glisse 
628771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
629771fe6b9SJerome Glisse 		radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
630771fe6b9SJerome Glisse 	else
631771fe6b9SJerome Glisse 		radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
632771fe6b9SJerome Glisse }
633771fe6b9SJerome Glisse 
radeon_legacy_primary_dac_detect(struct drm_encoder * encoder,struct drm_connector * connector)634771fe6b9SJerome Glisse static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_encoder *encoder,
635771fe6b9SJerome Glisse 								  struct drm_connector *connector)
636771fe6b9SJerome Glisse {
637771fe6b9SJerome Glisse 	struct drm_device *dev = encoder->dev;
638771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
639771fe6b9SJerome Glisse 	uint32_t vclk_ecp_cntl, crtc_ext_cntl;
640771fe6b9SJerome Glisse 	uint32_t dac_ext_cntl, dac_cntl, dac_macro_cntl, tmp;
641771fe6b9SJerome Glisse 	enum drm_connector_status found = connector_status_disconnected;
642771fe6b9SJerome Glisse 	bool color = true;
643771fe6b9SJerome Glisse 
64451861d4eSJerome Glisse 	/* just don't bother on RN50 those chip are often connected to remoting
64551861d4eSJerome Glisse 	 * console hw and often we get failure to load detect those. So to make
64651861d4eSJerome Glisse 	 * everyone happy report the encoder as always connected.
64751861d4eSJerome Glisse 	 */
64851861d4eSJerome Glisse 	if (ASIC_IS_RN50(rdev)) {
64951861d4eSJerome Glisse 		return connector_status_connected;
65051861d4eSJerome Glisse 	}
65151861d4eSJerome Glisse 
652771fe6b9SJerome Glisse 	/* save the regs we need */
653771fe6b9SJerome Glisse 	vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL);
654771fe6b9SJerome Glisse 	crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
655771fe6b9SJerome Glisse 	dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL);
656771fe6b9SJerome Glisse 	dac_cntl = RREG32(RADEON_DAC_CNTL);
657771fe6b9SJerome Glisse 	dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL);
658771fe6b9SJerome Glisse 
659771fe6b9SJerome Glisse 	tmp = vclk_ecp_cntl &
660771fe6b9SJerome Glisse 		~(RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb);
661771fe6b9SJerome Glisse 	WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp);
662771fe6b9SJerome Glisse 
663771fe6b9SJerome Glisse 	tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON;
664771fe6b9SJerome Glisse 	WREG32(RADEON_CRTC_EXT_CNTL, tmp);
665771fe6b9SJerome Glisse 
666771fe6b9SJerome Glisse 	tmp = RADEON_DAC_FORCE_BLANK_OFF_EN |
667771fe6b9SJerome Glisse 		RADEON_DAC_FORCE_DATA_EN;
668771fe6b9SJerome Glisse 
669771fe6b9SJerome Glisse 	if (color)
670771fe6b9SJerome Glisse 		tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB;
671771fe6b9SJerome Glisse 	else
672771fe6b9SJerome Glisse 		tmp |= RADEON_DAC_FORCE_DATA_SEL_G;
673771fe6b9SJerome Glisse 
674771fe6b9SJerome Glisse 	if (ASIC_IS_R300(rdev))
675771fe6b9SJerome Glisse 		tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT);
6769c50b1d9SEgbert Eich 	else if (ASIC_IS_RV100(rdev))
6779c50b1d9SEgbert Eich 		tmp |= (0x1ac << RADEON_DAC_FORCE_DATA_SHIFT);
678771fe6b9SJerome Glisse 	else
679771fe6b9SJerome Glisse 		tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT);
680771fe6b9SJerome Glisse 
681771fe6b9SJerome Glisse 	WREG32(RADEON_DAC_EXT_CNTL, tmp);
682771fe6b9SJerome Glisse 
683771fe6b9SJerome Glisse 	tmp = dac_cntl & ~(RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_PDWN);
684771fe6b9SJerome Glisse 	tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN;
685771fe6b9SJerome Glisse 	WREG32(RADEON_DAC_CNTL, tmp);
686771fe6b9SJerome Glisse 
68783325d07SEgbert Eich 	tmp = dac_macro_cntl;
688771fe6b9SJerome Glisse 	tmp &= ~(RADEON_DAC_PDWN_R |
689771fe6b9SJerome Glisse 		 RADEON_DAC_PDWN_G |
690771fe6b9SJerome Glisse 		 RADEON_DAC_PDWN_B);
691771fe6b9SJerome Glisse 
692771fe6b9SJerome Glisse 	WREG32(RADEON_DAC_MACRO_CNTL, tmp);
693771fe6b9SJerome Glisse 
6944de833c3SArnd Bergmann 	mdelay(2);
695771fe6b9SJerome Glisse 
696771fe6b9SJerome Glisse 	if (RREG32(RADEON_DAC_CNTL) & RADEON_DAC_CMP_OUTPUT)
697771fe6b9SJerome Glisse 		found = connector_status_connected;
698771fe6b9SJerome Glisse 
699771fe6b9SJerome Glisse 	/* restore the regs we used */
700771fe6b9SJerome Glisse 	WREG32(RADEON_DAC_CNTL, dac_cntl);
701771fe6b9SJerome Glisse 	WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl);
702771fe6b9SJerome Glisse 	WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl);
703771fe6b9SJerome Glisse 	WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
704771fe6b9SJerome Glisse 	WREG32_PLL(RADEON_VCLK_ECP_CNTL, vclk_ecp_cntl);
705771fe6b9SJerome Glisse 
706771fe6b9SJerome Glisse 	return found;
707771fe6b9SJerome Glisse }
708771fe6b9SJerome Glisse 
709771fe6b9SJerome Glisse static const struct drm_encoder_helper_funcs radeon_legacy_primary_dac_helper_funcs = {
710771fe6b9SJerome Glisse 	.dpms = radeon_legacy_primary_dac_dpms,
71180297e87SAlex Deucher 	.mode_fixup = radeon_legacy_mode_fixup,
712771fe6b9SJerome Glisse 	.prepare = radeon_legacy_primary_dac_prepare,
713771fe6b9SJerome Glisse 	.mode_set = radeon_legacy_primary_dac_mode_set,
714771fe6b9SJerome Glisse 	.commit = radeon_legacy_primary_dac_commit,
715771fe6b9SJerome Glisse 	.detect = radeon_legacy_primary_dac_detect,
7164ce001abSDave Airlie 	.disable = radeon_legacy_encoder_disable,
717771fe6b9SJerome Glisse };
718771fe6b9SJerome Glisse 
719771fe6b9SJerome Glisse 
720771fe6b9SJerome Glisse static const struct drm_encoder_funcs radeon_legacy_primary_dac_enc_funcs = {
721771fe6b9SJerome Glisse 	.destroy = radeon_enc_destroy,
722771fe6b9SJerome Glisse };
723771fe6b9SJerome Glisse 
radeon_legacy_tmds_int_dpms(struct drm_encoder * encoder,int mode)724771fe6b9SJerome Glisse static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode)
725771fe6b9SJerome Glisse {
726771fe6b9SJerome Glisse 	struct drm_device *dev = encoder->dev;
727771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
728771fe6b9SJerome Glisse 	uint32_t fp_gen_cntl = RREG32(RADEON_FP_GEN_CNTL);
729d9fdaafbSDave Airlie 	DRM_DEBUG_KMS("\n");
730771fe6b9SJerome Glisse 
731771fe6b9SJerome Glisse 	switch (mode) {
732771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_ON:
733771fe6b9SJerome Glisse 		fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN);
734771fe6b9SJerome Glisse 		break;
735771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_STANDBY:
736771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_SUSPEND:
737771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_OFF:
738771fe6b9SJerome Glisse 		fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
739771fe6b9SJerome Glisse 		break;
740771fe6b9SJerome Glisse 	}
741771fe6b9SJerome Glisse 
742771fe6b9SJerome Glisse 	WREG32(RADEON_FP_GEN_CNTL, fp_gen_cntl);
743771fe6b9SJerome Glisse 
744771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
745771fe6b9SJerome Glisse 		radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
746771fe6b9SJerome Glisse 	else
747771fe6b9SJerome Glisse 		radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
748c913e23aSRafał Miłecki 
749771fe6b9SJerome Glisse }
750771fe6b9SJerome Glisse 
radeon_legacy_tmds_int_prepare(struct drm_encoder * encoder)751771fe6b9SJerome Glisse static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder)
752771fe6b9SJerome Glisse {
753771fe6b9SJerome Glisse 	struct radeon_device *rdev = encoder->dev->dev_private;
754771fe6b9SJerome Glisse 
755771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
756771fe6b9SJerome Glisse 		radeon_atom_output_lock(encoder, true);
757771fe6b9SJerome Glisse 	else
758771fe6b9SJerome Glisse 		radeon_combios_output_lock(encoder, true);
759771fe6b9SJerome Glisse 	radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_OFF);
760771fe6b9SJerome Glisse }
761771fe6b9SJerome Glisse 
radeon_legacy_tmds_int_commit(struct drm_encoder * encoder)762771fe6b9SJerome Glisse static void radeon_legacy_tmds_int_commit(struct drm_encoder *encoder)
763771fe6b9SJerome Glisse {
764771fe6b9SJerome Glisse 	struct radeon_device *rdev = encoder->dev->dev_private;
765771fe6b9SJerome Glisse 
766771fe6b9SJerome Glisse 	radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_ON);
767771fe6b9SJerome Glisse 
768771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
769771fe6b9SJerome Glisse 		radeon_atom_output_lock(encoder, true);
770771fe6b9SJerome Glisse 	else
771771fe6b9SJerome Glisse 		radeon_combios_output_lock(encoder, true);
772771fe6b9SJerome Glisse }
773771fe6b9SJerome Glisse 
radeon_legacy_tmds_int_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)774771fe6b9SJerome Glisse static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder,
775771fe6b9SJerome Glisse 					    struct drm_display_mode *mode,
776771fe6b9SJerome Glisse 					    struct drm_display_mode *adjusted_mode)
777771fe6b9SJerome Glisse {
778771fe6b9SJerome Glisse 	struct drm_device *dev = encoder->dev;
779771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
780771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
781771fe6b9SJerome Glisse 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
782771fe6b9SJerome Glisse 	uint32_t tmp, tmds_pll_cntl, tmds_transmitter_cntl, fp_gen_cntl;
783771fe6b9SJerome Glisse 	int i;
784771fe6b9SJerome Glisse 
785d9fdaafbSDave Airlie 	DRM_DEBUG_KMS("\n");
786771fe6b9SJerome Glisse 
787771fe6b9SJerome Glisse 	tmp = tmds_pll_cntl = RREG32(RADEON_TMDS_PLL_CNTL);
788771fe6b9SJerome Glisse 	tmp &= 0xfffff;
789771fe6b9SJerome Glisse 	if (rdev->family == CHIP_RV280) {
790771fe6b9SJerome Glisse 		/* bit 22 of TMDS_PLL_CNTL is read-back inverted */
791771fe6b9SJerome Glisse 		tmp ^= (1 << 22);
792771fe6b9SJerome Glisse 		tmds_pll_cntl ^= (1 << 22);
793771fe6b9SJerome Glisse 	}
794771fe6b9SJerome Glisse 
795771fe6b9SJerome Glisse 	if (radeon_encoder->enc_priv) {
796771fe6b9SJerome Glisse 		struct radeon_encoder_int_tmds *tmds = (struct radeon_encoder_int_tmds *)radeon_encoder->enc_priv;
797771fe6b9SJerome Glisse 
798771fe6b9SJerome Glisse 		for (i = 0; i < 4; i++) {
799771fe6b9SJerome Glisse 			if (tmds->tmds_pll[i].freq == 0)
800771fe6b9SJerome Glisse 				break;
801771fe6b9SJerome Glisse 			if ((uint32_t)(mode->clock / 10) < tmds->tmds_pll[i].freq) {
802771fe6b9SJerome Glisse 				tmp = tmds->tmds_pll[i].value ;
803771fe6b9SJerome Glisse 				break;
804771fe6b9SJerome Glisse 			}
805771fe6b9SJerome Glisse 		}
806771fe6b9SJerome Glisse 	}
807771fe6b9SJerome Glisse 
808771fe6b9SJerome Glisse 	if (ASIC_IS_R300(rdev) || (rdev->family == CHIP_RV280)) {
809771fe6b9SJerome Glisse 		if (tmp & 0xfff00000)
810771fe6b9SJerome Glisse 			tmds_pll_cntl = tmp;
811771fe6b9SJerome Glisse 		else {
812771fe6b9SJerome Glisse 			tmds_pll_cntl &= 0xfff00000;
813771fe6b9SJerome Glisse 			tmds_pll_cntl |= tmp;
814771fe6b9SJerome Glisse 		}
815771fe6b9SJerome Glisse 	} else
816771fe6b9SJerome Glisse 		tmds_pll_cntl = tmp;
817771fe6b9SJerome Glisse 
818771fe6b9SJerome Glisse 	tmds_transmitter_cntl = RREG32(RADEON_TMDS_TRANSMITTER_CNTL) &
819771fe6b9SJerome Glisse 		~(RADEON_TMDS_TRANSMITTER_PLLRST);
820771fe6b9SJerome Glisse 
821771fe6b9SJerome Glisse 	if (rdev->family == CHIP_R200 ||
822771fe6b9SJerome Glisse 	    rdev->family == CHIP_R100 ||
823771fe6b9SJerome Glisse 	    ASIC_IS_R300(rdev))
824771fe6b9SJerome Glisse 		tmds_transmitter_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLEN);
825771fe6b9SJerome Glisse 	else /* RV chips got this bit reversed */
826771fe6b9SJerome Glisse 		tmds_transmitter_cntl |= RADEON_TMDS_TRANSMITTER_PLLEN;
827771fe6b9SJerome Glisse 
828771fe6b9SJerome Glisse 	fp_gen_cntl = (RREG32(RADEON_FP_GEN_CNTL) |
829771fe6b9SJerome Glisse 		      (RADEON_FP_CRTC_DONT_SHADOW_VPAR |
830771fe6b9SJerome Glisse 		       RADEON_FP_CRTC_DONT_SHADOW_HEND));
831771fe6b9SJerome Glisse 
832771fe6b9SJerome Glisse 	fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
833771fe6b9SJerome Glisse 
8341b4d7d75SAlex Deucher 	fp_gen_cntl &= ~(RADEON_FP_RMX_HVSYNC_CONTROL_EN |
8351b4d7d75SAlex Deucher 			 RADEON_FP_DFP_SYNC_SEL |
8361b4d7d75SAlex Deucher 			 RADEON_FP_CRT_SYNC_SEL |
8371b4d7d75SAlex Deucher 			 RADEON_FP_CRTC_LOCK_8DOT |
8381b4d7d75SAlex Deucher 			 RADEON_FP_USE_SHADOW_EN |
8391b4d7d75SAlex Deucher 			 RADEON_FP_CRTC_USE_SHADOW_VEND |
8401b4d7d75SAlex Deucher 			 RADEON_FP_CRT_SYNC_ALT);
8411b4d7d75SAlex Deucher 
842771fe6b9SJerome Glisse 	if (1) /*  FIXME rgbBits == 8 */
843771fe6b9SJerome Glisse 		fp_gen_cntl |= RADEON_FP_PANEL_FORMAT;  /* 24 bit format */
844771fe6b9SJerome Glisse 	else
845771fe6b9SJerome Glisse 		fp_gen_cntl &= ~RADEON_FP_PANEL_FORMAT;/* 18 bit format */
846771fe6b9SJerome Glisse 
847771fe6b9SJerome Glisse 	if (radeon_crtc->crtc_id == 0) {
848771fe6b9SJerome Glisse 		if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) {
849771fe6b9SJerome Glisse 			fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK;
850c93bb85bSJerome Glisse 			if (radeon_encoder->rmx_type != RMX_OFF)
851771fe6b9SJerome Glisse 				fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX;
852771fe6b9SJerome Glisse 			else
853771fe6b9SJerome Glisse 				fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1;
854771fe6b9SJerome Glisse 		} else
8551b4d7d75SAlex Deucher 			fp_gen_cntl &= ~RADEON_FP_SEL_CRTC2;
856771fe6b9SJerome Glisse 	} else {
857771fe6b9SJerome Glisse 		if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) {
858771fe6b9SJerome Glisse 			fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK;
859771fe6b9SJerome Glisse 			fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC2;
860771fe6b9SJerome Glisse 		} else
861771fe6b9SJerome Glisse 			fp_gen_cntl |= RADEON_FP_SEL_CRTC2;
862771fe6b9SJerome Glisse 	}
863771fe6b9SJerome Glisse 
864771fe6b9SJerome Glisse 	WREG32(RADEON_TMDS_PLL_CNTL, tmds_pll_cntl);
865771fe6b9SJerome Glisse 	WREG32(RADEON_TMDS_TRANSMITTER_CNTL, tmds_transmitter_cntl);
866771fe6b9SJerome Glisse 	WREG32(RADEON_FP_GEN_CNTL, fp_gen_cntl);
867771fe6b9SJerome Glisse 
868771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
869771fe6b9SJerome Glisse 		radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
870771fe6b9SJerome Glisse 	else
871771fe6b9SJerome Glisse 		radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
872771fe6b9SJerome Glisse }
873771fe6b9SJerome Glisse 
874771fe6b9SJerome Glisse static const struct drm_encoder_helper_funcs radeon_legacy_tmds_int_helper_funcs = {
875771fe6b9SJerome Glisse 	.dpms = radeon_legacy_tmds_int_dpms,
87680297e87SAlex Deucher 	.mode_fixup = radeon_legacy_mode_fixup,
877771fe6b9SJerome Glisse 	.prepare = radeon_legacy_tmds_int_prepare,
878771fe6b9SJerome Glisse 	.mode_set = radeon_legacy_tmds_int_mode_set,
879771fe6b9SJerome Glisse 	.commit = radeon_legacy_tmds_int_commit,
8804ce001abSDave Airlie 	.disable = radeon_legacy_encoder_disable,
881771fe6b9SJerome Glisse };
882771fe6b9SJerome Glisse 
883771fe6b9SJerome Glisse 
884771fe6b9SJerome Glisse static const struct drm_encoder_funcs radeon_legacy_tmds_int_enc_funcs = {
885771fe6b9SJerome Glisse 	.destroy = radeon_enc_destroy,
886771fe6b9SJerome Glisse };
887771fe6b9SJerome Glisse 
radeon_legacy_tmds_ext_dpms(struct drm_encoder * encoder,int mode)888771fe6b9SJerome Glisse static void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode)
889771fe6b9SJerome Glisse {
890771fe6b9SJerome Glisse 	struct drm_device *dev = encoder->dev;
891771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
892771fe6b9SJerome Glisse 	uint32_t fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
893d9fdaafbSDave Airlie 	DRM_DEBUG_KMS("\n");
894771fe6b9SJerome Glisse 
895771fe6b9SJerome Glisse 	switch (mode) {
896771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_ON:
897771fe6b9SJerome Glisse 		fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN;
898771fe6b9SJerome Glisse 		fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN);
899771fe6b9SJerome Glisse 		break;
900771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_STANDBY:
901771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_SUSPEND:
902771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_OFF:
903771fe6b9SJerome Glisse 		fp2_gen_cntl |= RADEON_FP2_BLANK_EN;
904771fe6b9SJerome Glisse 		fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN);
905771fe6b9SJerome Glisse 		break;
906771fe6b9SJerome Glisse 	}
907771fe6b9SJerome Glisse 
908771fe6b9SJerome Glisse 	WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
909771fe6b9SJerome Glisse 
910771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
911771fe6b9SJerome Glisse 		radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
912771fe6b9SJerome Glisse 	else
913771fe6b9SJerome Glisse 		radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
914c913e23aSRafał Miłecki 
915771fe6b9SJerome Glisse }
916771fe6b9SJerome Glisse 
radeon_legacy_tmds_ext_prepare(struct drm_encoder * encoder)917771fe6b9SJerome Glisse static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder)
918771fe6b9SJerome Glisse {
919771fe6b9SJerome Glisse 	struct radeon_device *rdev = encoder->dev->dev_private;
920771fe6b9SJerome Glisse 
921771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
922771fe6b9SJerome Glisse 		radeon_atom_output_lock(encoder, true);
923771fe6b9SJerome Glisse 	else
924771fe6b9SJerome Glisse 		radeon_combios_output_lock(encoder, true);
925771fe6b9SJerome Glisse 	radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_OFF);
926771fe6b9SJerome Glisse }
927771fe6b9SJerome Glisse 
radeon_legacy_tmds_ext_commit(struct drm_encoder * encoder)928771fe6b9SJerome Glisse static void radeon_legacy_tmds_ext_commit(struct drm_encoder *encoder)
929771fe6b9SJerome Glisse {
930771fe6b9SJerome Glisse 	struct radeon_device *rdev = encoder->dev->dev_private;
931771fe6b9SJerome Glisse 	radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_ON);
932771fe6b9SJerome Glisse 
933771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
934771fe6b9SJerome Glisse 		radeon_atom_output_lock(encoder, false);
935771fe6b9SJerome Glisse 	else
936771fe6b9SJerome Glisse 		radeon_combios_output_lock(encoder, false);
937771fe6b9SJerome Glisse }
938771fe6b9SJerome Glisse 
radeon_legacy_tmds_ext_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)939771fe6b9SJerome Glisse static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder,
940771fe6b9SJerome Glisse 					    struct drm_display_mode *mode,
941771fe6b9SJerome Glisse 					    struct drm_display_mode *adjusted_mode)
942771fe6b9SJerome Glisse {
943771fe6b9SJerome Glisse 	struct drm_device *dev = encoder->dev;
944771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
945771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
946771fe6b9SJerome Glisse 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
947771fe6b9SJerome Glisse 	uint32_t fp2_gen_cntl;
948771fe6b9SJerome Glisse 
949d9fdaafbSDave Airlie 	DRM_DEBUG_KMS("\n");
950771fe6b9SJerome Glisse 
951771fe6b9SJerome Glisse 	if (rdev->is_atom_bios) {
952771fe6b9SJerome Glisse 		radeon_encoder->pixel_clock = adjusted_mode->clock;
95399999aaaSAlex Deucher 		atombios_dvo_setup(encoder, ATOM_ENABLE);
954771fe6b9SJerome Glisse 		fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
955771fe6b9SJerome Glisse 	} else {
956771fe6b9SJerome Glisse 		fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
957771fe6b9SJerome Glisse 
958771fe6b9SJerome Glisse 		if (1) /*  FIXME rgbBits == 8 */
959771fe6b9SJerome Glisse 			fp2_gen_cntl |= RADEON_FP2_PANEL_FORMAT; /* 24 bit format, */
960771fe6b9SJerome Glisse 		else
961771fe6b9SJerome Glisse 			fp2_gen_cntl &= ~RADEON_FP2_PANEL_FORMAT;/* 18 bit format, */
962771fe6b9SJerome Glisse 
963771fe6b9SJerome Glisse 		fp2_gen_cntl &= ~(RADEON_FP2_ON |
964771fe6b9SJerome Glisse 				  RADEON_FP2_DVO_EN |
965771fe6b9SJerome Glisse 				  RADEON_FP2_DVO_RATE_SEL_SDR);
966771fe6b9SJerome Glisse 
967771fe6b9SJerome Glisse 		/* XXX: these are oem specific */
968771fe6b9SJerome Glisse 		if (ASIC_IS_R300(rdev)) {
969d86a4126SThomas Zimmermann 			if ((rdev->pdev->device == 0x4850) &&
970d86a4126SThomas Zimmermann 			    (rdev->pdev->subsystem_vendor == 0x1028) &&
971d86a4126SThomas Zimmermann 			    (rdev->pdev->subsystem_device == 0x2001)) /* Dell Inspiron 8600 */
972771fe6b9SJerome Glisse 				fp2_gen_cntl |= R300_FP2_DVO_CLOCK_MODE_SINGLE;
973771fe6b9SJerome Glisse 			else
974771fe6b9SJerome Glisse 				fp2_gen_cntl |= RADEON_FP2_PAD_FLOP_EN | R300_FP2_DVO_CLOCK_MODE_SINGLE;
975771fe6b9SJerome Glisse 
976771fe6b9SJerome Glisse 			/*if (mode->clock > 165000)
977771fe6b9SJerome Glisse 			  fp2_gen_cntl |= R300_FP2_DVO_DUAL_CHANNEL_EN;*/
978771fe6b9SJerome Glisse 		}
979fcec570bSAlex Deucher 		if (!radeon_combios_external_tmds_setup(encoder))
980fcec570bSAlex Deucher 			radeon_external_tmds_setup(encoder);
981771fe6b9SJerome Glisse 	}
982771fe6b9SJerome Glisse 
983771fe6b9SJerome Glisse 	if (radeon_crtc->crtc_id == 0) {
984771fe6b9SJerome Glisse 		if ((rdev->family == CHIP_R200) || ASIC_IS_R300(rdev)) {
985771fe6b9SJerome Glisse 			fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK;
986c93bb85bSJerome Glisse 			if (radeon_encoder->rmx_type != RMX_OFF)
987771fe6b9SJerome Glisse 				fp2_gen_cntl |= R200_FP2_SOURCE_SEL_RMX;
988771fe6b9SJerome Glisse 			else
989771fe6b9SJerome Glisse 				fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC1;
990771fe6b9SJerome Glisse 		} else
991771fe6b9SJerome Glisse 			fp2_gen_cntl &= ~RADEON_FP2_SRC_SEL_CRTC2;
992771fe6b9SJerome Glisse 	} else {
993771fe6b9SJerome Glisse 		if ((rdev->family == CHIP_R200) || ASIC_IS_R300(rdev)) {
994771fe6b9SJerome Glisse 			fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK;
995771fe6b9SJerome Glisse 			fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2;
996771fe6b9SJerome Glisse 		} else
997771fe6b9SJerome Glisse 			fp2_gen_cntl |= RADEON_FP2_SRC_SEL_CRTC2;
998771fe6b9SJerome Glisse 	}
999771fe6b9SJerome Glisse 
1000771fe6b9SJerome Glisse 	WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
1001771fe6b9SJerome Glisse 
1002771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
1003771fe6b9SJerome Glisse 		radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
1004771fe6b9SJerome Glisse 	else
1005771fe6b9SJerome Glisse 		radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
1006771fe6b9SJerome Glisse }
1007771fe6b9SJerome Glisse 
radeon_ext_tmds_enc_destroy(struct drm_encoder * encoder)1008fcec570bSAlex Deucher static void radeon_ext_tmds_enc_destroy(struct drm_encoder *encoder)
1009fcec570bSAlex Deucher {
1010fcec570bSAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
101108291847SEgbert Eich 	/* don't destroy the i2c bus record here, this will be done in radeon_i2c_fini */
1012fcec570bSAlex Deucher 	kfree(radeon_encoder->enc_priv);
1013fcec570bSAlex Deucher 	drm_encoder_cleanup(encoder);
1014fcec570bSAlex Deucher 	kfree(radeon_encoder);
1015fcec570bSAlex Deucher }
1016fcec570bSAlex Deucher 
1017771fe6b9SJerome Glisse static const struct drm_encoder_helper_funcs radeon_legacy_tmds_ext_helper_funcs = {
1018771fe6b9SJerome Glisse 	.dpms = radeon_legacy_tmds_ext_dpms,
101980297e87SAlex Deucher 	.mode_fixup = radeon_legacy_mode_fixup,
1020771fe6b9SJerome Glisse 	.prepare = radeon_legacy_tmds_ext_prepare,
1021771fe6b9SJerome Glisse 	.mode_set = radeon_legacy_tmds_ext_mode_set,
1022771fe6b9SJerome Glisse 	.commit = radeon_legacy_tmds_ext_commit,
10234ce001abSDave Airlie 	.disable = radeon_legacy_encoder_disable,
1024771fe6b9SJerome Glisse };
1025771fe6b9SJerome Glisse 
1026771fe6b9SJerome Glisse 
1027771fe6b9SJerome Glisse static const struct drm_encoder_funcs radeon_legacy_tmds_ext_enc_funcs = {
1028fcec570bSAlex Deucher 	.destroy = radeon_ext_tmds_enc_destroy,
1029771fe6b9SJerome Glisse };
1030771fe6b9SJerome Glisse 
radeon_legacy_tv_dac_dpms(struct drm_encoder * encoder,int mode)1031771fe6b9SJerome Glisse static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode)
1032771fe6b9SJerome Glisse {
1033771fe6b9SJerome Glisse 	struct drm_device *dev = encoder->dev;
1034771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
10354ce001abSDave Airlie 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
1036771fe6b9SJerome Glisse 	uint32_t fp2_gen_cntl = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0;
10374ce001abSDave Airlie 	uint32_t tv_master_cntl = 0;
10384ce001abSDave Airlie 	bool is_tv;
1039d9fdaafbSDave Airlie 	DRM_DEBUG_KMS("\n");
1040771fe6b9SJerome Glisse 
10414ce001abSDave Airlie 	is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false;
10424ce001abSDave Airlie 
1043771fe6b9SJerome Glisse 	if (rdev->family == CHIP_R200)
1044771fe6b9SJerome Glisse 		fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
1045771fe6b9SJerome Glisse 	else {
10464ce001abSDave Airlie 		if (is_tv)
10474ce001abSDave Airlie 			tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL);
10484ce001abSDave Airlie 		else
1049771fe6b9SJerome Glisse 			crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
1050771fe6b9SJerome Glisse 		tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
1051771fe6b9SJerome Glisse 	}
1052771fe6b9SJerome Glisse 
1053771fe6b9SJerome Glisse 	switch (mode) {
1054771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_ON:
1055771fe6b9SJerome Glisse 		if (rdev->family == CHIP_R200) {
1056771fe6b9SJerome Glisse 			fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN);
1057771fe6b9SJerome Glisse 		} else {
10584ce001abSDave Airlie 			if (is_tv)
10594ce001abSDave Airlie 				tv_master_cntl |= RADEON_TV_ON;
10604ce001abSDave Airlie 			else
1061771fe6b9SJerome Glisse 				crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON;
10624ce001abSDave Airlie 
1063771fe6b9SJerome Glisse 			if (rdev->family == CHIP_R420 ||
1064771fe6b9SJerome Glisse 			    rdev->family == CHIP_R423 ||
1065771fe6b9SJerome Glisse 			    rdev->family == CHIP_RV410)
1066771fe6b9SJerome Glisse 				tv_dac_cntl &= ~(R420_TV_DAC_RDACPD |
1067771fe6b9SJerome Glisse 						 R420_TV_DAC_GDACPD |
1068771fe6b9SJerome Glisse 						 R420_TV_DAC_BDACPD |
1069771fe6b9SJerome Glisse 						 RADEON_TV_DAC_BGSLEEP);
1070771fe6b9SJerome Glisse 			else
1071771fe6b9SJerome Glisse 				tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD |
1072771fe6b9SJerome Glisse 						 RADEON_TV_DAC_GDACPD |
1073771fe6b9SJerome Glisse 						 RADEON_TV_DAC_BDACPD |
1074771fe6b9SJerome Glisse 						 RADEON_TV_DAC_BGSLEEP);
1075771fe6b9SJerome Glisse 		}
1076771fe6b9SJerome Glisse 		break;
1077771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_STANDBY:
1078771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_SUSPEND:
1079771fe6b9SJerome Glisse 	case DRM_MODE_DPMS_OFF:
1080771fe6b9SJerome Glisse 		if (rdev->family == CHIP_R200)
1081771fe6b9SJerome Glisse 			fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN);
1082771fe6b9SJerome Glisse 		else {
10834ce001abSDave Airlie 			if (is_tv)
10844ce001abSDave Airlie 				tv_master_cntl &= ~RADEON_TV_ON;
10854ce001abSDave Airlie 			else
1086771fe6b9SJerome Glisse 				crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON;
10874ce001abSDave Airlie 
1088771fe6b9SJerome Glisse 			if (rdev->family == CHIP_R420 ||
1089771fe6b9SJerome Glisse 			    rdev->family == CHIP_R423 ||
1090771fe6b9SJerome Glisse 			    rdev->family == CHIP_RV410)
1091771fe6b9SJerome Glisse 				tv_dac_cntl |= (R420_TV_DAC_RDACPD |
1092771fe6b9SJerome Glisse 						R420_TV_DAC_GDACPD |
1093771fe6b9SJerome Glisse 						R420_TV_DAC_BDACPD |
1094771fe6b9SJerome Glisse 						RADEON_TV_DAC_BGSLEEP);
1095771fe6b9SJerome Glisse 			else
1096771fe6b9SJerome Glisse 				tv_dac_cntl |= (RADEON_TV_DAC_RDACPD |
1097771fe6b9SJerome Glisse 						RADEON_TV_DAC_GDACPD |
1098771fe6b9SJerome Glisse 						RADEON_TV_DAC_BDACPD |
1099771fe6b9SJerome Glisse 						RADEON_TV_DAC_BGSLEEP);
1100771fe6b9SJerome Glisse 		}
1101771fe6b9SJerome Glisse 		break;
1102771fe6b9SJerome Glisse 	}
1103771fe6b9SJerome Glisse 
1104771fe6b9SJerome Glisse 	if (rdev->family == CHIP_R200) {
1105771fe6b9SJerome Glisse 		WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
1106771fe6b9SJerome Glisse 	} else {
11074ce001abSDave Airlie 		if (is_tv)
11084ce001abSDave Airlie 			WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl);
1109f8c4d701SEgbert Eich 		/* handled in radeon_crtc_dpms() */
1110f8c4d701SEgbert Eich 		else if (!(rdev->flags & RADEON_SINGLE_CRTC))
1111771fe6b9SJerome Glisse 			WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
1112771fe6b9SJerome Glisse 		WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
1113771fe6b9SJerome Glisse 	}
1114771fe6b9SJerome Glisse 
1115771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
1116771fe6b9SJerome Glisse 		radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
1117771fe6b9SJerome Glisse 	else
1118771fe6b9SJerome Glisse 		radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
1119c913e23aSRafał Miłecki 
1120771fe6b9SJerome Glisse }
1121771fe6b9SJerome Glisse 
radeon_legacy_tv_dac_prepare(struct drm_encoder * encoder)1122771fe6b9SJerome Glisse static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder)
1123771fe6b9SJerome Glisse {
1124771fe6b9SJerome Glisse 	struct radeon_device *rdev = encoder->dev->dev_private;
1125771fe6b9SJerome Glisse 
1126771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
1127771fe6b9SJerome Glisse 		radeon_atom_output_lock(encoder, true);
1128771fe6b9SJerome Glisse 	else
1129771fe6b9SJerome Glisse 		radeon_combios_output_lock(encoder, true);
1130771fe6b9SJerome Glisse 	radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_OFF);
1131771fe6b9SJerome Glisse }
1132771fe6b9SJerome Glisse 
radeon_legacy_tv_dac_commit(struct drm_encoder * encoder)1133771fe6b9SJerome Glisse static void radeon_legacy_tv_dac_commit(struct drm_encoder *encoder)
1134771fe6b9SJerome Glisse {
1135771fe6b9SJerome Glisse 	struct radeon_device *rdev = encoder->dev->dev_private;
1136771fe6b9SJerome Glisse 
1137771fe6b9SJerome Glisse 	radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_ON);
1138771fe6b9SJerome Glisse 
1139771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
1140771fe6b9SJerome Glisse 		radeon_atom_output_lock(encoder, true);
1141771fe6b9SJerome Glisse 	else
1142771fe6b9SJerome Glisse 		radeon_combios_output_lock(encoder, true);
1143771fe6b9SJerome Glisse }
1144771fe6b9SJerome Glisse 
radeon_legacy_tv_dac_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)1145771fe6b9SJerome Glisse static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,
1146771fe6b9SJerome Glisse 		struct drm_display_mode *mode,
1147771fe6b9SJerome Glisse 		struct drm_display_mode *adjusted_mode)
1148771fe6b9SJerome Glisse {
1149771fe6b9SJerome Glisse 	struct drm_device *dev = encoder->dev;
1150771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
1151771fe6b9SJerome Glisse 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
1152771fe6b9SJerome Glisse 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
11534ce001abSDave Airlie 	struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
1154771fe6b9SJerome Glisse 	uint32_t tv_dac_cntl, gpiopad_a = 0, dac2_cntl, disp_output_cntl = 0;
11554ce001abSDave Airlie 	uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0, disp_tv_out_cntl = 0;
11564ce001abSDave Airlie 	bool is_tv = false;
1157771fe6b9SJerome Glisse 
1158d9fdaafbSDave Airlie 	DRM_DEBUG_KMS("\n");
1159771fe6b9SJerome Glisse 
11604ce001abSDave Airlie 	is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false;
11614ce001abSDave Airlie 
1162771fe6b9SJerome Glisse 	if (rdev->family != CHIP_R200) {
1163771fe6b9SJerome Glisse 		tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
1164771fe6b9SJerome Glisse 		if (rdev->family == CHIP_R420 ||
1165771fe6b9SJerome Glisse 		    rdev->family == CHIP_R423 ||
1166771fe6b9SJerome Glisse 		    rdev->family == CHIP_RV410) {
1167771fe6b9SJerome Glisse 			tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK |
1168771fe6b9SJerome Glisse 					 RADEON_TV_DAC_BGADJ_MASK |
1169771fe6b9SJerome Glisse 					 R420_TV_DAC_DACADJ_MASK |
1170771fe6b9SJerome Glisse 					 R420_TV_DAC_RDACPD |
1171771fe6b9SJerome Glisse 					 R420_TV_DAC_GDACPD |
1172aa96e341SRoel Kluin 					 R420_TV_DAC_BDACPD |
1173771fe6b9SJerome Glisse 					 R420_TV_DAC_TVENABLE);
1174771fe6b9SJerome Glisse 		} else {
1175771fe6b9SJerome Glisse 			tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK |
1176771fe6b9SJerome Glisse 					 RADEON_TV_DAC_BGADJ_MASK |
1177771fe6b9SJerome Glisse 					 RADEON_TV_DAC_DACADJ_MASK |
1178771fe6b9SJerome Glisse 					 RADEON_TV_DAC_RDACPD |
1179771fe6b9SJerome Glisse 					 RADEON_TV_DAC_GDACPD |
1180aa96e341SRoel Kluin 					 RADEON_TV_DAC_BDACPD);
1181771fe6b9SJerome Glisse 		}
1182771fe6b9SJerome Glisse 
118377416187SAlex Deucher 		tv_dac_cntl |= RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD;
118477416187SAlex Deucher 
118577416187SAlex Deucher 		if (is_tv) {
118677416187SAlex Deucher 			if (tv_dac->tv_std == TV_STD_NTSC ||
118777416187SAlex Deucher 			    tv_dac->tv_std == TV_STD_NTSC_J ||
118877416187SAlex Deucher 			    tv_dac->tv_std == TV_STD_PAL_M ||
118977416187SAlex Deucher 			    tv_dac->tv_std == TV_STD_PAL_60)
119077416187SAlex Deucher 				tv_dac_cntl |= tv_dac->ntsc_tvdac_adj;
119177416187SAlex Deucher 			else
119277416187SAlex Deucher 				tv_dac_cntl |= tv_dac->pal_tvdac_adj;
119377416187SAlex Deucher 
119477416187SAlex Deucher 			if (tv_dac->tv_std == TV_STD_NTSC ||
119577416187SAlex Deucher 			    tv_dac->tv_std == TV_STD_NTSC_J)
119677416187SAlex Deucher 				tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC;
119777416187SAlex Deucher 			else
119877416187SAlex Deucher 				tv_dac_cntl |= RADEON_TV_DAC_STD_PAL;
1199771fe6b9SJerome Glisse 		} else
120077416187SAlex Deucher 			tv_dac_cntl |= (RADEON_TV_DAC_STD_PS2 |
120177416187SAlex Deucher 					tv_dac->ps2_tvdac_adj);
1202771fe6b9SJerome Glisse 
1203771fe6b9SJerome Glisse 		WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
1204771fe6b9SJerome Glisse 	}
1205771fe6b9SJerome Glisse 
1206771fe6b9SJerome Glisse 	if (ASIC_IS_R300(rdev)) {
1207771fe6b9SJerome Glisse 		gpiopad_a = RREG32(RADEON_GPIOPAD_A) | 1;
1208771fe6b9SJerome Glisse 		disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL);
12091ab064deSDave Airlie 	} else if (rdev->family != CHIP_R200)
1210771fe6b9SJerome Glisse 		disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG);
12111ab064deSDave Airlie 	else if (rdev->family == CHIP_R200)
12124ce001abSDave Airlie 		fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
12134ce001abSDave Airlie 
12141ab064deSDave Airlie 	if (rdev->family >= CHIP_R200)
12151ab064deSDave Airlie 		disp_tv_out_cntl = RREG32(RADEON_DISP_TV_OUT_CNTL);
12161ab064deSDave Airlie 
12174ce001abSDave Airlie 	if (is_tv) {
12184ce001abSDave Airlie 		uint32_t dac_cntl;
12194ce001abSDave Airlie 
12204ce001abSDave Airlie 		dac_cntl = RREG32(RADEON_DAC_CNTL);
12214ce001abSDave Airlie 		dac_cntl &= ~RADEON_DAC_TVO_EN;
12224ce001abSDave Airlie 		WREG32(RADEON_DAC_CNTL, dac_cntl);
12234ce001abSDave Airlie 
12244ce001abSDave Airlie 		if (ASIC_IS_R300(rdev))
12254ce001abSDave Airlie 			gpiopad_a = RREG32(RADEON_GPIOPAD_A) & ~1;
12264ce001abSDave Airlie 
12274ce001abSDave Airlie 		dac2_cntl = RREG32(RADEON_DAC_CNTL2) & ~RADEON_DAC2_DAC2_CLK_SEL;
12284ce001abSDave Airlie 		if (radeon_crtc->crtc_id == 0) {
12294ce001abSDave Airlie 			if (ASIC_IS_R300(rdev)) {
12304ce001abSDave Airlie 				disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
12314ce001abSDave Airlie 				disp_output_cntl |= (RADEON_DISP_TVDAC_SOURCE_CRTC |
12324ce001abSDave Airlie 						     RADEON_DISP_TV_SOURCE_CRTC);
12334ce001abSDave Airlie 			}
12344ce001abSDave Airlie 			if (rdev->family >= CHIP_R200) {
12354ce001abSDave Airlie 				disp_tv_out_cntl &= ~RADEON_DISP_TV_PATH_SRC_CRTC2;
12364ce001abSDave Airlie 			} else {
12374ce001abSDave Airlie 				disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
12384ce001abSDave Airlie 			}
12394ce001abSDave Airlie 		} else {
12404ce001abSDave Airlie 			if (ASIC_IS_R300(rdev)) {
12414ce001abSDave Airlie 				disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
12424ce001abSDave Airlie 				disp_output_cntl |= RADEON_DISP_TV_SOURCE_CRTC;
12434ce001abSDave Airlie 			}
12444ce001abSDave Airlie 			if (rdev->family >= CHIP_R200) {
12454ce001abSDave Airlie 				disp_tv_out_cntl |= RADEON_DISP_TV_PATH_SRC_CRTC2;
12464ce001abSDave Airlie 			} else {
12474ce001abSDave Airlie 				disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
12484ce001abSDave Airlie 			}
12494ce001abSDave Airlie 		}
12504ce001abSDave Airlie 		WREG32(RADEON_DAC_CNTL2, dac2_cntl);
12514ce001abSDave Airlie 	} else {
12524ce001abSDave Airlie 
1253771fe6b9SJerome Glisse 		dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC2_CLK_SEL;
1254771fe6b9SJerome Glisse 
1255771fe6b9SJerome Glisse 		if (radeon_crtc->crtc_id == 0) {
1256771fe6b9SJerome Glisse 			if (ASIC_IS_R300(rdev)) {
1257771fe6b9SJerome Glisse 				disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
1258771fe6b9SJerome Glisse 				disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC;
1259771fe6b9SJerome Glisse 			} else if (rdev->family == CHIP_R200) {
1260771fe6b9SJerome Glisse 				fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK |
1261771fe6b9SJerome Glisse 						  RADEON_FP2_DVO_RATE_SEL_SDR);
1262771fe6b9SJerome Glisse 			} else
1263771fe6b9SJerome Glisse 				disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
1264771fe6b9SJerome Glisse 		} else {
1265771fe6b9SJerome Glisse 			if (ASIC_IS_R300(rdev)) {
1266771fe6b9SJerome Glisse 				disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
1267771fe6b9SJerome Glisse 				disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC2;
1268771fe6b9SJerome Glisse 			} else if (rdev->family == CHIP_R200) {
1269771fe6b9SJerome Glisse 				fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK |
1270771fe6b9SJerome Glisse 						  RADEON_FP2_DVO_RATE_SEL_SDR);
1271771fe6b9SJerome Glisse 				fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2;
1272771fe6b9SJerome Glisse 			} else
1273771fe6b9SJerome Glisse 				disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
1274771fe6b9SJerome Glisse 		}
1275771fe6b9SJerome Glisse 		WREG32(RADEON_DAC_CNTL2, dac2_cntl);
12764ce001abSDave Airlie 	}
1277771fe6b9SJerome Glisse 
1278771fe6b9SJerome Glisse 	if (ASIC_IS_R300(rdev)) {
1279771fe6b9SJerome Glisse 		WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1);
12804ce001abSDave Airlie 		WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
12811ab064deSDave Airlie 	} else if (rdev->family != CHIP_R200)
12821ab064deSDave Airlie 		WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug);
12831ab064deSDave Airlie 	else if (rdev->family == CHIP_R200)
12841ab064deSDave Airlie 		WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
12854ce001abSDave Airlie 
12864ce001abSDave Airlie 	if (rdev->family >= CHIP_R200)
12874ce001abSDave Airlie 		WREG32(RADEON_DISP_TV_OUT_CNTL, disp_tv_out_cntl);
12884ce001abSDave Airlie 
12894ce001abSDave Airlie 	if (is_tv)
12904ce001abSDave Airlie 		radeon_legacy_tv_mode_set(encoder, mode, adjusted_mode);
12914ce001abSDave Airlie 
1292771fe6b9SJerome Glisse 	if (rdev->is_atom_bios)
1293771fe6b9SJerome Glisse 		radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
1294771fe6b9SJerome Glisse 	else
1295771fe6b9SJerome Glisse 		radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
1296771fe6b9SJerome Glisse 
1297771fe6b9SJerome Glisse }
1298771fe6b9SJerome Glisse 
r300_legacy_tv_detect(struct drm_encoder * encoder,struct drm_connector * connector)12994ce001abSDave Airlie static bool r300_legacy_tv_detect(struct drm_encoder *encoder,
13004ce001abSDave Airlie 				  struct drm_connector *connector)
13014ce001abSDave Airlie {
13024ce001abSDave Airlie 	struct drm_device *dev = encoder->dev;
13034ce001abSDave Airlie 	struct radeon_device *rdev = dev->dev_private;
13044ce001abSDave Airlie 	uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl;
13054ce001abSDave Airlie 	uint32_t disp_output_cntl, gpiopad_a, tmp;
13064ce001abSDave Airlie 	bool found = false;
13074ce001abSDave Airlie 
13084ce001abSDave Airlie 	/* save regs needed */
13094ce001abSDave Airlie 	gpiopad_a = RREG32(RADEON_GPIOPAD_A);
13104ce001abSDave Airlie 	dac_cntl2 = RREG32(RADEON_DAC_CNTL2);
13114ce001abSDave Airlie 	crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
13124ce001abSDave Airlie 	dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL);
13134ce001abSDave Airlie 	tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
13144ce001abSDave Airlie 	disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL);
13154ce001abSDave Airlie 
13164ce001abSDave Airlie 	WREG32_P(RADEON_GPIOPAD_A, 0, ~1);
13174ce001abSDave Airlie 
13184ce001abSDave Airlie 	WREG32(RADEON_DAC_CNTL2, RADEON_DAC2_DAC2_CLK_SEL);
13194ce001abSDave Airlie 
13204ce001abSDave Airlie 	WREG32(RADEON_CRTC2_GEN_CNTL,
13214ce001abSDave Airlie 	       RADEON_CRTC2_CRT2_ON | RADEON_CRTC2_VSYNC_TRISTAT);
13224ce001abSDave Airlie 
13234ce001abSDave Airlie 	tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK;
13244ce001abSDave Airlie 	tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2;
13254ce001abSDave Airlie 	WREG32(RADEON_DISP_OUTPUT_CNTL, tmp);
13264ce001abSDave Airlie 
13274ce001abSDave Airlie 	WREG32(RADEON_DAC_EXT_CNTL,
13284ce001abSDave Airlie 	       RADEON_DAC2_FORCE_BLANK_OFF_EN |
13294ce001abSDave Airlie 	       RADEON_DAC2_FORCE_DATA_EN |
13304ce001abSDave Airlie 	       RADEON_DAC_FORCE_DATA_SEL_RGB |
13314ce001abSDave Airlie 	       (0xec << RADEON_DAC_FORCE_DATA_SHIFT));
13324ce001abSDave Airlie 
13334ce001abSDave Airlie 	WREG32(RADEON_TV_DAC_CNTL,
13344ce001abSDave Airlie 	       RADEON_TV_DAC_STD_NTSC |
13354ce001abSDave Airlie 	       (8 << RADEON_TV_DAC_BGADJ_SHIFT) |
13364ce001abSDave Airlie 	       (6 << RADEON_TV_DAC_DACADJ_SHIFT));
13374ce001abSDave Airlie 
13384ce001abSDave Airlie 	RREG32(RADEON_TV_DAC_CNTL);
13394ce001abSDave Airlie 	mdelay(4);
13404ce001abSDave Airlie 
13414ce001abSDave Airlie 	WREG32(RADEON_TV_DAC_CNTL,
13424ce001abSDave Airlie 	       RADEON_TV_DAC_NBLANK |
13434ce001abSDave Airlie 	       RADEON_TV_DAC_NHOLD |
13444ce001abSDave Airlie 	       RADEON_TV_MONITOR_DETECT_EN |
13454ce001abSDave Airlie 	       RADEON_TV_DAC_STD_NTSC |
13464ce001abSDave Airlie 	       (8 << RADEON_TV_DAC_BGADJ_SHIFT) |
13474ce001abSDave Airlie 	       (6 << RADEON_TV_DAC_DACADJ_SHIFT));
13484ce001abSDave Airlie 
13494ce001abSDave Airlie 	RREG32(RADEON_TV_DAC_CNTL);
13504ce001abSDave Airlie 	mdelay(6);
13514ce001abSDave Airlie 
13524ce001abSDave Airlie 	tmp = RREG32(RADEON_TV_DAC_CNTL);
13534ce001abSDave Airlie 	if ((tmp & RADEON_TV_DAC_GDACDET) != 0) {
13544ce001abSDave Airlie 		found = true;
1355d9fdaafbSDave Airlie 		DRM_DEBUG_KMS("S-video TV connection detected\n");
13564ce001abSDave Airlie 	} else if ((tmp & RADEON_TV_DAC_BDACDET) != 0) {
13574ce001abSDave Airlie 		found = true;
1358d9fdaafbSDave Airlie 		DRM_DEBUG_KMS("Composite TV connection detected\n");
13594ce001abSDave Airlie 	}
13604ce001abSDave Airlie 
13614ce001abSDave Airlie 	WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
13624ce001abSDave Airlie 	WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl);
13634ce001abSDave Airlie 	WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
13644ce001abSDave Airlie 	WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
13654ce001abSDave Airlie 	WREG32(RADEON_DAC_CNTL2, dac_cntl2);
13664ce001abSDave Airlie 	WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1);
13674ce001abSDave Airlie 	return found;
13684ce001abSDave Airlie }
13694ce001abSDave Airlie 
radeon_legacy_tv_detect(struct drm_encoder * encoder,struct drm_connector * connector)13704ce001abSDave Airlie static bool radeon_legacy_tv_detect(struct drm_encoder *encoder,
13714ce001abSDave Airlie 				    struct drm_connector *connector)
13724ce001abSDave Airlie {
13734ce001abSDave Airlie 	struct drm_device *dev = encoder->dev;
13744ce001abSDave Airlie 	struct radeon_device *rdev = dev->dev_private;
13754ce001abSDave Airlie 	uint32_t tv_dac_cntl, dac_cntl2;
13764ce001abSDave Airlie 	uint32_t config_cntl, tv_pre_dac_mux_cntl, tv_master_cntl, tmp;
13774ce001abSDave Airlie 	bool found = false;
13784ce001abSDave Airlie 
13794ce001abSDave Airlie 	if (ASIC_IS_R300(rdev))
13804ce001abSDave Airlie 		return r300_legacy_tv_detect(encoder, connector);
13814ce001abSDave Airlie 
13824ce001abSDave Airlie 	dac_cntl2 = RREG32(RADEON_DAC_CNTL2);
13834ce001abSDave Airlie 	tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL);
13844ce001abSDave Airlie 	tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
13854ce001abSDave Airlie 	config_cntl = RREG32(RADEON_CONFIG_CNTL);
13864ce001abSDave Airlie 	tv_pre_dac_mux_cntl = RREG32(RADEON_TV_PRE_DAC_MUX_CNTL);
13874ce001abSDave Airlie 
13884ce001abSDave Airlie 	tmp = dac_cntl2 & ~RADEON_DAC2_DAC2_CLK_SEL;
13894ce001abSDave Airlie 	WREG32(RADEON_DAC_CNTL2, tmp);
13904ce001abSDave Airlie 
13914ce001abSDave Airlie 	tmp = tv_master_cntl | RADEON_TV_ON;
13924ce001abSDave Airlie 	tmp &= ~(RADEON_TV_ASYNC_RST |
13934ce001abSDave Airlie 		 RADEON_RESTART_PHASE_FIX |
13944ce001abSDave Airlie 		 RADEON_CRT_FIFO_CE_EN |
13954ce001abSDave Airlie 		 RADEON_TV_FIFO_CE_EN |
13964ce001abSDave Airlie 		 RADEON_RE_SYNC_NOW_SEL_MASK);
13974ce001abSDave Airlie 	tmp |= RADEON_TV_FIFO_ASYNC_RST | RADEON_CRT_ASYNC_RST;
13984ce001abSDave Airlie 	WREG32(RADEON_TV_MASTER_CNTL, tmp);
13994ce001abSDave Airlie 
14004ce001abSDave Airlie 	tmp = RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD |
14014ce001abSDave Airlie 		RADEON_TV_MONITOR_DETECT_EN | RADEON_TV_DAC_STD_NTSC |
14024ce001abSDave Airlie 		(8 << RADEON_TV_DAC_BGADJ_SHIFT);
14034ce001abSDave Airlie 
14044ce001abSDave Airlie 	if (config_cntl & RADEON_CFG_ATI_REV_ID_MASK)
14054ce001abSDave Airlie 		tmp |= (4 << RADEON_TV_DAC_DACADJ_SHIFT);
14064ce001abSDave Airlie 	else
14074ce001abSDave Airlie 		tmp |= (8 << RADEON_TV_DAC_DACADJ_SHIFT);
14084ce001abSDave Airlie 	WREG32(RADEON_TV_DAC_CNTL, tmp);
14094ce001abSDave Airlie 
14104ce001abSDave Airlie 	tmp = RADEON_C_GRN_EN | RADEON_CMP_BLU_EN |
14114ce001abSDave Airlie 		RADEON_RED_MX_FORCE_DAC_DATA |
14124ce001abSDave Airlie 		RADEON_GRN_MX_FORCE_DAC_DATA |
14134ce001abSDave Airlie 		RADEON_BLU_MX_FORCE_DAC_DATA |
14144ce001abSDave Airlie 		(0x109 << RADEON_TV_FORCE_DAC_DATA_SHIFT);
14154ce001abSDave Airlie 	WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, tmp);
14164ce001abSDave Airlie 
14174ce001abSDave Airlie 	mdelay(3);
14184ce001abSDave Airlie 	tmp = RREG32(RADEON_TV_DAC_CNTL);
14194ce001abSDave Airlie 	if (tmp & RADEON_TV_DAC_GDACDET) {
14204ce001abSDave Airlie 		found = true;
1421d9fdaafbSDave Airlie 		DRM_DEBUG_KMS("S-video TV connection detected\n");
14224ce001abSDave Airlie 	} else if ((tmp & RADEON_TV_DAC_BDACDET) != 0) {
14234ce001abSDave Airlie 		found = true;
1424d9fdaafbSDave Airlie 		DRM_DEBUG_KMS("Composite TV connection detected\n");
14254ce001abSDave Airlie 	}
14264ce001abSDave Airlie 
14274ce001abSDave Airlie 	WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, tv_pre_dac_mux_cntl);
14284ce001abSDave Airlie 	WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
14294ce001abSDave Airlie 	WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl);
14304ce001abSDave Airlie 	WREG32(RADEON_DAC_CNTL2, dac_cntl2);
14314ce001abSDave Airlie 	return found;
14324ce001abSDave Airlie }
14334ce001abSDave Airlie 
radeon_legacy_ext_dac_detect(struct drm_encoder * encoder,struct drm_connector * connector)14346d9cdfc2SAlex Deucher static bool radeon_legacy_ext_dac_detect(struct drm_encoder *encoder,
14356d9cdfc2SAlex Deucher 					 struct drm_connector *connector)
14366d9cdfc2SAlex Deucher {
14376d9cdfc2SAlex Deucher 	struct drm_device *dev = encoder->dev;
14386d9cdfc2SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
14396d9cdfc2SAlex Deucher 	uint32_t gpio_monid, fp2_gen_cntl, disp_output_cntl, crtc2_gen_cntl;
14406d9cdfc2SAlex Deucher 	uint32_t disp_lin_trans_grph_a, disp_lin_trans_grph_b, disp_lin_trans_grph_c;
14416d9cdfc2SAlex Deucher 	uint32_t disp_lin_trans_grph_d, disp_lin_trans_grph_e, disp_lin_trans_grph_f;
14426d9cdfc2SAlex Deucher 	uint32_t tmp, crtc2_h_total_disp, crtc2_v_total_disp;
14436d9cdfc2SAlex Deucher 	uint32_t crtc2_h_sync_strt_wid, crtc2_v_sync_strt_wid;
14446d9cdfc2SAlex Deucher 	bool found = false;
14456d9cdfc2SAlex Deucher 	int i;
14466d9cdfc2SAlex Deucher 
14476d9cdfc2SAlex Deucher 	/* save the regs we need */
14486d9cdfc2SAlex Deucher 	gpio_monid = RREG32(RADEON_GPIO_MONID);
14496d9cdfc2SAlex Deucher 	fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
14506d9cdfc2SAlex Deucher 	disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL);
14516d9cdfc2SAlex Deucher 	crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
14526d9cdfc2SAlex Deucher 	disp_lin_trans_grph_a = RREG32(RADEON_DISP_LIN_TRANS_GRPH_A);
14536d9cdfc2SAlex Deucher 	disp_lin_trans_grph_b = RREG32(RADEON_DISP_LIN_TRANS_GRPH_B);
14546d9cdfc2SAlex Deucher 	disp_lin_trans_grph_c = RREG32(RADEON_DISP_LIN_TRANS_GRPH_C);
14556d9cdfc2SAlex Deucher 	disp_lin_trans_grph_d = RREG32(RADEON_DISP_LIN_TRANS_GRPH_D);
14566d9cdfc2SAlex Deucher 	disp_lin_trans_grph_e = RREG32(RADEON_DISP_LIN_TRANS_GRPH_E);
14576d9cdfc2SAlex Deucher 	disp_lin_trans_grph_f = RREG32(RADEON_DISP_LIN_TRANS_GRPH_F);
14586d9cdfc2SAlex Deucher 	crtc2_h_total_disp = RREG32(RADEON_CRTC2_H_TOTAL_DISP);
14596d9cdfc2SAlex Deucher 	crtc2_v_total_disp = RREG32(RADEON_CRTC2_V_TOTAL_DISP);
14606d9cdfc2SAlex Deucher 	crtc2_h_sync_strt_wid = RREG32(RADEON_CRTC2_H_SYNC_STRT_WID);
14616d9cdfc2SAlex Deucher 	crtc2_v_sync_strt_wid = RREG32(RADEON_CRTC2_V_SYNC_STRT_WID);
14626d9cdfc2SAlex Deucher 
14636d9cdfc2SAlex Deucher 	tmp = RREG32(RADEON_GPIO_MONID);
14646d9cdfc2SAlex Deucher 	tmp &= ~RADEON_GPIO_A_0;
14656d9cdfc2SAlex Deucher 	WREG32(RADEON_GPIO_MONID, tmp);
14666d9cdfc2SAlex Deucher 
14676d9cdfc2SAlex Deucher 	WREG32(RADEON_FP2_GEN_CNTL, (RADEON_FP2_ON |
14686d9cdfc2SAlex Deucher 				     RADEON_FP2_PANEL_FORMAT |
14696d9cdfc2SAlex Deucher 				     R200_FP2_SOURCE_SEL_TRANS_UNIT |
14706d9cdfc2SAlex Deucher 				     RADEON_FP2_DVO_EN |
14716d9cdfc2SAlex Deucher 				     R200_FP2_DVO_RATE_SEL_SDR));
14726d9cdfc2SAlex Deucher 
14736d9cdfc2SAlex Deucher 	WREG32(RADEON_DISP_OUTPUT_CNTL, (RADEON_DISP_DAC_SOURCE_RMX |
14746d9cdfc2SAlex Deucher 					 RADEON_DISP_TRANS_MATRIX_GRAPHICS));
14756d9cdfc2SAlex Deucher 
14766d9cdfc2SAlex Deucher 	WREG32(RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_EN |
14776d9cdfc2SAlex Deucher 				       RADEON_CRTC2_DISP_REQ_EN_B));
14786d9cdfc2SAlex Deucher 
14796d9cdfc2SAlex Deucher 	WREG32(RADEON_DISP_LIN_TRANS_GRPH_A, 0x00000000);
14806d9cdfc2SAlex Deucher 	WREG32(RADEON_DISP_LIN_TRANS_GRPH_B, 0x000003f0);
14816d9cdfc2SAlex Deucher 	WREG32(RADEON_DISP_LIN_TRANS_GRPH_C, 0x00000000);
14826d9cdfc2SAlex Deucher 	WREG32(RADEON_DISP_LIN_TRANS_GRPH_D, 0x000003f0);
14836d9cdfc2SAlex Deucher 	WREG32(RADEON_DISP_LIN_TRANS_GRPH_E, 0x00000000);
14846d9cdfc2SAlex Deucher 	WREG32(RADEON_DISP_LIN_TRANS_GRPH_F, 0x000003f0);
14856d9cdfc2SAlex Deucher 
14866d9cdfc2SAlex Deucher 	WREG32(RADEON_CRTC2_H_TOTAL_DISP, 0x01000008);
14876d9cdfc2SAlex Deucher 	WREG32(RADEON_CRTC2_H_SYNC_STRT_WID, 0x00000800);
14886d9cdfc2SAlex Deucher 	WREG32(RADEON_CRTC2_V_TOTAL_DISP, 0x00080001);
14896d9cdfc2SAlex Deucher 	WREG32(RADEON_CRTC2_V_SYNC_STRT_WID, 0x00000080);
14906d9cdfc2SAlex Deucher 
14916d9cdfc2SAlex Deucher 	for (i = 0; i < 200; i++) {
14926d9cdfc2SAlex Deucher 		tmp = RREG32(RADEON_GPIO_MONID);
14936d9cdfc2SAlex Deucher 		if (tmp & RADEON_GPIO_Y_0)
14946d9cdfc2SAlex Deucher 			found = true;
14956d9cdfc2SAlex Deucher 
14966d9cdfc2SAlex Deucher 		if (found)
14976d9cdfc2SAlex Deucher 			break;
14986d9cdfc2SAlex Deucher 
14996d9cdfc2SAlex Deucher 		if (!drm_can_sleep())
15006d9cdfc2SAlex Deucher 			mdelay(1);
15016d9cdfc2SAlex Deucher 		else
15026d9cdfc2SAlex Deucher 			msleep(1);
15036d9cdfc2SAlex Deucher 	}
15046d9cdfc2SAlex Deucher 
15056d9cdfc2SAlex Deucher 	/* restore the regs we used */
15066d9cdfc2SAlex Deucher 	WREG32(RADEON_DISP_LIN_TRANS_GRPH_A, disp_lin_trans_grph_a);
15076d9cdfc2SAlex Deucher 	WREG32(RADEON_DISP_LIN_TRANS_GRPH_B, disp_lin_trans_grph_b);
15086d9cdfc2SAlex Deucher 	WREG32(RADEON_DISP_LIN_TRANS_GRPH_C, disp_lin_trans_grph_c);
15096d9cdfc2SAlex Deucher 	WREG32(RADEON_DISP_LIN_TRANS_GRPH_D, disp_lin_trans_grph_d);
15106d9cdfc2SAlex Deucher 	WREG32(RADEON_DISP_LIN_TRANS_GRPH_E, disp_lin_trans_grph_e);
15116d9cdfc2SAlex Deucher 	WREG32(RADEON_DISP_LIN_TRANS_GRPH_F, disp_lin_trans_grph_f);
15126d9cdfc2SAlex Deucher 	WREG32(RADEON_CRTC2_H_TOTAL_DISP, crtc2_h_total_disp);
15136d9cdfc2SAlex Deucher 	WREG32(RADEON_CRTC2_V_TOTAL_DISP, crtc2_v_total_disp);
15146d9cdfc2SAlex Deucher 	WREG32(RADEON_CRTC2_H_SYNC_STRT_WID, crtc2_h_sync_strt_wid);
15156d9cdfc2SAlex Deucher 	WREG32(RADEON_CRTC2_V_SYNC_STRT_WID, crtc2_v_sync_strt_wid);
15166d9cdfc2SAlex Deucher 	WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
15176d9cdfc2SAlex Deucher 	WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
15186d9cdfc2SAlex Deucher 	WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
15196d9cdfc2SAlex Deucher 	WREG32(RADEON_GPIO_MONID, gpio_monid);
15206d9cdfc2SAlex Deucher 
15216d9cdfc2SAlex Deucher 	return found;
15226d9cdfc2SAlex Deucher }
15236d9cdfc2SAlex Deucher 
radeon_legacy_tv_dac_detect(struct drm_encoder * encoder,struct drm_connector * connector)1524771fe6b9SJerome Glisse static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder,
1525771fe6b9SJerome Glisse 							     struct drm_connector *connector)
1526771fe6b9SJerome Glisse {
1527771fe6b9SJerome Glisse 	struct drm_device *dev = encoder->dev;
1528771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
1529701337dcSEgbert Eich 	uint32_t crtc2_gen_cntl = 0, tv_dac_cntl, dac_cntl2, dac_ext_cntl;
1530d038db86SEgbert Eich 	uint32_t gpiopad_a = 0, pixclks_cntl, tmp;
1531701337dcSEgbert Eich 	uint32_t disp_output_cntl = 0, disp_hw_debug = 0, crtc_ext_cntl = 0;
1532771fe6b9SJerome Glisse 	enum drm_connector_status found = connector_status_disconnected;
15334ce001abSDave Airlie 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
15344ce001abSDave Airlie 	struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
1535771fe6b9SJerome Glisse 	bool color = true;
1536b62e948fSDave Airlie 	struct drm_crtc *crtc;
1537b62e948fSDave Airlie 
1538b62e948fSDave Airlie 	/* find out if crtc2 is in use or if this encoder is using it */
1539b62e948fSDave Airlie 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1540b62e948fSDave Airlie 		struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
1541b62e948fSDave Airlie 		if ((radeon_crtc->crtc_id == 1) && crtc->enabled) {
1542b62e948fSDave Airlie 			if (encoder->crtc != crtc) {
1543b62e948fSDave Airlie 				return connector_status_disconnected;
1544b62e948fSDave Airlie 			}
1545b62e948fSDave Airlie 		}
1546b62e948fSDave Airlie 	}
1547771fe6b9SJerome Glisse 
15484ce001abSDave Airlie 	if (connector->connector_type == DRM_MODE_CONNECTOR_SVIDEO ||
15494ce001abSDave Airlie 	    connector->connector_type == DRM_MODE_CONNECTOR_Composite ||
15504ce001abSDave Airlie 	    connector->connector_type == DRM_MODE_CONNECTOR_9PinDIN) {
15514ce001abSDave Airlie 		bool tv_detect;
15524ce001abSDave Airlie 
15534ce001abSDave Airlie 		if (radeon_encoder->active_device && !(radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT))
15544ce001abSDave Airlie 			return connector_status_disconnected;
15554ce001abSDave Airlie 
15564ce001abSDave Airlie 		tv_detect = radeon_legacy_tv_detect(encoder, connector);
15574ce001abSDave Airlie 		if (tv_detect && tv_dac)
15584ce001abSDave Airlie 			found = connector_status_connected;
15594ce001abSDave Airlie 		return found;
15604ce001abSDave Airlie 	}
15614ce001abSDave Airlie 
15624ce001abSDave Airlie 	/* don't probe if the encoder is being used for something else not CRT related */
15634ce001abSDave Airlie 	if (radeon_encoder->active_device && !(radeon_encoder->active_device & ATOM_DEVICE_CRT_SUPPORT)) {
15644ce001abSDave Airlie 		DRM_INFO("not detecting due to %08x\n", radeon_encoder->active_device);
15654ce001abSDave Airlie 		return connector_status_disconnected;
15664ce001abSDave Airlie 	}
1567771fe6b9SJerome Glisse 
15686d9cdfc2SAlex Deucher 	/* R200 uses an external DAC for secondary DAC */
15696d9cdfc2SAlex Deucher 	if (rdev->family == CHIP_R200) {
15706d9cdfc2SAlex Deucher 		if (radeon_legacy_ext_dac_detect(encoder, connector))
15716d9cdfc2SAlex Deucher 			found = connector_status_connected;
15726d9cdfc2SAlex Deucher 		return found;
15736d9cdfc2SAlex Deucher 	}
15746d9cdfc2SAlex Deucher 
1575771fe6b9SJerome Glisse 	/* save the regs we need */
1576771fe6b9SJerome Glisse 	pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
1577701337dcSEgbert Eich 
1578701337dcSEgbert Eich 	if (rdev->flags & RADEON_SINGLE_CRTC) {
1579701337dcSEgbert Eich 		crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
1580701337dcSEgbert Eich 	} else {
1581d038db86SEgbert Eich 		if (ASIC_IS_R300(rdev)) {
1582d038db86SEgbert Eich 			gpiopad_a = RREG32(RADEON_GPIOPAD_A);
1583d038db86SEgbert Eich 			disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL);
1584d038db86SEgbert Eich 		} else {
1585d038db86SEgbert Eich 			disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG);
1586d038db86SEgbert Eich 		}
1587771fe6b9SJerome Glisse 		crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
1588701337dcSEgbert Eich 	}
1589771fe6b9SJerome Glisse 	tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
1590771fe6b9SJerome Glisse 	dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL);
1591771fe6b9SJerome Glisse 	dac_cntl2 = RREG32(RADEON_DAC_CNTL2);
1592771fe6b9SJerome Glisse 
1593771fe6b9SJerome Glisse 	tmp = pixclks_cntl & ~(RADEON_PIX2CLK_ALWAYS_ONb
1594771fe6b9SJerome Glisse 			       | RADEON_PIX2CLK_DAC_ALWAYS_ONb);
1595771fe6b9SJerome Glisse 	WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp);
1596771fe6b9SJerome Glisse 
1597701337dcSEgbert Eich 	if (rdev->flags & RADEON_SINGLE_CRTC) {
1598701337dcSEgbert Eich 		tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON;
1599701337dcSEgbert Eich 		WREG32(RADEON_CRTC_EXT_CNTL, tmp);
1600701337dcSEgbert Eich 	} else {
1601771fe6b9SJerome Glisse 		tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK;
1602771fe6b9SJerome Glisse 		tmp |= RADEON_CRTC2_CRT2_ON |
1603771fe6b9SJerome Glisse 			(2 << RADEON_CRTC2_PIX_WIDTH_SHIFT);
1604771fe6b9SJerome Glisse 		WREG32(RADEON_CRTC2_GEN_CNTL, tmp);
1605771fe6b9SJerome Glisse 
1606771fe6b9SJerome Glisse 		if (ASIC_IS_R300(rdev)) {
1607d038db86SEgbert Eich 			WREG32_P(RADEON_GPIOPAD_A, 1, ~1);
1608771fe6b9SJerome Glisse 			tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK;
1609771fe6b9SJerome Glisse 			tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2;
1610771fe6b9SJerome Glisse 			WREG32(RADEON_DISP_OUTPUT_CNTL, tmp);
1611771fe6b9SJerome Glisse 		} else {
1612771fe6b9SJerome Glisse 			tmp = disp_hw_debug & ~RADEON_CRT2_DISP1_SEL;
1613771fe6b9SJerome Glisse 			WREG32(RADEON_DISP_HW_DEBUG, tmp);
1614771fe6b9SJerome Glisse 		}
1615701337dcSEgbert Eich 	}
1616771fe6b9SJerome Glisse 
1617771fe6b9SJerome Glisse 	tmp = RADEON_TV_DAC_NBLANK |
1618771fe6b9SJerome Glisse 		RADEON_TV_DAC_NHOLD |
1619771fe6b9SJerome Glisse 		RADEON_TV_MONITOR_DETECT_EN |
1620771fe6b9SJerome Glisse 		RADEON_TV_DAC_STD_PS2;
1621771fe6b9SJerome Glisse 
1622771fe6b9SJerome Glisse 	WREG32(RADEON_TV_DAC_CNTL, tmp);
1623771fe6b9SJerome Glisse 
1624771fe6b9SJerome Glisse 	tmp = RADEON_DAC2_FORCE_BLANK_OFF_EN |
1625771fe6b9SJerome Glisse 		RADEON_DAC2_FORCE_DATA_EN;
1626771fe6b9SJerome Glisse 
1627771fe6b9SJerome Glisse 	if (color)
1628771fe6b9SJerome Glisse 		tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB;
1629771fe6b9SJerome Glisse 	else
1630771fe6b9SJerome Glisse 		tmp |= RADEON_DAC_FORCE_DATA_SEL_G;
1631771fe6b9SJerome Glisse 
1632771fe6b9SJerome Glisse 	if (ASIC_IS_R300(rdev))
1633771fe6b9SJerome Glisse 		tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT);
1634771fe6b9SJerome Glisse 	else
1635771fe6b9SJerome Glisse 		tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT);
1636771fe6b9SJerome Glisse 
1637771fe6b9SJerome Glisse 	WREG32(RADEON_DAC_EXT_CNTL, tmp);
1638771fe6b9SJerome Glisse 
1639771fe6b9SJerome Glisse 	tmp = dac_cntl2 | RADEON_DAC2_DAC2_CLK_SEL | RADEON_DAC2_CMP_EN;
1640771fe6b9SJerome Glisse 	WREG32(RADEON_DAC_CNTL2, tmp);
1641771fe6b9SJerome Glisse 
16424de833c3SArnd Bergmann 	mdelay(10);
1643771fe6b9SJerome Glisse 
1644771fe6b9SJerome Glisse 	if (ASIC_IS_R300(rdev)) {
1645771fe6b9SJerome Glisse 		if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUT_B)
1646771fe6b9SJerome Glisse 			found = connector_status_connected;
1647771fe6b9SJerome Glisse 	} else {
1648771fe6b9SJerome Glisse 		if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUTPUT)
1649771fe6b9SJerome Glisse 			found = connector_status_connected;
1650771fe6b9SJerome Glisse 	}
1651771fe6b9SJerome Glisse 
1652771fe6b9SJerome Glisse 	/* restore regs we used */
1653771fe6b9SJerome Glisse 	WREG32(RADEON_DAC_CNTL2, dac_cntl2);
1654771fe6b9SJerome Glisse 	WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl);
1655771fe6b9SJerome Glisse 	WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
1656771fe6b9SJerome Glisse 
1657701337dcSEgbert Eich 	if (rdev->flags & RADEON_SINGLE_CRTC) {
1658701337dcSEgbert Eich 		WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
1659701337dcSEgbert Eich 	} else {
1660701337dcSEgbert Eich 		WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
1661771fe6b9SJerome Glisse 		if (ASIC_IS_R300(rdev)) {
1662771fe6b9SJerome Glisse 			WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
1663771fe6b9SJerome Glisse 			WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1);
1664771fe6b9SJerome Glisse 		} else {
1665771fe6b9SJerome Glisse 			WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug);
1666771fe6b9SJerome Glisse 		}
1667701337dcSEgbert Eich 	}
1668d038db86SEgbert Eich 
1669771fe6b9SJerome Glisse 	WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
1670771fe6b9SJerome Glisse 
16714ce001abSDave Airlie 	return found;
1672771fe6b9SJerome Glisse 
1673771fe6b9SJerome Glisse }
1674771fe6b9SJerome Glisse 
1675771fe6b9SJerome Glisse static const struct drm_encoder_helper_funcs radeon_legacy_tv_dac_helper_funcs = {
1676771fe6b9SJerome Glisse 	.dpms = radeon_legacy_tv_dac_dpms,
167780297e87SAlex Deucher 	.mode_fixup = radeon_legacy_mode_fixup,
1678771fe6b9SJerome Glisse 	.prepare = radeon_legacy_tv_dac_prepare,
1679771fe6b9SJerome Glisse 	.mode_set = radeon_legacy_tv_dac_mode_set,
1680771fe6b9SJerome Glisse 	.commit = radeon_legacy_tv_dac_commit,
1681771fe6b9SJerome Glisse 	.detect = radeon_legacy_tv_dac_detect,
16824ce001abSDave Airlie 	.disable = radeon_legacy_encoder_disable,
1683771fe6b9SJerome Glisse };
1684771fe6b9SJerome Glisse 
1685771fe6b9SJerome Glisse 
1686771fe6b9SJerome Glisse static const struct drm_encoder_funcs radeon_legacy_tv_dac_enc_funcs = {
1687771fe6b9SJerome Glisse 	.destroy = radeon_enc_destroy,
1688771fe6b9SJerome Glisse };
1689771fe6b9SJerome Glisse 
1690445282dbSDave Airlie 
radeon_legacy_get_tmds_info(struct radeon_encoder * encoder)1691445282dbSDave Airlie static struct radeon_encoder_int_tmds *radeon_legacy_get_tmds_info(struct radeon_encoder *encoder)
1692445282dbSDave Airlie {
1693445282dbSDave Airlie 	struct drm_device *dev = encoder->base.dev;
1694445282dbSDave Airlie 	struct radeon_device *rdev = dev->dev_private;
1695*3cc0f8f4SRuan Jinjie 	struct radeon_encoder_int_tmds *tmds;
1696445282dbSDave Airlie 	bool ret;
1697445282dbSDave Airlie 
1698445282dbSDave Airlie 	tmds = kzalloc(sizeof(struct radeon_encoder_int_tmds), GFP_KERNEL);
1699445282dbSDave Airlie 
1700445282dbSDave Airlie 	if (!tmds)
1701445282dbSDave Airlie 		return NULL;
1702445282dbSDave Airlie 
1703445282dbSDave Airlie 	if (rdev->is_atom_bios)
1704445282dbSDave Airlie 		ret = radeon_atombios_get_tmds_info(encoder, tmds);
1705445282dbSDave Airlie 	else
1706445282dbSDave Airlie 		ret = radeon_legacy_get_tmds_info_from_combios(encoder, tmds);
1707445282dbSDave Airlie 
1708fbd62354SWambui Karuga 	if (!ret)
1709445282dbSDave Airlie 		radeon_legacy_get_tmds_info_from_table(encoder, tmds);
1710445282dbSDave Airlie 
1711445282dbSDave Airlie 	return tmds;
1712445282dbSDave Airlie }
1713445282dbSDave Airlie 
radeon_legacy_get_ext_tmds_info(struct radeon_encoder * encoder)1714fcec570bSAlex Deucher static struct radeon_encoder_ext_tmds *radeon_legacy_get_ext_tmds_info(struct radeon_encoder *encoder)
1715fcec570bSAlex Deucher {
1716fcec570bSAlex Deucher 	struct drm_device *dev = encoder->base.dev;
1717fcec570bSAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
1718*3cc0f8f4SRuan Jinjie 	struct radeon_encoder_ext_tmds *tmds;
1719fcec570bSAlex Deucher 	bool ret;
1720fcec570bSAlex Deucher 
1721fcec570bSAlex Deucher 	if (rdev->is_atom_bios)
1722fcec570bSAlex Deucher 		return NULL;
1723fcec570bSAlex Deucher 
1724fcec570bSAlex Deucher 	tmds = kzalloc(sizeof(struct radeon_encoder_ext_tmds), GFP_KERNEL);
1725fcec570bSAlex Deucher 
1726fcec570bSAlex Deucher 	if (!tmds)
1727fcec570bSAlex Deucher 		return NULL;
1728fcec570bSAlex Deucher 
1729fcec570bSAlex Deucher 	ret = radeon_legacy_get_ext_tmds_info_from_combios(encoder, tmds);
1730fcec570bSAlex Deucher 
1731fbd62354SWambui Karuga 	if (!ret)
1732fcec570bSAlex Deucher 		radeon_legacy_get_ext_tmds_info_from_table(encoder, tmds);
1733fcec570bSAlex Deucher 
1734fcec570bSAlex Deucher 	return tmds;
1735fcec570bSAlex Deucher }
1736fcec570bSAlex Deucher 
1737771fe6b9SJerome Glisse void
radeon_add_legacy_encoder(struct drm_device * dev,uint32_t encoder_enum,uint32_t supported_device)17385137ee94SAlex Deucher radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device)
1739771fe6b9SJerome Glisse {
1740771fe6b9SJerome Glisse 	struct radeon_device *rdev = dev->dev_private;
1741771fe6b9SJerome Glisse 	struct drm_encoder *encoder;
1742771fe6b9SJerome Glisse 	struct radeon_encoder *radeon_encoder;
1743771fe6b9SJerome Glisse 
1744771fe6b9SJerome Glisse 	/* see if we already added it */
1745771fe6b9SJerome Glisse 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
1746771fe6b9SJerome Glisse 		radeon_encoder = to_radeon_encoder(encoder);
17475137ee94SAlex Deucher 		if (radeon_encoder->encoder_enum == encoder_enum) {
1748771fe6b9SJerome Glisse 			radeon_encoder->devices |= supported_device;
1749771fe6b9SJerome Glisse 			return;
1750771fe6b9SJerome Glisse 		}
1751771fe6b9SJerome Glisse 
1752771fe6b9SJerome Glisse 	}
1753771fe6b9SJerome Glisse 
1754771fe6b9SJerome Glisse 	/* add a new one */
1755771fe6b9SJerome Glisse 	radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL);
1756771fe6b9SJerome Glisse 	if (!radeon_encoder)
1757771fe6b9SJerome Glisse 		return;
1758771fe6b9SJerome Glisse 
1759771fe6b9SJerome Glisse 	encoder = &radeon_encoder->base;
1760dfee5614SDave Airlie 	if (rdev->flags & RADEON_SINGLE_CRTC)
1761dfee5614SDave Airlie 		encoder->possible_crtcs = 0x1;
1762dfee5614SDave Airlie 	else
1763771fe6b9SJerome Glisse 		encoder->possible_crtcs = 0x3;
1764771fe6b9SJerome Glisse 
1765771fe6b9SJerome Glisse 	radeon_encoder->enc_priv = NULL;
1766771fe6b9SJerome Glisse 
17675137ee94SAlex Deucher 	radeon_encoder->encoder_enum = encoder_enum;
17685137ee94SAlex Deucher 	radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
1769771fe6b9SJerome Glisse 	radeon_encoder->devices = supported_device;
1770c93bb85bSJerome Glisse 	radeon_encoder->rmx_type = RMX_OFF;
1771771fe6b9SJerome Glisse 
1772771fe6b9SJerome Glisse 	switch (radeon_encoder->encoder_id) {
1773771fe6b9SJerome Glisse 	case ENCODER_OBJECT_ID_INTERNAL_LVDS:
177480e6914dSDave Airlie 		encoder->possible_crtcs = 0x1;
177513a3d91fSVille Syrjälä 		drm_encoder_init(dev, encoder, &radeon_legacy_lvds_enc_funcs,
177613a3d91fSVille Syrjälä 				 DRM_MODE_ENCODER_LVDS, NULL);
1777771fe6b9SJerome Glisse 		drm_encoder_helper_add(encoder, &radeon_legacy_lvds_helper_funcs);
1778771fe6b9SJerome Glisse 		if (rdev->is_atom_bios)
1779771fe6b9SJerome Glisse 			radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder);
1780771fe6b9SJerome Glisse 		else
1781771fe6b9SJerome Glisse 			radeon_encoder->enc_priv = radeon_combios_get_lvds_info(radeon_encoder);
1782771fe6b9SJerome Glisse 		radeon_encoder->rmx_type = RMX_FULL;
1783771fe6b9SJerome Glisse 		break;
1784771fe6b9SJerome Glisse 	case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
178513a3d91fSVille Syrjälä 		drm_encoder_init(dev, encoder, &radeon_legacy_tmds_int_enc_funcs,
178613a3d91fSVille Syrjälä 				 DRM_MODE_ENCODER_TMDS, NULL);
1787771fe6b9SJerome Glisse 		drm_encoder_helper_add(encoder, &radeon_legacy_tmds_int_helper_funcs);
1788445282dbSDave Airlie 		radeon_encoder->enc_priv = radeon_legacy_get_tmds_info(radeon_encoder);
1789771fe6b9SJerome Glisse 		break;
1790771fe6b9SJerome Glisse 	case ENCODER_OBJECT_ID_INTERNAL_DAC1:
179113a3d91fSVille Syrjälä 		drm_encoder_init(dev, encoder, &radeon_legacy_primary_dac_enc_funcs,
179213a3d91fSVille Syrjälä 				 DRM_MODE_ENCODER_DAC, NULL);
1793771fe6b9SJerome Glisse 		drm_encoder_helper_add(encoder, &radeon_legacy_primary_dac_helper_funcs);
17946fe7ac3fSAlex Deucher 		if (rdev->is_atom_bios)
17956fe7ac3fSAlex Deucher 			radeon_encoder->enc_priv = radeon_atombios_get_primary_dac_info(radeon_encoder);
17966fe7ac3fSAlex Deucher 		else
1797771fe6b9SJerome Glisse 			radeon_encoder->enc_priv = radeon_combios_get_primary_dac_info(radeon_encoder);
1798771fe6b9SJerome Glisse 		break;
1799771fe6b9SJerome Glisse 	case ENCODER_OBJECT_ID_INTERNAL_DAC2:
180013a3d91fSVille Syrjälä 		drm_encoder_init(dev, encoder, &radeon_legacy_tv_dac_enc_funcs,
180113a3d91fSVille Syrjälä 				 DRM_MODE_ENCODER_TVDAC, NULL);
1802771fe6b9SJerome Glisse 		drm_encoder_helper_add(encoder, &radeon_legacy_tv_dac_helper_funcs);
18036fe7ac3fSAlex Deucher 		if (rdev->is_atom_bios)
18046fe7ac3fSAlex Deucher 			radeon_encoder->enc_priv = radeon_atombios_get_tv_dac_info(radeon_encoder);
18056fe7ac3fSAlex Deucher 		else
1806771fe6b9SJerome Glisse 			radeon_encoder->enc_priv = radeon_combios_get_tv_dac_info(radeon_encoder);
1807771fe6b9SJerome Glisse 		break;
1808771fe6b9SJerome Glisse 	case ENCODER_OBJECT_ID_INTERNAL_DVO1:
180913a3d91fSVille Syrjälä 		drm_encoder_init(dev, encoder, &radeon_legacy_tmds_ext_enc_funcs,
181013a3d91fSVille Syrjälä 				 DRM_MODE_ENCODER_TMDS, NULL);
1811771fe6b9SJerome Glisse 		drm_encoder_helper_add(encoder, &radeon_legacy_tmds_ext_helper_funcs);
1812771fe6b9SJerome Glisse 		if (!rdev->is_atom_bios)
1813fcec570bSAlex Deucher 			radeon_encoder->enc_priv = radeon_legacy_get_ext_tmds_info(radeon_encoder);
1814771fe6b9SJerome Glisse 		break;
1815771fe6b9SJerome Glisse 	}
1816771fe6b9SJerome Glisse }
1817