xref: /linux/drivers/gpu/drm/radeon/atombios_encoders.c (revision 1eb67781117ca2095f0dbede79f22f6b2ffa3189)
13f03ced8SAlex Deucher /*
23f03ced8SAlex Deucher  * Copyright 2007-11 Advanced Micro Devices, Inc.
33f03ced8SAlex Deucher  * Copyright 2008 Red Hat Inc.
43f03ced8SAlex Deucher  *
53f03ced8SAlex Deucher  * Permission is hereby granted, free of charge, to any person obtaining a
63f03ced8SAlex Deucher  * copy of this software and associated documentation files (the "Software"),
73f03ced8SAlex Deucher  * to deal in the Software without restriction, including without limitation
83f03ced8SAlex Deucher  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
93f03ced8SAlex Deucher  * and/or sell copies of the Software, and to permit persons to whom the
103f03ced8SAlex Deucher  * Software is furnished to do so, subject to the following conditions:
113f03ced8SAlex Deucher  *
123f03ced8SAlex Deucher  * The above copyright notice and this permission notice shall be included in
133f03ced8SAlex Deucher  * all copies or substantial portions of the Software.
143f03ced8SAlex Deucher  *
153f03ced8SAlex Deucher  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
163f03ced8SAlex Deucher  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
173f03ced8SAlex Deucher  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
183f03ced8SAlex Deucher  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
193f03ced8SAlex Deucher  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
203f03ced8SAlex Deucher  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
213f03ced8SAlex Deucher  * OTHER DEALINGS IN THE SOFTWARE.
223f03ced8SAlex Deucher  *
233f03ced8SAlex Deucher  * Authors: Dave Airlie
243f03ced8SAlex Deucher  *          Alex Deucher
253f03ced8SAlex Deucher  */
26c182615fSSam Ravnborg 
27f3728734SAlex Deucher #include <linux/backlight.h>
28564d8a2cSMario Kleiner #include <linux/dmi.h>
292ef79416SThomas Zimmermann #include <linux/pci.h>
303f03ced8SAlex Deucher 
31c182615fSSam Ravnborg #include <drm/drm_crtc_helper.h>
32c182615fSSam Ravnborg #include <drm/drm_file.h>
33c182615fSSam Ravnborg #include <drm/radeon_drm.h>
34c182615fSSam Ravnborg 
35*1eb67781SHans de Goede #include <acpi/video.h>
36*1eb67781SHans de Goede 
37c182615fSSam Ravnborg #include "atom.h"
3854ae7f99SLee Jones #include "radeon_atombios.h"
39c182615fSSam Ravnborg #include "radeon.h"
40c182615fSSam Ravnborg #include "radeon_asic.h"
41c182615fSSam Ravnborg #include "radeon_audio.h"
42c182615fSSam Ravnborg 
433f03ced8SAlex Deucher extern int atom_debug;
443f03ced8SAlex Deucher 
45f3728734SAlex Deucher static u8
46f3728734SAlex Deucher radeon_atom_get_backlight_level_from_reg(struct radeon_device *rdev)
47f3728734SAlex Deucher {
48f3728734SAlex Deucher 	u8 backlight_level;
49f3728734SAlex Deucher 	u32 bios_2_scratch;
50f3728734SAlex Deucher 
51f3728734SAlex Deucher 	if (rdev->family >= CHIP_R600)
52f3728734SAlex Deucher 		bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
53f3728734SAlex Deucher 	else
54f3728734SAlex Deucher 		bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
55f3728734SAlex Deucher 
56f3728734SAlex Deucher 	backlight_level = ((bios_2_scratch & ATOM_S2_CURRENT_BL_LEVEL_MASK) >>
57f3728734SAlex Deucher 			   ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
58f3728734SAlex Deucher 
59f3728734SAlex Deucher 	return backlight_level;
60f3728734SAlex Deucher }
61f3728734SAlex Deucher 
62f3728734SAlex Deucher static void
63f3728734SAlex Deucher radeon_atom_set_backlight_level_to_reg(struct radeon_device *rdev,
64f3728734SAlex Deucher 				       u8 backlight_level)
65f3728734SAlex Deucher {
66f3728734SAlex Deucher 	u32 bios_2_scratch;
67f3728734SAlex Deucher 
68f3728734SAlex Deucher 	if (rdev->family >= CHIP_R600)
69f3728734SAlex Deucher 		bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
70f3728734SAlex Deucher 	else
71f3728734SAlex Deucher 		bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
72f3728734SAlex Deucher 
73f3728734SAlex Deucher 	bios_2_scratch &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK;
74f3728734SAlex Deucher 	bios_2_scratch |= ((backlight_level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT) &
75f3728734SAlex Deucher 			   ATOM_S2_CURRENT_BL_LEVEL_MASK);
76f3728734SAlex Deucher 
77f3728734SAlex Deucher 	if (rdev->family >= CHIP_R600)
78f3728734SAlex Deucher 		WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
79f3728734SAlex Deucher 	else
80f3728734SAlex Deucher 		WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch);
81f3728734SAlex Deucher }
82f3728734SAlex Deucher 
836d92f81dSAlex Deucher u8
846d92f81dSAlex Deucher atombios_get_backlight_level(struct radeon_encoder *radeon_encoder)
856d92f81dSAlex Deucher {
866d92f81dSAlex Deucher 	struct drm_device *dev = radeon_encoder->base.dev;
876d92f81dSAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
886d92f81dSAlex Deucher 
896d92f81dSAlex Deucher 	if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
906d92f81dSAlex Deucher 		return 0;
916d92f81dSAlex Deucher 
926d92f81dSAlex Deucher 	return radeon_atom_get_backlight_level_from_reg(rdev);
936d92f81dSAlex Deucher }
946d92f81dSAlex Deucher 
95fda4b25cSLuca Tettamanti void
9637e9b6a6SAlex Deucher atombios_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level)
97f3728734SAlex Deucher {
98f3728734SAlex Deucher 	struct drm_encoder *encoder = &radeon_encoder->base;
99f3728734SAlex Deucher 	struct drm_device *dev = radeon_encoder->base.dev;
100f3728734SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
101f3728734SAlex Deucher 	struct radeon_encoder_atom_dig *dig;
102f3728734SAlex Deucher 	DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
103f3728734SAlex Deucher 	int index;
104f3728734SAlex Deucher 
10537e9b6a6SAlex Deucher 	if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
10637e9b6a6SAlex Deucher 		return;
10737e9b6a6SAlex Deucher 
10837e9b6a6SAlex Deucher 	if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) &&
10937e9b6a6SAlex Deucher 	    radeon_encoder->enc_priv) {
110f3728734SAlex Deucher 		dig = radeon_encoder->enc_priv;
11137e9b6a6SAlex Deucher 		dig->backlight_level = level;
112f3728734SAlex Deucher 		radeon_atom_set_backlight_level_to_reg(rdev, dig->backlight_level);
113f3728734SAlex Deucher 
114f3728734SAlex Deucher 		switch (radeon_encoder->encoder_id) {
115f3728734SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_LVDS:
116f3728734SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
117f3728734SAlex Deucher 			index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
118f3728734SAlex Deucher 			if (dig->backlight_level == 0) {
119f3728734SAlex Deucher 				args.ucAction = ATOM_LCD_BLOFF;
120f3728734SAlex Deucher 				atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
121f3728734SAlex Deucher 			} else {
122f3728734SAlex Deucher 				args.ucAction = ATOM_LCD_BL_BRIGHTNESS_CONTROL;
123f3728734SAlex Deucher 				atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
124f3728734SAlex Deucher 				args.ucAction = ATOM_LCD_BLON;
125f3728734SAlex Deucher 				atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
126f3728734SAlex Deucher 			}
127f3728734SAlex Deucher 			break;
128f3728734SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
129f3728734SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
130f3728734SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
131f3728734SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
132d3200be6SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
133f3728734SAlex Deucher 			if (dig->backlight_level == 0)
134f3728734SAlex Deucher 				atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
135f3728734SAlex Deucher 			else {
136f3728734SAlex Deucher 				atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL, 0, 0);
137f3728734SAlex Deucher 				atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
138f3728734SAlex Deucher 			}
139f3728734SAlex Deucher 			break;
140f3728734SAlex Deucher 		default:
141f3728734SAlex Deucher 			break;
142f3728734SAlex Deucher 		}
143f3728734SAlex Deucher 	}
144f3728734SAlex Deucher }
145f3728734SAlex Deucher 
146f3728734SAlex Deucher static u8 radeon_atom_bl_level(struct backlight_device *bd)
147f3728734SAlex Deucher {
148f3728734SAlex Deucher 	u8 level;
149f3728734SAlex Deucher 
150f3728734SAlex Deucher 	/* Convert brightness to hardware level */
151f3728734SAlex Deucher 	if (bd->props.brightness < 0)
152f3728734SAlex Deucher 		level = 0;
153f3728734SAlex Deucher 	else if (bd->props.brightness > RADEON_MAX_BL_LEVEL)
154f3728734SAlex Deucher 		level = RADEON_MAX_BL_LEVEL;
155f3728734SAlex Deucher 	else
156f3728734SAlex Deucher 		level = bd->props.brightness;
157f3728734SAlex Deucher 
158f3728734SAlex Deucher 	return level;
159f3728734SAlex Deucher }
160f3728734SAlex Deucher 
161f3728734SAlex Deucher static int radeon_atom_backlight_update_status(struct backlight_device *bd)
162f3728734SAlex Deucher {
163f3728734SAlex Deucher 	struct radeon_backlight_privdata *pdata = bl_get_data(bd);
164f3728734SAlex Deucher 	struct radeon_encoder *radeon_encoder = pdata->encoder;
165f3728734SAlex Deucher 
16637e9b6a6SAlex Deucher 	atombios_set_backlight_level(radeon_encoder, radeon_atom_bl_level(bd));
167f3728734SAlex Deucher 
168f3728734SAlex Deucher 	return 0;
169f3728734SAlex Deucher }
170f3728734SAlex Deucher 
171f3728734SAlex Deucher static int radeon_atom_backlight_get_brightness(struct backlight_device *bd)
172f3728734SAlex Deucher {
173f3728734SAlex Deucher 	struct radeon_backlight_privdata *pdata = bl_get_data(bd);
174f3728734SAlex Deucher 	struct radeon_encoder *radeon_encoder = pdata->encoder;
175f3728734SAlex Deucher 	struct drm_device *dev = radeon_encoder->base.dev;
176f3728734SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
177f3728734SAlex Deucher 
178f3728734SAlex Deucher 	return radeon_atom_get_backlight_level_from_reg(rdev);
179f3728734SAlex Deucher }
180f3728734SAlex Deucher 
181f3728734SAlex Deucher static const struct backlight_ops radeon_atom_backlight_ops = {
182f3728734SAlex Deucher 	.get_brightness = radeon_atom_backlight_get_brightness,
183f3728734SAlex Deucher 	.update_status	= radeon_atom_backlight_update_status,
184f3728734SAlex Deucher };
185f3728734SAlex Deucher 
186f3728734SAlex Deucher void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder,
187f3728734SAlex Deucher 				struct drm_connector *drm_connector)
188f3728734SAlex Deucher {
189f3728734SAlex Deucher 	struct drm_device *dev = radeon_encoder->base.dev;
190f3728734SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
191f3728734SAlex Deucher 	struct backlight_device *bd;
192f3728734SAlex Deucher 	struct backlight_properties props;
193f3728734SAlex Deucher 	struct radeon_backlight_privdata *pdata;
194f3728734SAlex Deucher 	struct radeon_encoder_atom_dig *dig;
195614499b4SAlex Deucher 	char bl_name[16];
196f3728734SAlex Deucher 
19780101790SAlex Deucher 	/* Mac laptops with multiple GPUs use the gmux driver for backlight
19880101790SAlex Deucher 	 * so don't register a backlight device
19980101790SAlex Deucher 	 */
20080101790SAlex Deucher 	if ((rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
201364438fdSNicholas Bishop 	    (rdev->pdev->device == 0x6741) &&
202364438fdSNicholas Bishop 	    !dmi_match(DMI_PRODUCT_NAME, "iMac12,1"))
20380101790SAlex Deucher 		return;
20480101790SAlex Deucher 
205f3728734SAlex Deucher 	if (!radeon_encoder->enc_priv)
206f3728734SAlex Deucher 		return;
207f3728734SAlex Deucher 
208f3728734SAlex Deucher 	if (!rdev->is_atom_bios)
209f3728734SAlex Deucher 		return;
210f3728734SAlex Deucher 
211f3728734SAlex Deucher 	if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
212f3728734SAlex Deucher 		return;
213f3728734SAlex Deucher 
214*1eb67781SHans de Goede 	if (!acpi_video_backlight_use_native()) {
215*1eb67781SHans de Goede 		drm_info(dev, "Skipping radeon atom DIG backlight registration\n");
216*1eb67781SHans de Goede 		return;
217*1eb67781SHans de Goede 	}
218*1eb67781SHans de Goede 
219f3728734SAlex Deucher 	pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL);
220f3728734SAlex Deucher 	if (!pdata) {
221f3728734SAlex Deucher 		DRM_ERROR("Memory allocation failed\n");
222f3728734SAlex Deucher 		goto error;
223f3728734SAlex Deucher 	}
224f3728734SAlex Deucher 
225f3728734SAlex Deucher 	memset(&props, 0, sizeof(props));
226f3728734SAlex Deucher 	props.max_brightness = RADEON_MAX_BL_LEVEL;
227f3728734SAlex Deucher 	props.type = BACKLIGHT_RAW;
228614499b4SAlex Deucher 	snprintf(bl_name, sizeof(bl_name),
229614499b4SAlex Deucher 		 "radeon_bl%d", dev->primary->index);
2305bdebb18SDave Airlie 	bd = backlight_device_register(bl_name, drm_connector->kdev,
231f3728734SAlex Deucher 				       pdata, &radeon_atom_backlight_ops, &props);
232f3728734SAlex Deucher 	if (IS_ERR(bd)) {
233f3728734SAlex Deucher 		DRM_ERROR("Backlight registration failed\n");
234f3728734SAlex Deucher 		goto error;
235f3728734SAlex Deucher 	}
236f3728734SAlex Deucher 
237f3728734SAlex Deucher 	pdata->encoder = radeon_encoder;
238f3728734SAlex Deucher 
239f3728734SAlex Deucher 	dig = radeon_encoder->enc_priv;
240f3728734SAlex Deucher 	dig->bl_dev = bd;
241f3728734SAlex Deucher 
242f3728734SAlex Deucher 	bd->props.brightness = radeon_atom_backlight_get_brightness(bd);
243201bb624SAlex Deucher 	/* Set a reasonable default here if the level is 0 otherwise
244201bb624SAlex Deucher 	 * fbdev will attempt to turn the backlight on after console
245201bb624SAlex Deucher 	 * unblanking and it will try and restore 0 which turns the backlight
246201bb624SAlex Deucher 	 * off again.
247201bb624SAlex Deucher 	 */
248201bb624SAlex Deucher 	if (bd->props.brightness == 0)
249201bb624SAlex Deucher 		bd->props.brightness = RADEON_MAX_BL_LEVEL;
250f3728734SAlex Deucher 	bd->props.power = FB_BLANK_UNBLANK;
251f3728734SAlex Deucher 	backlight_update_status(bd);
252f3728734SAlex Deucher 
253f3728734SAlex Deucher 	DRM_INFO("radeon atom DIG backlight initialized\n");
2544cee6a90SAlex Deucher 	rdev->mode_info.bl_encoder = radeon_encoder;
255f3728734SAlex Deucher 
256f3728734SAlex Deucher 	return;
257f3728734SAlex Deucher 
258f3728734SAlex Deucher error:
259f3728734SAlex Deucher 	kfree(pdata);
260f3728734SAlex Deucher 	return;
261f3728734SAlex Deucher }
262f3728734SAlex Deucher 
263f3728734SAlex Deucher static void radeon_atom_backlight_exit(struct radeon_encoder *radeon_encoder)
264f3728734SAlex Deucher {
265f3728734SAlex Deucher 	struct drm_device *dev = radeon_encoder->base.dev;
266f3728734SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
267f3728734SAlex Deucher 	struct backlight_device *bd = NULL;
268f3728734SAlex Deucher 	struct radeon_encoder_atom_dig *dig;
269f3728734SAlex Deucher 
270f3728734SAlex Deucher 	if (!radeon_encoder->enc_priv)
271f3728734SAlex Deucher 		return;
272f3728734SAlex Deucher 
273f3728734SAlex Deucher 	if (!rdev->is_atom_bios)
274f3728734SAlex Deucher 		return;
275f3728734SAlex Deucher 
276f3728734SAlex Deucher 	if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
277f3728734SAlex Deucher 		return;
278f3728734SAlex Deucher 
279f3728734SAlex Deucher 	dig = radeon_encoder->enc_priv;
280f3728734SAlex Deucher 	bd = dig->bl_dev;
281f3728734SAlex Deucher 	dig->bl_dev = NULL;
282f3728734SAlex Deucher 
283f3728734SAlex Deucher 	if (bd) {
284f3728734SAlex Deucher 		struct radeon_legacy_backlight_privdata *pdata;
285f3728734SAlex Deucher 
286f3728734SAlex Deucher 		pdata = bl_get_data(bd);
287f3728734SAlex Deucher 		backlight_device_unregister(bd);
288f3728734SAlex Deucher 		kfree(pdata);
289f3728734SAlex Deucher 
290f3728734SAlex Deucher 		DRM_INFO("radeon atom LVDS backlight unloaded\n");
291f3728734SAlex Deucher 	}
292f3728734SAlex Deucher }
293f3728734SAlex Deucher 
2943f03ced8SAlex Deucher static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
295e811f5aeSLaurent Pinchart 				   const struct drm_display_mode *mode,
2963f03ced8SAlex Deucher 				   struct drm_display_mode *adjusted_mode)
2973f03ced8SAlex Deucher {
2983f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
2993f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
3003f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
3013f03ced8SAlex Deucher 
3023f03ced8SAlex Deucher 	/* set the active encoder to connector routing */
3033f03ced8SAlex Deucher 	radeon_encoder_set_active_device(encoder);
3043f03ced8SAlex Deucher 	drm_mode_set_crtcinfo(adjusted_mode, 0);
3053f03ced8SAlex Deucher 
3063f03ced8SAlex Deucher 	/* hw bug */
3073f03ced8SAlex Deucher 	if ((mode->flags & DRM_MODE_FLAG_INTERLACE)
3083f03ced8SAlex Deucher 	    && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2)))
3093f03ced8SAlex Deucher 		adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2;
3103f03ced8SAlex Deucher 
3113104b812SAlex Deucher 	/* vertical FP must be at least 1 */
3123104b812SAlex Deucher 	if (mode->crtc_vsync_start == mode->crtc_vdisplay)
3133104b812SAlex Deucher 		adjusted_mode->crtc_vsync_start++;
3143104b812SAlex Deucher 
315da997620SAlex Deucher 	/* get the native mode for scaling */
316da997620SAlex Deucher 	if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
3173f03ced8SAlex Deucher 		radeon_panel_mode_fixup(encoder, adjusted_mode);
318da997620SAlex Deucher 	} else if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
3193f03ced8SAlex Deucher 		struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv;
3203f03ced8SAlex Deucher 		if (tv_dac) {
3213f03ced8SAlex Deucher 			if (tv_dac->tv_std == TV_STD_NTSC ||
3223f03ced8SAlex Deucher 			    tv_dac->tv_std == TV_STD_NTSC_J ||
3233f03ced8SAlex Deucher 			    tv_dac->tv_std == TV_STD_PAL_M)
3243f03ced8SAlex Deucher 				radeon_atom_get_tv_timings(rdev, 0, adjusted_mode);
3253f03ced8SAlex Deucher 			else
3263f03ced8SAlex Deucher 				radeon_atom_get_tv_timings(rdev, 1, adjusted_mode);
3273f03ced8SAlex Deucher 		}
328da997620SAlex Deucher 	} else if (radeon_encoder->rmx_type != RMX_OFF) {
329da997620SAlex Deucher 		radeon_panel_mode_fixup(encoder, adjusted_mode);
3303f03ced8SAlex Deucher 	}
3313f03ced8SAlex Deucher 
3323f03ced8SAlex Deucher 	if (ASIC_IS_DCE3(rdev) &&
3333f03ced8SAlex Deucher 	    ((radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) ||
3343f03ced8SAlex Deucher 	     (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE))) {
3353f03ced8SAlex Deucher 		struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
33693927f9cSAlex Deucher 		radeon_dp_set_link_config(connector, adjusted_mode);
3373f03ced8SAlex Deucher 	}
3383f03ced8SAlex Deucher 
3393f03ced8SAlex Deucher 	return true;
3403f03ced8SAlex Deucher }
3413f03ced8SAlex Deucher 
3423f03ced8SAlex Deucher static void
3433f03ced8SAlex Deucher atombios_dac_setup(struct drm_encoder *encoder, int action)
3443f03ced8SAlex Deucher {
3453f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
3463f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
3473f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
3483f03ced8SAlex Deucher 	DAC_ENCODER_CONTROL_PS_ALLOCATION args;
3493f03ced8SAlex Deucher 	int index = 0;
3503f03ced8SAlex Deucher 	struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv;
3513f03ced8SAlex Deucher 
3523f03ced8SAlex Deucher 	memset(&args, 0, sizeof(args));
3533f03ced8SAlex Deucher 
3543f03ced8SAlex Deucher 	switch (radeon_encoder->encoder_id) {
3553f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DAC1:
3563f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
3573f03ced8SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl);
3583f03ced8SAlex Deucher 		break;
3593f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DAC2:
3603f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
3613f03ced8SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl);
3623f03ced8SAlex Deucher 		break;
3633f03ced8SAlex Deucher 	}
3643f03ced8SAlex Deucher 
3653f03ced8SAlex Deucher 	args.ucAction = action;
3663f03ced8SAlex Deucher 
3673f03ced8SAlex Deucher 	if (radeon_encoder->active_device & (ATOM_DEVICE_CRT_SUPPORT))
3683f03ced8SAlex Deucher 		args.ucDacStandard = ATOM_DAC1_PS2;
3693f03ced8SAlex Deucher 	else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
3703f03ced8SAlex Deucher 		args.ucDacStandard = ATOM_DAC1_CV;
3713f03ced8SAlex Deucher 	else {
3723f03ced8SAlex Deucher 		switch (dac_info->tv_std) {
3733f03ced8SAlex Deucher 		case TV_STD_PAL:
3743f03ced8SAlex Deucher 		case TV_STD_PAL_M:
3753f03ced8SAlex Deucher 		case TV_STD_SCART_PAL:
3763f03ced8SAlex Deucher 		case TV_STD_SECAM:
3773f03ced8SAlex Deucher 		case TV_STD_PAL_CN:
3783f03ced8SAlex Deucher 			args.ucDacStandard = ATOM_DAC1_PAL;
3793f03ced8SAlex Deucher 			break;
3803f03ced8SAlex Deucher 		case TV_STD_NTSC:
3813f03ced8SAlex Deucher 		case TV_STD_NTSC_J:
3823f03ced8SAlex Deucher 		case TV_STD_PAL_60:
3833f03ced8SAlex Deucher 		default:
3843f03ced8SAlex Deucher 			args.ucDacStandard = ATOM_DAC1_NTSC;
3853f03ced8SAlex Deucher 			break;
3863f03ced8SAlex Deucher 		}
3873f03ced8SAlex Deucher 	}
3883f03ced8SAlex Deucher 	args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
3893f03ced8SAlex Deucher 
3903f03ced8SAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
3913f03ced8SAlex Deucher 
3923f03ced8SAlex Deucher }
3933f03ced8SAlex Deucher 
3943f03ced8SAlex Deucher static void
3953f03ced8SAlex Deucher atombios_tv_setup(struct drm_encoder *encoder, int action)
3963f03ced8SAlex Deucher {
3973f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
3983f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
3993f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
4003f03ced8SAlex Deucher 	TV_ENCODER_CONTROL_PS_ALLOCATION args;
4013f03ced8SAlex Deucher 	int index = 0;
4023f03ced8SAlex Deucher 	struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv;
4033f03ced8SAlex Deucher 
4043f03ced8SAlex Deucher 	memset(&args, 0, sizeof(args));
4053f03ced8SAlex Deucher 
4063f03ced8SAlex Deucher 	index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl);
4073f03ced8SAlex Deucher 
4083f03ced8SAlex Deucher 	args.sTVEncoder.ucAction = action;
4093f03ced8SAlex Deucher 
4103f03ced8SAlex Deucher 	if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
4113f03ced8SAlex Deucher 		args.sTVEncoder.ucTvStandard = ATOM_TV_CV;
4123f03ced8SAlex Deucher 	else {
4133f03ced8SAlex Deucher 		switch (dac_info->tv_std) {
4143f03ced8SAlex Deucher 		case TV_STD_NTSC:
4153f03ced8SAlex Deucher 			args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
4163f03ced8SAlex Deucher 			break;
4173f03ced8SAlex Deucher 		case TV_STD_PAL:
4183f03ced8SAlex Deucher 			args.sTVEncoder.ucTvStandard = ATOM_TV_PAL;
4193f03ced8SAlex Deucher 			break;
4203f03ced8SAlex Deucher 		case TV_STD_PAL_M:
4213f03ced8SAlex Deucher 			args.sTVEncoder.ucTvStandard = ATOM_TV_PALM;
4223f03ced8SAlex Deucher 			break;
4233f03ced8SAlex Deucher 		case TV_STD_PAL_60:
4243f03ced8SAlex Deucher 			args.sTVEncoder.ucTvStandard = ATOM_TV_PAL60;
4253f03ced8SAlex Deucher 			break;
4263f03ced8SAlex Deucher 		case TV_STD_NTSC_J:
4273f03ced8SAlex Deucher 			args.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ;
4283f03ced8SAlex Deucher 			break;
4293f03ced8SAlex Deucher 		case TV_STD_SCART_PAL:
4303f03ced8SAlex Deucher 			args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */
4313f03ced8SAlex Deucher 			break;
4323f03ced8SAlex Deucher 		case TV_STD_SECAM:
4333f03ced8SAlex Deucher 			args.sTVEncoder.ucTvStandard = ATOM_TV_SECAM;
4343f03ced8SAlex Deucher 			break;
4353f03ced8SAlex Deucher 		case TV_STD_PAL_CN:
4363f03ced8SAlex Deucher 			args.sTVEncoder.ucTvStandard = ATOM_TV_PALCN;
4373f03ced8SAlex Deucher 			break;
4383f03ced8SAlex Deucher 		default:
4393f03ced8SAlex Deucher 			args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
4403f03ced8SAlex Deucher 			break;
4413f03ced8SAlex Deucher 		}
4423f03ced8SAlex Deucher 	}
4433f03ced8SAlex Deucher 
4443f03ced8SAlex Deucher 	args.sTVEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
4453f03ced8SAlex Deucher 
4463f03ced8SAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
4473f03ced8SAlex Deucher 
4483f03ced8SAlex Deucher }
4493f03ced8SAlex Deucher 
4501f0e2943SAlex Deucher static u8 radeon_atom_get_bpc(struct drm_encoder *encoder)
4511f0e2943SAlex Deucher {
4521f0e2943SAlex Deucher 	int bpc = 8;
4531f0e2943SAlex Deucher 
4547d5a33b0SAlex Deucher 	if (encoder->crtc) {
4557d5a33b0SAlex Deucher 		struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
4567d5a33b0SAlex Deucher 		bpc = radeon_crtc->bpc;
4577d5a33b0SAlex Deucher 	}
4581f0e2943SAlex Deucher 
4591f0e2943SAlex Deucher 	switch (bpc) {
4601f0e2943SAlex Deucher 	case 0:
4611f0e2943SAlex Deucher 		return PANEL_BPC_UNDEFINE;
4621f0e2943SAlex Deucher 	case 6:
4631f0e2943SAlex Deucher 		return PANEL_6BIT_PER_COLOR;
4641f0e2943SAlex Deucher 	case 8:
4651f0e2943SAlex Deucher 	default:
4661f0e2943SAlex Deucher 		return PANEL_8BIT_PER_COLOR;
4671f0e2943SAlex Deucher 	case 10:
4681f0e2943SAlex Deucher 		return PANEL_10BIT_PER_COLOR;
4691f0e2943SAlex Deucher 	case 12:
4701f0e2943SAlex Deucher 		return PANEL_12BIT_PER_COLOR;
4711f0e2943SAlex Deucher 	case 16:
4721f0e2943SAlex Deucher 		return PANEL_16BIT_PER_COLOR;
4731f0e2943SAlex Deucher 	}
4741f0e2943SAlex Deucher }
4751f0e2943SAlex Deucher 
4763f03ced8SAlex Deucher union dvo_encoder_control {
4773f03ced8SAlex Deucher 	ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds;
4783f03ced8SAlex Deucher 	DVO_ENCODER_CONTROL_PS_ALLOCATION dvo;
4793f03ced8SAlex Deucher 	DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3;
480aea65641SAlex Deucher 	DVO_ENCODER_CONTROL_PS_ALLOCATION_V1_4 dvo_v4;
4813f03ced8SAlex Deucher };
4823f03ced8SAlex Deucher 
4833f03ced8SAlex Deucher void
4843f03ced8SAlex Deucher atombios_dvo_setup(struct drm_encoder *encoder, int action)
4853f03ced8SAlex Deucher {
4863f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
4873f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
4883f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
4893f03ced8SAlex Deucher 	union dvo_encoder_control args;
4903f03ced8SAlex Deucher 	int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
49124153dd3SAlex Deucher 	uint8_t frev, crev;
4923f03ced8SAlex Deucher 
4933f03ced8SAlex Deucher 	memset(&args, 0, sizeof(args));
4943f03ced8SAlex Deucher 
49524153dd3SAlex Deucher 	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
49624153dd3SAlex Deucher 		return;
49724153dd3SAlex Deucher 
498afceb931SAlex Deucher 	/* some R4xx chips have the wrong frev */
499afceb931SAlex Deucher 	if (rdev->family <= CHIP_RV410)
500afceb931SAlex Deucher 		frev = 1;
501afceb931SAlex Deucher 
50224153dd3SAlex Deucher 	switch (frev) {
50324153dd3SAlex Deucher 	case 1:
50424153dd3SAlex Deucher 		switch (crev) {
50524153dd3SAlex Deucher 		case 1:
50624153dd3SAlex Deucher 			/* R4xx, R5xx */
50724153dd3SAlex Deucher 			args.ext_tmds.sXTmdsEncoder.ucEnable = action;
50824153dd3SAlex Deucher 
5099aa59993SAlex Deucher 			if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
51024153dd3SAlex Deucher 				args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL;
51124153dd3SAlex Deucher 
51224153dd3SAlex Deucher 			args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB;
51324153dd3SAlex Deucher 			break;
51424153dd3SAlex Deucher 		case 2:
51524153dd3SAlex Deucher 			/* RS600/690/740 */
5163f03ced8SAlex Deucher 			args.dvo.sDVOEncoder.ucAction = action;
5173f03ced8SAlex Deucher 			args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
5183f03ced8SAlex Deucher 			/* DFP1, CRT1, TV1 depending on the type of port */
5193f03ced8SAlex Deucher 			args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX;
5203f03ced8SAlex Deucher 
5219aa59993SAlex Deucher 			if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
5223f03ced8SAlex Deucher 				args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL;
52324153dd3SAlex Deucher 			break;
52424153dd3SAlex Deucher 		case 3:
52524153dd3SAlex Deucher 			/* R6xx */
52624153dd3SAlex Deucher 			args.dvo_v3.ucAction = action;
52724153dd3SAlex Deucher 			args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
52824153dd3SAlex Deucher 			args.dvo_v3.ucDVOConfig = 0; /* XXX */
52924153dd3SAlex Deucher 			break;
530aea65641SAlex Deucher 		case 4:
531aea65641SAlex Deucher 			/* DCE8 */
532aea65641SAlex Deucher 			args.dvo_v4.ucAction = action;
533aea65641SAlex Deucher 			args.dvo_v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
534aea65641SAlex Deucher 			args.dvo_v4.ucDVOConfig = 0; /* XXX */
535aea65641SAlex Deucher 			args.dvo_v4.ucBitPerColor = radeon_atom_get_bpc(encoder);
536aea65641SAlex Deucher 			break;
53724153dd3SAlex Deucher 		default:
53824153dd3SAlex Deucher 			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
53924153dd3SAlex Deucher 			break;
54024153dd3SAlex Deucher 		}
54124153dd3SAlex Deucher 		break;
54224153dd3SAlex Deucher 	default:
54324153dd3SAlex Deucher 		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
54424153dd3SAlex Deucher 		break;
5453f03ced8SAlex Deucher 	}
5463f03ced8SAlex Deucher 
5473f03ced8SAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
5483f03ced8SAlex Deucher }
5493f03ced8SAlex Deucher 
5503f03ced8SAlex Deucher union lvds_encoder_control {
5513f03ced8SAlex Deucher 	LVDS_ENCODER_CONTROL_PS_ALLOCATION    v1;
5523f03ced8SAlex Deucher 	LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2;
5533f03ced8SAlex Deucher };
5543f03ced8SAlex Deucher 
5553f03ced8SAlex Deucher void
5563f03ced8SAlex Deucher atombios_digital_setup(struct drm_encoder *encoder, int action)
5573f03ced8SAlex Deucher {
5583f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
5593f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
5603f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
5613f03ced8SAlex Deucher 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
5623f03ced8SAlex Deucher 	union lvds_encoder_control args;
5633f03ced8SAlex Deucher 	int index = 0;
5643f03ced8SAlex Deucher 	int hdmi_detected = 0;
5653f03ced8SAlex Deucher 	uint8_t frev, crev;
5663f03ced8SAlex Deucher 
5673f03ced8SAlex Deucher 	if (!dig)
5683f03ced8SAlex Deucher 		return;
5693f03ced8SAlex Deucher 
5703f03ced8SAlex Deucher 	if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI)
5713f03ced8SAlex Deucher 		hdmi_detected = 1;
5723f03ced8SAlex Deucher 
5733f03ced8SAlex Deucher 	memset(&args, 0, sizeof(args));
5743f03ced8SAlex Deucher 
5753f03ced8SAlex Deucher 	switch (radeon_encoder->encoder_id) {
5763f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_LVDS:
5773f03ced8SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
5783f03ced8SAlex Deucher 		break;
5793f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
5803f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
5813f03ced8SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl);
5823f03ced8SAlex Deucher 		break;
5833f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
5843f03ced8SAlex Deucher 		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
5853f03ced8SAlex Deucher 			index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
5863f03ced8SAlex Deucher 		else
5873f03ced8SAlex Deucher 			index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl);
5883f03ced8SAlex Deucher 		break;
5893f03ced8SAlex Deucher 	}
5903f03ced8SAlex Deucher 
5913f03ced8SAlex Deucher 	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
5923f03ced8SAlex Deucher 		return;
5933f03ced8SAlex Deucher 
5943f03ced8SAlex Deucher 	switch (frev) {
5953f03ced8SAlex Deucher 	case 1:
5963f03ced8SAlex Deucher 	case 2:
5973f03ced8SAlex Deucher 		switch (crev) {
5983f03ced8SAlex Deucher 		case 1:
5993f03ced8SAlex Deucher 			args.v1.ucMisc = 0;
6003f03ced8SAlex Deucher 			args.v1.ucAction = action;
6013f03ced8SAlex Deucher 			if (hdmi_detected)
6023f03ced8SAlex Deucher 				args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
6033f03ced8SAlex Deucher 			args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
6043f03ced8SAlex Deucher 			if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
6053f03ced8SAlex Deucher 				if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL)
6063f03ced8SAlex Deucher 					args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
6073f03ced8SAlex Deucher 				if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
6083f03ced8SAlex Deucher 					args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
6093f03ced8SAlex Deucher 			} else {
6103f03ced8SAlex Deucher 				if (dig->linkb)
6113f03ced8SAlex Deucher 					args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
6129aa59993SAlex Deucher 				if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
6133f03ced8SAlex Deucher 					args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
6143f03ced8SAlex Deucher 				/*if (pScrn->rgbBits == 8) */
6153f03ced8SAlex Deucher 				args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
6163f03ced8SAlex Deucher 			}
6173f03ced8SAlex Deucher 			break;
6183f03ced8SAlex Deucher 		case 2:
6193f03ced8SAlex Deucher 		case 3:
6203f03ced8SAlex Deucher 			args.v2.ucMisc = 0;
6213f03ced8SAlex Deucher 			args.v2.ucAction = action;
6223f03ced8SAlex Deucher 			if (crev == 3) {
6233f03ced8SAlex Deucher 				if (dig->coherent_mode)
6243f03ced8SAlex Deucher 					args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT;
6253f03ced8SAlex Deucher 			}
6263f03ced8SAlex Deucher 			if (hdmi_detected)
6273f03ced8SAlex Deucher 				args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
6283f03ced8SAlex Deucher 			args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
6293f03ced8SAlex Deucher 			args.v2.ucTruncate = 0;
6303f03ced8SAlex Deucher 			args.v2.ucSpatial = 0;
6313f03ced8SAlex Deucher 			args.v2.ucTemporal = 0;
6323f03ced8SAlex Deucher 			args.v2.ucFRC = 0;
6333f03ced8SAlex Deucher 			if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
6343f03ced8SAlex Deucher 				if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL)
6353f03ced8SAlex Deucher 					args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
6363f03ced8SAlex Deucher 				if (dig->lcd_misc & ATOM_PANEL_MISC_SPATIAL) {
6373f03ced8SAlex Deucher 					args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN;
6383f03ced8SAlex Deucher 					if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
6393f03ced8SAlex Deucher 						args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH;
6403f03ced8SAlex Deucher 				}
6413f03ced8SAlex Deucher 				if (dig->lcd_misc & ATOM_PANEL_MISC_TEMPORAL) {
6423f03ced8SAlex Deucher 					args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN;
6433f03ced8SAlex Deucher 					if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
6443f03ced8SAlex Deucher 						args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH;
6453f03ced8SAlex Deucher 					if (((dig->lcd_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2)
6463f03ced8SAlex Deucher 						args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4;
6473f03ced8SAlex Deucher 				}
6483f03ced8SAlex Deucher 			} else {
6493f03ced8SAlex Deucher 				if (dig->linkb)
6503f03ced8SAlex Deucher 					args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
6519aa59993SAlex Deucher 				if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
6523f03ced8SAlex Deucher 					args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
6533f03ced8SAlex Deucher 			}
6543f03ced8SAlex Deucher 			break;
6553f03ced8SAlex Deucher 		default:
6563f03ced8SAlex Deucher 			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
6573f03ced8SAlex Deucher 			break;
6583f03ced8SAlex Deucher 		}
6593f03ced8SAlex Deucher 		break;
6603f03ced8SAlex Deucher 	default:
6613f03ced8SAlex Deucher 		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
6623f03ced8SAlex Deucher 		break;
6633f03ced8SAlex Deucher 	}
6643f03ced8SAlex Deucher 
6653f03ced8SAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
6663f03ced8SAlex Deucher }
6673f03ced8SAlex Deucher 
6683f03ced8SAlex Deucher int
6693f03ced8SAlex Deucher atombios_get_encoder_mode(struct drm_encoder *encoder)
6703f03ced8SAlex Deucher {
671e55bca26SSlava Grigorev 	struct drm_device *dev = encoder->dev;
672e55bca26SSlava Grigorev 	struct radeon_device *rdev = dev->dev_private;
6733f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
6743f03ced8SAlex Deucher 	struct drm_connector *connector;
6753f03ced8SAlex Deucher 	struct radeon_connector *radeon_connector;
6763f03ced8SAlex Deucher 	struct radeon_connector_atom_dig *dig_connector;
6779843ead0SDave Airlie 	struct radeon_encoder_atom_dig *dig_enc;
6783f03ced8SAlex Deucher 
6799843ead0SDave Airlie 	if (radeon_encoder_is_digital(encoder)) {
6809843ead0SDave Airlie 		dig_enc = radeon_encoder->enc_priv;
6819843ead0SDave Airlie 		if (dig_enc->active_mst_links)
6829843ead0SDave Airlie 			return ATOM_ENCODER_MODE_DP_MST;
6839843ead0SDave Airlie 	}
6849843ead0SDave Airlie 	if (radeon_encoder->is_mst_encoder || radeon_encoder->offset)
6859843ead0SDave Airlie 		return ATOM_ENCODER_MODE_DP_MST;
6863f03ced8SAlex Deucher 	/* dp bridges are always DP */
6873f03ced8SAlex Deucher 	if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)
6883f03ced8SAlex Deucher 		return ATOM_ENCODER_MODE_DP;
6893f03ced8SAlex Deucher 
6903f03ced8SAlex Deucher 	/* DVO is always DVO */
691a59fbb8eSAlex Deucher 	if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DVO1) ||
692a59fbb8eSAlex Deucher 	    (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1))
6933f03ced8SAlex Deucher 		return ATOM_ENCODER_MODE_DVO;
6943f03ced8SAlex Deucher 
6953f03ced8SAlex Deucher 	connector = radeon_get_connector_for_encoder(encoder);
6963f03ced8SAlex Deucher 	/* if we don't have an active device yet, just use one of
6973f03ced8SAlex Deucher 	 * the connectors tied to the encoder.
6983f03ced8SAlex Deucher 	 */
6993f03ced8SAlex Deucher 	if (!connector)
7003f03ced8SAlex Deucher 		connector = radeon_get_connector_for_encoder_init(encoder);
7013f03ced8SAlex Deucher 	radeon_connector = to_radeon_connector(connector);
7023f03ced8SAlex Deucher 
7033f03ced8SAlex Deucher 	switch (connector->connector_type) {
7043f03ced8SAlex Deucher 	case DRM_MODE_CONNECTOR_DVII:
7053f03ced8SAlex Deucher 	case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */
706108dc8e8SAlex Deucher 		if (radeon_audio != 0) {
707108dc8e8SAlex Deucher 			if (radeon_connector->use_digital &&
708108dc8e8SAlex Deucher 			    (radeon_connector->audio == RADEON_AUDIO_ENABLE))
709108dc8e8SAlex Deucher 				return ATOM_ENCODER_MODE_HDMI;
710377bd8a9SAlex Deucher 			else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) &&
711108dc8e8SAlex Deucher 				 (radeon_connector->audio == RADEON_AUDIO_AUTO))
7123f03ced8SAlex Deucher 				return ATOM_ENCODER_MODE_HDMI;
713f92e70caSRafał Miłecki 			else if (radeon_connector->use_digital)
7143f03ced8SAlex Deucher 				return ATOM_ENCODER_MODE_DVI;
7153f03ced8SAlex Deucher 			else
7163f03ced8SAlex Deucher 				return ATOM_ENCODER_MODE_CRT;
717108dc8e8SAlex Deucher 		} else if (radeon_connector->use_digital) {
718108dc8e8SAlex Deucher 			return ATOM_ENCODER_MODE_DVI;
719108dc8e8SAlex Deucher 		} else {
720108dc8e8SAlex Deucher 			return ATOM_ENCODER_MODE_CRT;
721108dc8e8SAlex Deucher 		}
7223f03ced8SAlex Deucher 		break;
7233f03ced8SAlex Deucher 	case DRM_MODE_CONNECTOR_DVID:
7243f03ced8SAlex Deucher 	case DRM_MODE_CONNECTOR_HDMIA:
7253f03ced8SAlex Deucher 	default:
726108dc8e8SAlex Deucher 		if (radeon_audio != 0) {
727108dc8e8SAlex Deucher 			if (radeon_connector->audio == RADEON_AUDIO_ENABLE)
728108dc8e8SAlex Deucher 				return ATOM_ENCODER_MODE_HDMI;
729377bd8a9SAlex Deucher 			else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) &&
730108dc8e8SAlex Deucher 				 (radeon_connector->audio == RADEON_AUDIO_AUTO))
7313f03ced8SAlex Deucher 				return ATOM_ENCODER_MODE_HDMI;
732f92e70caSRafał Miłecki 			else
7333f03ced8SAlex Deucher 				return ATOM_ENCODER_MODE_DVI;
734108dc8e8SAlex Deucher 		} else {
735108dc8e8SAlex Deucher 			return ATOM_ENCODER_MODE_DVI;
736108dc8e8SAlex Deucher 		}
7373f03ced8SAlex Deucher 		break;
7383f03ced8SAlex Deucher 	case DRM_MODE_CONNECTOR_LVDS:
7393f03ced8SAlex Deucher 		return ATOM_ENCODER_MODE_LVDS;
7403f03ced8SAlex Deucher 		break;
7413f03ced8SAlex Deucher 	case DRM_MODE_CONNECTOR_DisplayPort:
7423f03ced8SAlex Deucher 		dig_connector = radeon_connector->con_priv;
7433f03ced8SAlex Deucher 		if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
744108dc8e8SAlex Deucher 		    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
7453473f542SAlex Deucher 			if (radeon_audio != 0 &&
7463473f542SAlex Deucher 			    drm_detect_monitor_audio(radeon_connector_edid(connector)) &&
7473473f542SAlex Deucher 			    ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
748e55bca26SSlava Grigorev 				return ATOM_ENCODER_MODE_DP_AUDIO;
7493f03ced8SAlex Deucher 			return ATOM_ENCODER_MODE_DP;
750108dc8e8SAlex Deucher 		} else if (radeon_audio != 0) {
751108dc8e8SAlex Deucher 			if (radeon_connector->audio == RADEON_AUDIO_ENABLE)
752108dc8e8SAlex Deucher 				return ATOM_ENCODER_MODE_HDMI;
753377bd8a9SAlex Deucher 			else if (drm_detect_hdmi_monitor(radeon_connector_edid(connector)) &&
754108dc8e8SAlex Deucher 				 (radeon_connector->audio == RADEON_AUDIO_AUTO))
7553f03ced8SAlex Deucher 				return ATOM_ENCODER_MODE_HDMI;
756f92e70caSRafał Miłecki 			else
7573f03ced8SAlex Deucher 				return ATOM_ENCODER_MODE_DVI;
758108dc8e8SAlex Deucher 		} else {
759108dc8e8SAlex Deucher 			return ATOM_ENCODER_MODE_DVI;
760108dc8e8SAlex Deucher 		}
7613f03ced8SAlex Deucher 		break;
7623f03ced8SAlex Deucher 	case DRM_MODE_CONNECTOR_eDP:
7633473f542SAlex Deucher 		if (radeon_audio != 0 &&
7643473f542SAlex Deucher 		    drm_detect_monitor_audio(radeon_connector_edid(connector)) &&
7653473f542SAlex Deucher 		    ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
766e55bca26SSlava Grigorev 			return ATOM_ENCODER_MODE_DP_AUDIO;
7673f03ced8SAlex Deucher 		return ATOM_ENCODER_MODE_DP;
7683f03ced8SAlex Deucher 	case DRM_MODE_CONNECTOR_DVIA:
7693f03ced8SAlex Deucher 	case DRM_MODE_CONNECTOR_VGA:
7703f03ced8SAlex Deucher 		return ATOM_ENCODER_MODE_CRT;
7713f03ced8SAlex Deucher 		break;
7723f03ced8SAlex Deucher 	case DRM_MODE_CONNECTOR_Composite:
7733f03ced8SAlex Deucher 	case DRM_MODE_CONNECTOR_SVIDEO:
7743f03ced8SAlex Deucher 	case DRM_MODE_CONNECTOR_9PinDIN:
7753f03ced8SAlex Deucher 		/* fix me */
7763f03ced8SAlex Deucher 		return ATOM_ENCODER_MODE_TV;
7773f03ced8SAlex Deucher 		/*return ATOM_ENCODER_MODE_CV;*/
7783f03ced8SAlex Deucher 		break;
7793f03ced8SAlex Deucher 	}
7803f03ced8SAlex Deucher }
7813f03ced8SAlex Deucher 
7823f03ced8SAlex Deucher /*
7833f03ced8SAlex Deucher  * DIG Encoder/Transmitter Setup
7843f03ced8SAlex Deucher  *
7853f03ced8SAlex Deucher  * DCE 3.0/3.1
7863f03ced8SAlex Deucher  * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA.
7873f03ced8SAlex Deucher  * Supports up to 3 digital outputs
7883f03ced8SAlex Deucher  * - 2 DIG encoder blocks.
7893f03ced8SAlex Deucher  * DIG1 can drive UNIPHY link A or link B
7903f03ced8SAlex Deucher  * DIG2 can drive UNIPHY link B or LVTMA
7913f03ced8SAlex Deucher  *
7923f03ced8SAlex Deucher  * DCE 3.2
7933f03ced8SAlex Deucher  * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B).
7943f03ced8SAlex Deucher  * Supports up to 5 digital outputs
7953f03ced8SAlex Deucher  * - 2 DIG encoder blocks.
7963f03ced8SAlex Deucher  * DIG1/2 can drive UNIPHY0/1/2 link A or link B
7973f03ced8SAlex Deucher  *
7982d415869SAlex Deucher  * DCE 4.0/5.0/6.0
7993f03ced8SAlex Deucher  * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B).
8003f03ced8SAlex Deucher  * Supports up to 6 digital outputs
8013f03ced8SAlex Deucher  * - 6 DIG encoder blocks.
8023f03ced8SAlex Deucher  * - DIG to PHY mapping is hardcoded
8033f03ced8SAlex Deucher  * DIG1 drives UNIPHY0 link A, A+B
8043f03ced8SAlex Deucher  * DIG2 drives UNIPHY0 link B
8053f03ced8SAlex Deucher  * DIG3 drives UNIPHY1 link A, A+B
8063f03ced8SAlex Deucher  * DIG4 drives UNIPHY1 link B
8073f03ced8SAlex Deucher  * DIG5 drives UNIPHY2 link A, A+B
8083f03ced8SAlex Deucher  * DIG6 drives UNIPHY2 link B
8093f03ced8SAlex Deucher  *
8103f03ced8SAlex Deucher  * DCE 4.1
8113f03ced8SAlex Deucher  * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B).
8123f03ced8SAlex Deucher  * Supports up to 6 digital outputs
8133f03ced8SAlex Deucher  * - 2 DIG encoder blocks.
8142d415869SAlex Deucher  * llano
8153f03ced8SAlex Deucher  * DIG1/2 can drive UNIPHY0/1/2 link A or link B
8162d415869SAlex Deucher  * ontario
8172d415869SAlex Deucher  * DIG1 drives UNIPHY0/1/2 link A
8182d415869SAlex Deucher  * DIG2 drives UNIPHY0/1/2 link B
8193f03ced8SAlex Deucher  *
8203f03ced8SAlex Deucher  * Routing
8213f03ced8SAlex Deucher  * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links)
8223f03ced8SAlex Deucher  * Examples:
8233f03ced8SAlex Deucher  * crtc0 -> dig2 -> LVTMA   links A+B -> TMDS/HDMI
8243f03ced8SAlex Deucher  * crtc1 -> dig1 -> UNIPHY0 link  B   -> DP
8253f03ced8SAlex Deucher  * crtc0 -> dig1 -> UNIPHY2 link  A   -> LVDS
8263f03ced8SAlex Deucher  * crtc1 -> dig2 -> UNIPHY1 link  B+A -> TMDS/HDMI
8273f03ced8SAlex Deucher  */
8283f03ced8SAlex Deucher 
8293f03ced8SAlex Deucher union dig_encoder_control {
8303f03ced8SAlex Deucher 	DIG_ENCODER_CONTROL_PS_ALLOCATION v1;
8313f03ced8SAlex Deucher 	DIG_ENCODER_CONTROL_PARAMETERS_V2 v2;
8323f03ced8SAlex Deucher 	DIG_ENCODER_CONTROL_PARAMETERS_V3 v3;
8333f03ced8SAlex Deucher 	DIG_ENCODER_CONTROL_PARAMETERS_V4 v4;
8343f03ced8SAlex Deucher };
8353f03ced8SAlex Deucher 
8363f03ced8SAlex Deucher void
837bf071900SDave Airlie atombios_dig_encoder_setup2(struct drm_encoder *encoder, int action, int panel_mode, int enc_override)
8383f03ced8SAlex Deucher {
8393f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
8403f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
8413f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
8423f03ced8SAlex Deucher 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
8433f03ced8SAlex Deucher 	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
8443f03ced8SAlex Deucher 	union dig_encoder_control args;
8453f03ced8SAlex Deucher 	int index = 0;
8463f03ced8SAlex Deucher 	uint8_t frev, crev;
8473f03ced8SAlex Deucher 	int dp_clock = 0;
8483f03ced8SAlex Deucher 	int dp_lane_count = 0;
8493f03ced8SAlex Deucher 	int hpd_id = RADEON_HPD_NONE;
8503f03ced8SAlex Deucher 
8513f03ced8SAlex Deucher 	if (connector) {
8523f03ced8SAlex Deucher 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
8533f03ced8SAlex Deucher 		struct radeon_connector_atom_dig *dig_connector =
8543f03ced8SAlex Deucher 			radeon_connector->con_priv;
8553f03ced8SAlex Deucher 
8563f03ced8SAlex Deucher 		dp_clock = dig_connector->dp_clock;
8573f03ced8SAlex Deucher 		dp_lane_count = dig_connector->dp_lane_count;
8583f03ced8SAlex Deucher 		hpd_id = radeon_connector->hpd.hpd;
8593f03ced8SAlex Deucher 	}
8603f03ced8SAlex Deucher 
8613f03ced8SAlex Deucher 	/* no dig encoder assigned */
8623f03ced8SAlex Deucher 	if (dig->dig_encoder == -1)
8633f03ced8SAlex Deucher 		return;
8643f03ced8SAlex Deucher 
8653f03ced8SAlex Deucher 	memset(&args, 0, sizeof(args));
8663f03ced8SAlex Deucher 
8673f03ced8SAlex Deucher 	if (ASIC_IS_DCE4(rdev))
8683f03ced8SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl);
8693f03ced8SAlex Deucher 	else {
8703f03ced8SAlex Deucher 		if (dig->dig_encoder)
8713f03ced8SAlex Deucher 			index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
8723f03ced8SAlex Deucher 		else
8733f03ced8SAlex Deucher 			index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
8743f03ced8SAlex Deucher 	}
8753f03ced8SAlex Deucher 
8763f03ced8SAlex Deucher 	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
8773f03ced8SAlex Deucher 		return;
8783f03ced8SAlex Deucher 
87958cdcb8bSAlex Deucher 	switch (frev) {
88058cdcb8bSAlex Deucher 	case 1:
88158cdcb8bSAlex Deucher 		switch (crev) {
88258cdcb8bSAlex Deucher 		case 1:
8833f03ced8SAlex Deucher 			args.v1.ucAction = action;
8843f03ced8SAlex Deucher 			args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
8853f03ced8SAlex Deucher 			if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
8863f03ced8SAlex Deucher 				args.v3.ucPanelMode = panel_mode;
8873f03ced8SAlex Deucher 			else
8883f03ced8SAlex Deucher 				args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder);
8893f03ced8SAlex Deucher 
8903f03ced8SAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode))
8913f03ced8SAlex Deucher 				args.v1.ucLaneNum = dp_lane_count;
8929aa59993SAlex Deucher 			else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
8933f03ced8SAlex Deucher 				args.v1.ucLaneNum = 8;
8943f03ced8SAlex Deucher 			else
8953f03ced8SAlex Deucher 				args.v1.ucLaneNum = 4;
8963f03ced8SAlex Deucher 
89758cdcb8bSAlex Deucher 			switch (radeon_encoder->encoder_id) {
89858cdcb8bSAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
89958cdcb8bSAlex Deucher 				args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
90058cdcb8bSAlex Deucher 				break;
90158cdcb8bSAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
90258cdcb8bSAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
90358cdcb8bSAlex Deucher 				args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2;
90458cdcb8bSAlex Deucher 				break;
90558cdcb8bSAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
90658cdcb8bSAlex Deucher 				args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3;
90758cdcb8bSAlex Deucher 				break;
90858cdcb8bSAlex Deucher 			}
90958cdcb8bSAlex Deucher 			if (dig->linkb)
91058cdcb8bSAlex Deucher 				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
91158cdcb8bSAlex Deucher 			else
91258cdcb8bSAlex Deucher 				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
913459ee1c3SMario Kleiner 
914459ee1c3SMario Kleiner 			if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000))
915459ee1c3SMario Kleiner 				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
916459ee1c3SMario Kleiner 
91758cdcb8bSAlex Deucher 			break;
91858cdcb8bSAlex Deucher 		case 2:
91958cdcb8bSAlex Deucher 		case 3:
92058cdcb8bSAlex Deucher 			args.v3.ucAction = action;
92158cdcb8bSAlex Deucher 			args.v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
92258cdcb8bSAlex Deucher 			if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
92358cdcb8bSAlex Deucher 				args.v3.ucPanelMode = panel_mode;
92458cdcb8bSAlex Deucher 			else
92558cdcb8bSAlex Deucher 				args.v3.ucEncoderMode = atombios_get_encoder_mode(encoder);
92658cdcb8bSAlex Deucher 
9272f6fa79aSAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode))
92858cdcb8bSAlex Deucher 				args.v3.ucLaneNum = dp_lane_count;
9299aa59993SAlex Deucher 			else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
93058cdcb8bSAlex Deucher 				args.v3.ucLaneNum = 8;
93158cdcb8bSAlex Deucher 			else
93258cdcb8bSAlex Deucher 				args.v3.ucLaneNum = 4;
93358cdcb8bSAlex Deucher 
9342f6fa79aSAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode) && (dp_clock == 270000))
93558cdcb8bSAlex Deucher 				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
936bf071900SDave Airlie 			if (enc_override != -1)
937bf071900SDave Airlie 				args.v3.acConfig.ucDigSel = enc_override;
938bf071900SDave Airlie 			else
93958cdcb8bSAlex Deucher 				args.v3.acConfig.ucDigSel = dig->dig_encoder;
9401f0e2943SAlex Deucher 			args.v3.ucBitPerColor = radeon_atom_get_bpc(encoder);
94158cdcb8bSAlex Deucher 			break;
94258cdcb8bSAlex Deucher 		case 4:
94358cdcb8bSAlex Deucher 			args.v4.ucAction = action;
94458cdcb8bSAlex Deucher 			args.v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
94558cdcb8bSAlex Deucher 			if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
94658cdcb8bSAlex Deucher 				args.v4.ucPanelMode = panel_mode;
94758cdcb8bSAlex Deucher 			else
94858cdcb8bSAlex Deucher 				args.v4.ucEncoderMode = atombios_get_encoder_mode(encoder);
94958cdcb8bSAlex Deucher 
9502f6fa79aSAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode))
95158cdcb8bSAlex Deucher 				args.v4.ucLaneNum = dp_lane_count;
9529aa59993SAlex Deucher 			else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
95358cdcb8bSAlex Deucher 				args.v4.ucLaneNum = 8;
95458cdcb8bSAlex Deucher 			else
95558cdcb8bSAlex Deucher 				args.v4.ucLaneNum = 4;
95658cdcb8bSAlex Deucher 
9572f6fa79aSAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) {
958e68adef8SAlex Deucher 				if (dp_clock == 540000)
9593f03ced8SAlex Deucher 					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ;
960e68adef8SAlex Deucher 				else if (dp_clock == 324000)
961e68adef8SAlex Deucher 					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_3_24GHZ;
962e68adef8SAlex Deucher 				else if (dp_clock == 270000)
963e68adef8SAlex Deucher 					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ;
964e68adef8SAlex Deucher 				else
965e68adef8SAlex Deucher 					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ;
9663f03ced8SAlex Deucher 			}
967bf071900SDave Airlie 
968bf071900SDave Airlie 			if (enc_override != -1)
969bf071900SDave Airlie 				args.v4.acConfig.ucDigSel = enc_override;
970bf071900SDave Airlie 			else
9713f03ced8SAlex Deucher 				args.v4.acConfig.ucDigSel = dig->dig_encoder;
9721f0e2943SAlex Deucher 			args.v4.ucBitPerColor = radeon_atom_get_bpc(encoder);
9733f03ced8SAlex Deucher 			if (hpd_id == RADEON_HPD_NONE)
9743f03ced8SAlex Deucher 				args.v4.ucHPD_ID = 0;
9753f03ced8SAlex Deucher 			else
9763f03ced8SAlex Deucher 				args.v4.ucHPD_ID = hpd_id + 1;
9773f03ced8SAlex Deucher 			break;
9783f03ced8SAlex Deucher 		default:
97958cdcb8bSAlex Deucher 			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
9803f03ced8SAlex Deucher 			break;
9813f03ced8SAlex Deucher 		}
9823f03ced8SAlex Deucher 		break;
98358cdcb8bSAlex Deucher 	default:
98458cdcb8bSAlex Deucher 		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
9853f03ced8SAlex Deucher 		break;
9863f03ced8SAlex Deucher 	}
9873f03ced8SAlex Deucher 
9883f03ced8SAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
9893f03ced8SAlex Deucher 
9903f03ced8SAlex Deucher }
9913f03ced8SAlex Deucher 
992bf071900SDave Airlie void
993bf071900SDave Airlie atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode)
994bf071900SDave Airlie {
995bf071900SDave Airlie 	atombios_dig_encoder_setup2(encoder, action, panel_mode, -1);
996bf071900SDave Airlie }
997bf071900SDave Airlie 
9983f03ced8SAlex Deucher union dig_transmitter_control {
9993f03ced8SAlex Deucher 	DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
10003f03ced8SAlex Deucher 	DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
10013f03ced8SAlex Deucher 	DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3;
10023f03ced8SAlex Deucher 	DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4;
100347aef7a8SAlex Deucher 	DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5 v5;
10043f03ced8SAlex Deucher };
10053f03ced8SAlex Deucher 
10063f03ced8SAlex Deucher void
1007bf071900SDave Airlie atombios_dig_transmitter_setup2(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set, int fe)
10083f03ced8SAlex Deucher {
10093f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
10103f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
10113f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
10123f03ced8SAlex Deucher 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
10133f03ced8SAlex Deucher 	struct drm_connector *connector;
10143f03ced8SAlex Deucher 	union dig_transmitter_control args;
10153f03ced8SAlex Deucher 	int index = 0;
10163f03ced8SAlex Deucher 	uint8_t frev, crev;
10173f03ced8SAlex Deucher 	bool is_dp = false;
10183f03ced8SAlex Deucher 	int pll_id = 0;
10193f03ced8SAlex Deucher 	int dp_clock = 0;
10203f03ced8SAlex Deucher 	int dp_lane_count = 0;
10213f03ced8SAlex Deucher 	int connector_object_id = 0;
10223f03ced8SAlex Deucher 	int igp_lane_info = 0;
10233f03ced8SAlex Deucher 	int dig_encoder = dig->dig_encoder;
102447aef7a8SAlex Deucher 	int hpd_id = RADEON_HPD_NONE;
10253f03ced8SAlex Deucher 
10263f03ced8SAlex Deucher 	if (action == ATOM_TRANSMITTER_ACTION_INIT) {
10273f03ced8SAlex Deucher 		connector = radeon_get_connector_for_encoder_init(encoder);
10283f03ced8SAlex Deucher 		/* just needed to avoid bailing in the encoder check.  the encoder
10293f03ced8SAlex Deucher 		 * isn't used for init
10303f03ced8SAlex Deucher 		 */
10313f03ced8SAlex Deucher 		dig_encoder = 0;
10323f03ced8SAlex Deucher 	} else
10333f03ced8SAlex Deucher 		connector = radeon_get_connector_for_encoder(encoder);
10343f03ced8SAlex Deucher 
10353f03ced8SAlex Deucher 	if (connector) {
10363f03ced8SAlex Deucher 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
10373f03ced8SAlex Deucher 		struct radeon_connector_atom_dig *dig_connector =
10383f03ced8SAlex Deucher 			radeon_connector->con_priv;
10393f03ced8SAlex Deucher 
104047aef7a8SAlex Deucher 		hpd_id = radeon_connector->hpd.hpd;
10413f03ced8SAlex Deucher 		dp_clock = dig_connector->dp_clock;
10423f03ced8SAlex Deucher 		dp_lane_count = dig_connector->dp_lane_count;
10433f03ced8SAlex Deucher 		connector_object_id =
10443f03ced8SAlex Deucher 			(radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
10453f03ced8SAlex Deucher 		igp_lane_info = dig_connector->igp_lane_info;
10463f03ced8SAlex Deucher 	}
10473f03ced8SAlex Deucher 
1048a3b08294SAlex Deucher 	if (encoder->crtc) {
1049a3b08294SAlex Deucher 		struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
1050a3b08294SAlex Deucher 		pll_id = radeon_crtc->pll_id;
1051a3b08294SAlex Deucher 	}
1052a3b08294SAlex Deucher 
10533f03ced8SAlex Deucher 	/* no dig encoder assigned */
10543f03ced8SAlex Deucher 	if (dig_encoder == -1)
10553f03ced8SAlex Deucher 		return;
10563f03ced8SAlex Deucher 
10573f03ced8SAlex Deucher 	if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)))
10583f03ced8SAlex Deucher 		is_dp = true;
10593f03ced8SAlex Deucher 
10603f03ced8SAlex Deucher 	memset(&args, 0, sizeof(args));
10613f03ced8SAlex Deucher 
10623f03ced8SAlex Deucher 	switch (radeon_encoder->encoder_id) {
10633f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
10643f03ced8SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
10653f03ced8SAlex Deucher 		break;
10663f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
10673f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
10683f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1069e68adef8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
10703f03ced8SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
10713f03ced8SAlex Deucher 		break;
10723f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
10733f03ced8SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl);
10743f03ced8SAlex Deucher 		break;
10753f03ced8SAlex Deucher 	}
10763f03ced8SAlex Deucher 
10773f03ced8SAlex Deucher 	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
10783f03ced8SAlex Deucher 		return;
10793f03ced8SAlex Deucher 
1080a3b08294SAlex Deucher 	switch (frev) {
1081a3b08294SAlex Deucher 	case 1:
1082a3b08294SAlex Deucher 		switch (crev) {
1083a3b08294SAlex Deucher 		case 1:
10843f03ced8SAlex Deucher 			args.v1.ucAction = action;
10853f03ced8SAlex Deucher 			if (action == ATOM_TRANSMITTER_ACTION_INIT) {
10863f03ced8SAlex Deucher 				args.v1.usInitInfo = cpu_to_le16(connector_object_id);
10873f03ced8SAlex Deucher 			} else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
10883f03ced8SAlex Deucher 				args.v1.asMode.ucLaneSel = lane_num;
10893f03ced8SAlex Deucher 				args.v1.asMode.ucLaneSet = lane_set;
10903f03ced8SAlex Deucher 			} else {
10913f03ced8SAlex Deucher 				if (is_dp)
10926e76a2dfSAlex Deucher 					args.v1.usPixelClock = cpu_to_le16(dp_clock / 10);
10939aa59993SAlex Deucher 				else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
10943f03ced8SAlex Deucher 					args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
10953f03ced8SAlex Deucher 				else
10963f03ced8SAlex Deucher 					args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
10973f03ced8SAlex Deucher 			}
10983f03ced8SAlex Deucher 
10993f03ced8SAlex Deucher 			args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
11003f03ced8SAlex Deucher 
11013f03ced8SAlex Deucher 			if (dig_encoder)
11023f03ced8SAlex Deucher 				args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
11033f03ced8SAlex Deucher 			else
11043f03ced8SAlex Deucher 				args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
11053f03ced8SAlex Deucher 
11063f03ced8SAlex Deucher 			if ((rdev->flags & RADEON_IS_IGP) &&
11073f03ced8SAlex Deucher 			    (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) {
11089aa59993SAlex Deucher 				if (is_dp ||
11099aa59993SAlex Deucher 				    !radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) {
11103f03ced8SAlex Deucher 					if (igp_lane_info & 0x1)
11113f03ced8SAlex Deucher 						args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3;
11123f03ced8SAlex Deucher 					else if (igp_lane_info & 0x2)
11133f03ced8SAlex Deucher 						args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7;
11143f03ced8SAlex Deucher 					else if (igp_lane_info & 0x4)
11153f03ced8SAlex Deucher 						args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11;
11163f03ced8SAlex Deucher 					else if (igp_lane_info & 0x8)
11173f03ced8SAlex Deucher 						args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15;
11183f03ced8SAlex Deucher 				} else {
11193f03ced8SAlex Deucher 					if (igp_lane_info & 0x3)
11203f03ced8SAlex Deucher 						args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7;
11213f03ced8SAlex Deucher 					else if (igp_lane_info & 0xc)
11223f03ced8SAlex Deucher 						args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15;
11233f03ced8SAlex Deucher 				}
11243f03ced8SAlex Deucher 			}
11253f03ced8SAlex Deucher 
11263f03ced8SAlex Deucher 			if (dig->linkb)
11273f03ced8SAlex Deucher 				args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB;
11283f03ced8SAlex Deucher 			else
11293f03ced8SAlex Deucher 				args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
11303f03ced8SAlex Deucher 
11313f03ced8SAlex Deucher 			if (is_dp)
11323f03ced8SAlex Deucher 				args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
11333f03ced8SAlex Deucher 			else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
11343f03ced8SAlex Deucher 				if (dig->coherent_mode)
11353f03ced8SAlex Deucher 					args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
11369aa59993SAlex Deucher 				if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
11373f03ced8SAlex Deucher 					args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK;
11383f03ced8SAlex Deucher 			}
1139a3b08294SAlex Deucher 			break;
1140a3b08294SAlex Deucher 		case 2:
1141a3b08294SAlex Deucher 			args.v2.ucAction = action;
1142a3b08294SAlex Deucher 			if (action == ATOM_TRANSMITTER_ACTION_INIT) {
1143a3b08294SAlex Deucher 				args.v2.usInitInfo = cpu_to_le16(connector_object_id);
1144a3b08294SAlex Deucher 			} else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1145a3b08294SAlex Deucher 				args.v2.asMode.ucLaneSel = lane_num;
1146a3b08294SAlex Deucher 				args.v2.asMode.ucLaneSet = lane_set;
1147a3b08294SAlex Deucher 			} else {
1148a3b08294SAlex Deucher 				if (is_dp)
11496e76a2dfSAlex Deucher 					args.v2.usPixelClock = cpu_to_le16(dp_clock / 10);
11509aa59993SAlex Deucher 				else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
1151a3b08294SAlex Deucher 					args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
1152a3b08294SAlex Deucher 				else
1153a3b08294SAlex Deucher 					args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
1154a3b08294SAlex Deucher 			}
1155a3b08294SAlex Deucher 
1156a3b08294SAlex Deucher 			args.v2.acConfig.ucEncoderSel = dig_encoder;
1157a3b08294SAlex Deucher 			if (dig->linkb)
1158a3b08294SAlex Deucher 				args.v2.acConfig.ucLinkSel = 1;
1159a3b08294SAlex Deucher 
1160a3b08294SAlex Deucher 			switch (radeon_encoder->encoder_id) {
1161a3b08294SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1162a3b08294SAlex Deucher 				args.v2.acConfig.ucTransmitterSel = 0;
1163a3b08294SAlex Deucher 				break;
1164a3b08294SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1165a3b08294SAlex Deucher 				args.v2.acConfig.ucTransmitterSel = 1;
1166a3b08294SAlex Deucher 				break;
1167a3b08294SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1168a3b08294SAlex Deucher 				args.v2.acConfig.ucTransmitterSel = 2;
1169a3b08294SAlex Deucher 				break;
1170a3b08294SAlex Deucher 			}
1171a3b08294SAlex Deucher 
1172a3b08294SAlex Deucher 			if (is_dp) {
1173a3b08294SAlex Deucher 				args.v2.acConfig.fCoherentMode = 1;
1174a3b08294SAlex Deucher 				args.v2.acConfig.fDPConnector = 1;
1175a3b08294SAlex Deucher 			} else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
1176a3b08294SAlex Deucher 				if (dig->coherent_mode)
1177a3b08294SAlex Deucher 					args.v2.acConfig.fCoherentMode = 1;
11789aa59993SAlex Deucher 				if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
1179a3b08294SAlex Deucher 					args.v2.acConfig.fDualLinkConnector = 1;
1180a3b08294SAlex Deucher 			}
1181a3b08294SAlex Deucher 			break;
1182a3b08294SAlex Deucher 		case 3:
1183a3b08294SAlex Deucher 			args.v3.ucAction = action;
1184a3b08294SAlex Deucher 			if (action == ATOM_TRANSMITTER_ACTION_INIT) {
1185a3b08294SAlex Deucher 				args.v3.usInitInfo = cpu_to_le16(connector_object_id);
1186a3b08294SAlex Deucher 			} else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1187a3b08294SAlex Deucher 				args.v3.asMode.ucLaneSel = lane_num;
1188a3b08294SAlex Deucher 				args.v3.asMode.ucLaneSet = lane_set;
1189a3b08294SAlex Deucher 			} else {
1190a3b08294SAlex Deucher 				if (is_dp)
11916e76a2dfSAlex Deucher 					args.v3.usPixelClock = cpu_to_le16(dp_clock / 10);
11929aa59993SAlex Deucher 				else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
1193a3b08294SAlex Deucher 					args.v3.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
1194a3b08294SAlex Deucher 				else
1195a3b08294SAlex Deucher 					args.v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
1196a3b08294SAlex Deucher 			}
1197a3b08294SAlex Deucher 
1198a3b08294SAlex Deucher 			if (is_dp)
1199a3b08294SAlex Deucher 				args.v3.ucLaneNum = dp_lane_count;
12009aa59993SAlex Deucher 			else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
1201a3b08294SAlex Deucher 				args.v3.ucLaneNum = 8;
1202a3b08294SAlex Deucher 			else
1203a3b08294SAlex Deucher 				args.v3.ucLaneNum = 4;
1204a3b08294SAlex Deucher 
1205a3b08294SAlex Deucher 			if (dig->linkb)
1206a3b08294SAlex Deucher 				args.v3.acConfig.ucLinkSel = 1;
1207a3b08294SAlex Deucher 			if (dig_encoder & 1)
1208a3b08294SAlex Deucher 				args.v3.acConfig.ucEncoderSel = 1;
1209a3b08294SAlex Deucher 
1210a3b08294SAlex Deucher 			/* Select the PLL for the PHY
1211a3b08294SAlex Deucher 			 * DP PHY should be clocked from external src if there is
1212a3b08294SAlex Deucher 			 * one.
1213a3b08294SAlex Deucher 			 */
1214a3b08294SAlex Deucher 			/* On DCE4, if there is an external clock, it generates the DP ref clock */
1215a3b08294SAlex Deucher 			if (is_dp && rdev->clock.dp_extclk)
1216a3b08294SAlex Deucher 				args.v3.acConfig.ucRefClkSource = 2; /* external src */
1217a3b08294SAlex Deucher 			else
1218a3b08294SAlex Deucher 				args.v3.acConfig.ucRefClkSource = pll_id;
1219a3b08294SAlex Deucher 
1220a3b08294SAlex Deucher 			switch (radeon_encoder->encoder_id) {
1221a3b08294SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1222a3b08294SAlex Deucher 				args.v3.acConfig.ucTransmitterSel = 0;
1223a3b08294SAlex Deucher 				break;
1224a3b08294SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1225a3b08294SAlex Deucher 				args.v3.acConfig.ucTransmitterSel = 1;
1226a3b08294SAlex Deucher 				break;
1227a3b08294SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1228a3b08294SAlex Deucher 				args.v3.acConfig.ucTransmitterSel = 2;
1229a3b08294SAlex Deucher 				break;
1230a3b08294SAlex Deucher 			}
1231a3b08294SAlex Deucher 
1232a3b08294SAlex Deucher 			if (is_dp)
1233a3b08294SAlex Deucher 				args.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */
1234a3b08294SAlex Deucher 			else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
1235a3b08294SAlex Deucher 				if (dig->coherent_mode)
1236a3b08294SAlex Deucher 					args.v3.acConfig.fCoherentMode = 1;
12379aa59993SAlex Deucher 				if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
1238a3b08294SAlex Deucher 					args.v3.acConfig.fDualLinkConnector = 1;
1239a3b08294SAlex Deucher 			}
1240a3b08294SAlex Deucher 			break;
1241a3b08294SAlex Deucher 		case 4:
1242a3b08294SAlex Deucher 			args.v4.ucAction = action;
1243a3b08294SAlex Deucher 			if (action == ATOM_TRANSMITTER_ACTION_INIT) {
1244a3b08294SAlex Deucher 				args.v4.usInitInfo = cpu_to_le16(connector_object_id);
1245a3b08294SAlex Deucher 			} else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1246a3b08294SAlex Deucher 				args.v4.asMode.ucLaneSel = lane_num;
1247a3b08294SAlex Deucher 				args.v4.asMode.ucLaneSet = lane_set;
1248a3b08294SAlex Deucher 			} else {
1249a3b08294SAlex Deucher 				if (is_dp)
12506e76a2dfSAlex Deucher 					args.v4.usPixelClock = cpu_to_le16(dp_clock / 10);
12519aa59993SAlex Deucher 				else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
1252a3b08294SAlex Deucher 					args.v4.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
1253a3b08294SAlex Deucher 				else
1254a3b08294SAlex Deucher 					args.v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
1255a3b08294SAlex Deucher 			}
1256a3b08294SAlex Deucher 
1257a3b08294SAlex Deucher 			if (is_dp)
1258a3b08294SAlex Deucher 				args.v4.ucLaneNum = dp_lane_count;
12599aa59993SAlex Deucher 			else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
1260a3b08294SAlex Deucher 				args.v4.ucLaneNum = 8;
1261a3b08294SAlex Deucher 			else
1262a3b08294SAlex Deucher 				args.v4.ucLaneNum = 4;
1263a3b08294SAlex Deucher 
1264a3b08294SAlex Deucher 			if (dig->linkb)
1265a3b08294SAlex Deucher 				args.v4.acConfig.ucLinkSel = 1;
1266a3b08294SAlex Deucher 			if (dig_encoder & 1)
1267a3b08294SAlex Deucher 				args.v4.acConfig.ucEncoderSel = 1;
1268a3b08294SAlex Deucher 
1269a3b08294SAlex Deucher 			/* Select the PLL for the PHY
1270a3b08294SAlex Deucher 			 * DP PHY should be clocked from external src if there is
1271a3b08294SAlex Deucher 			 * one.
1272a3b08294SAlex Deucher 			 */
1273a3b08294SAlex Deucher 			/* On DCE5 DCPLL usually generates the DP ref clock */
1274a3b08294SAlex Deucher 			if (is_dp) {
1275a3b08294SAlex Deucher 				if (rdev->clock.dp_extclk)
1276a3b08294SAlex Deucher 					args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_EXTCLK;
1277a3b08294SAlex Deucher 				else
1278a3b08294SAlex Deucher 					args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_DCPLL;
1279a3b08294SAlex Deucher 			} else
1280a3b08294SAlex Deucher 				args.v4.acConfig.ucRefClkSource = pll_id;
1281a3b08294SAlex Deucher 
1282a3b08294SAlex Deucher 			switch (radeon_encoder->encoder_id) {
1283a3b08294SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1284a3b08294SAlex Deucher 				args.v4.acConfig.ucTransmitterSel = 0;
1285a3b08294SAlex Deucher 				break;
1286a3b08294SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1287a3b08294SAlex Deucher 				args.v4.acConfig.ucTransmitterSel = 1;
1288a3b08294SAlex Deucher 				break;
1289a3b08294SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1290a3b08294SAlex Deucher 				args.v4.acConfig.ucTransmitterSel = 2;
1291a3b08294SAlex Deucher 				break;
1292a3b08294SAlex Deucher 			}
1293a3b08294SAlex Deucher 
1294a3b08294SAlex Deucher 			if (is_dp)
1295a3b08294SAlex Deucher 				args.v4.acConfig.fCoherentMode = 1; /* DP requires coherent */
1296a3b08294SAlex Deucher 			else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
1297a3b08294SAlex Deucher 				if (dig->coherent_mode)
1298a3b08294SAlex Deucher 					args.v4.acConfig.fCoherentMode = 1;
12999aa59993SAlex Deucher 				if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
1300a3b08294SAlex Deucher 					args.v4.acConfig.fDualLinkConnector = 1;
1301a3b08294SAlex Deucher 			}
1302a3b08294SAlex Deucher 			break;
130347aef7a8SAlex Deucher 		case 5:
130447aef7a8SAlex Deucher 			args.v5.ucAction = action;
130547aef7a8SAlex Deucher 			if (is_dp)
130647aef7a8SAlex Deucher 				args.v5.usSymClock = cpu_to_le16(dp_clock / 10);
130747aef7a8SAlex Deucher 			else
130847aef7a8SAlex Deucher 				args.v5.usSymClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
130947aef7a8SAlex Deucher 
131047aef7a8SAlex Deucher 			switch (radeon_encoder->encoder_id) {
131147aef7a8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
131247aef7a8SAlex Deucher 				if (dig->linkb)
131347aef7a8SAlex Deucher 					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYB;
131447aef7a8SAlex Deucher 				else
131547aef7a8SAlex Deucher 					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYA;
131647aef7a8SAlex Deucher 				break;
131747aef7a8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
131847aef7a8SAlex Deucher 				if (dig->linkb)
131947aef7a8SAlex Deucher 					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYD;
132047aef7a8SAlex Deucher 				else
132147aef7a8SAlex Deucher 					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYC;
132247aef7a8SAlex Deucher 				break;
132347aef7a8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
132447aef7a8SAlex Deucher 				if (dig->linkb)
132547aef7a8SAlex Deucher 					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYF;
132647aef7a8SAlex Deucher 				else
132747aef7a8SAlex Deucher 					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYE;
132847aef7a8SAlex Deucher 				break;
1329e68adef8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
1330e68adef8SAlex Deucher 				args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYG;
1331e68adef8SAlex Deucher 				break;
133247aef7a8SAlex Deucher 			}
133347aef7a8SAlex Deucher 			if (is_dp)
133447aef7a8SAlex Deucher 				args.v5.ucLaneNum = dp_lane_count;
1335d03874c8SAlex Deucher 			else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
133647aef7a8SAlex Deucher 				args.v5.ucLaneNum = 8;
133747aef7a8SAlex Deucher 			else
133847aef7a8SAlex Deucher 				args.v5.ucLaneNum = 4;
133947aef7a8SAlex Deucher 			args.v5.ucConnObjId = connector_object_id;
134047aef7a8SAlex Deucher 			args.v5.ucDigMode = atombios_get_encoder_mode(encoder);
134147aef7a8SAlex Deucher 
134247aef7a8SAlex Deucher 			if (is_dp && rdev->clock.dp_extclk)
134347aef7a8SAlex Deucher 				args.v5.asConfig.ucPhyClkSrcId = ENCODER_REFCLK_SRC_EXTCLK;
134447aef7a8SAlex Deucher 			else
134547aef7a8SAlex Deucher 				args.v5.asConfig.ucPhyClkSrcId = pll_id;
134647aef7a8SAlex Deucher 
134747aef7a8SAlex Deucher 			if (is_dp)
134847aef7a8SAlex Deucher 				args.v5.asConfig.ucCoherentMode = 1; /* DP requires coherent */
134947aef7a8SAlex Deucher 			else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
135047aef7a8SAlex Deucher 				if (dig->coherent_mode)
135147aef7a8SAlex Deucher 					args.v5.asConfig.ucCoherentMode = 1;
135247aef7a8SAlex Deucher 			}
135347aef7a8SAlex Deucher 			if (hpd_id == RADEON_HPD_NONE)
135447aef7a8SAlex Deucher 				args.v5.asConfig.ucHPDSel = 0;
135547aef7a8SAlex Deucher 			else
135647aef7a8SAlex Deucher 				args.v5.asConfig.ucHPDSel = hpd_id + 1;
1357bf071900SDave Airlie 			args.v5.ucDigEncoderSel = (fe != -1) ? (1 << fe) : (1 << dig_encoder);
135847aef7a8SAlex Deucher 			args.v5.ucDPLaneSet = lane_set;
135947aef7a8SAlex Deucher 			break;
1360a3b08294SAlex Deucher 		default:
1361a3b08294SAlex Deucher 			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
1362a3b08294SAlex Deucher 			break;
1363a3b08294SAlex Deucher 		}
1364a3b08294SAlex Deucher 		break;
1365a3b08294SAlex Deucher 	default:
1366a3b08294SAlex Deucher 		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
1367a3b08294SAlex Deucher 		break;
13683f03ced8SAlex Deucher 	}
13693f03ced8SAlex Deucher 
13703f03ced8SAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
13713f03ced8SAlex Deucher }
13723f03ced8SAlex Deucher 
1373bf071900SDave Airlie void
1374bf071900SDave Airlie atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set)
1375bf071900SDave Airlie {
1376bf071900SDave Airlie 	atombios_dig_transmitter_setup2(encoder, action, lane_num, lane_set, -1);
1377bf071900SDave Airlie }
1378bf071900SDave Airlie 
13793f03ced8SAlex Deucher bool
13803f03ced8SAlex Deucher atombios_set_edp_panel_power(struct drm_connector *connector, int action)
13813f03ced8SAlex Deucher {
13823f03ced8SAlex Deucher 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
13833f03ced8SAlex Deucher 	struct drm_device *dev = radeon_connector->base.dev;
13843f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
13853f03ced8SAlex Deucher 	union dig_transmitter_control args;
13863f03ced8SAlex Deucher 	int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
13873f03ced8SAlex Deucher 	uint8_t frev, crev;
13883f03ced8SAlex Deucher 
13893f03ced8SAlex Deucher 	if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
13903f03ced8SAlex Deucher 		goto done;
13913f03ced8SAlex Deucher 
13923f03ced8SAlex Deucher 	if (!ASIC_IS_DCE4(rdev))
13933f03ced8SAlex Deucher 		goto done;
13943f03ced8SAlex Deucher 
13953f03ced8SAlex Deucher 	if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) &&
13963f03ced8SAlex Deucher 	    (action != ATOM_TRANSMITTER_ACTION_POWER_OFF))
13973f03ced8SAlex Deucher 		goto done;
13983f03ced8SAlex Deucher 
13993f03ced8SAlex Deucher 	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
14003f03ced8SAlex Deucher 		goto done;
14013f03ced8SAlex Deucher 
14023f03ced8SAlex Deucher 	memset(&args, 0, sizeof(args));
14033f03ced8SAlex Deucher 
14043f03ced8SAlex Deucher 	args.v1.ucAction = action;
14053f03ced8SAlex Deucher 
14063f03ced8SAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
14073f03ced8SAlex Deucher 
14083f03ced8SAlex Deucher 	/* wait for the panel to power up */
14093f03ced8SAlex Deucher 	if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) {
14103f03ced8SAlex Deucher 		int i;
14113f03ced8SAlex Deucher 
14123f03ced8SAlex Deucher 		for (i = 0; i < 300; i++) {
14133f03ced8SAlex Deucher 			if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
14143f03ced8SAlex Deucher 				return true;
14153f03ced8SAlex Deucher 			mdelay(1);
14163f03ced8SAlex Deucher 		}
14173f03ced8SAlex Deucher 		return false;
14183f03ced8SAlex Deucher 	}
14193f03ced8SAlex Deucher done:
14203f03ced8SAlex Deucher 	return true;
14213f03ced8SAlex Deucher }
14223f03ced8SAlex Deucher 
14233f03ced8SAlex Deucher union external_encoder_control {
14243f03ced8SAlex Deucher 	EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1;
14253f03ced8SAlex Deucher 	EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3;
14263f03ced8SAlex Deucher };
14273f03ced8SAlex Deucher 
14283f03ced8SAlex Deucher static void
14293f03ced8SAlex Deucher atombios_external_encoder_setup(struct drm_encoder *encoder,
14303f03ced8SAlex Deucher 				struct drm_encoder *ext_encoder,
14313f03ced8SAlex Deucher 				int action)
14323f03ced8SAlex Deucher {
14333f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
14343f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
14353f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
14363f03ced8SAlex Deucher 	struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder);
14373f03ced8SAlex Deucher 	union external_encoder_control args;
14383f03ced8SAlex Deucher 	struct drm_connector *connector;
14393f03ced8SAlex Deucher 	int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl);
14403f03ced8SAlex Deucher 	u8 frev, crev;
14413f03ced8SAlex Deucher 	int dp_clock = 0;
14423f03ced8SAlex Deucher 	int dp_lane_count = 0;
14433f03ced8SAlex Deucher 	int connector_object_id = 0;
14443f03ced8SAlex Deucher 	u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
14453f03ced8SAlex Deucher 
14463f03ced8SAlex Deucher 	if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
14473f03ced8SAlex Deucher 		connector = radeon_get_connector_for_encoder_init(encoder);
14483f03ced8SAlex Deucher 	else
14493f03ced8SAlex Deucher 		connector = radeon_get_connector_for_encoder(encoder);
14503f03ced8SAlex Deucher 
14513f03ced8SAlex Deucher 	if (connector) {
14523f03ced8SAlex Deucher 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
14533f03ced8SAlex Deucher 		struct radeon_connector_atom_dig *dig_connector =
14543f03ced8SAlex Deucher 			radeon_connector->con_priv;
14553f03ced8SAlex Deucher 
14563f03ced8SAlex Deucher 		dp_clock = dig_connector->dp_clock;
14573f03ced8SAlex Deucher 		dp_lane_count = dig_connector->dp_lane_count;
14583f03ced8SAlex Deucher 		connector_object_id =
14593f03ced8SAlex Deucher 			(radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
14603f03ced8SAlex Deucher 	}
14613f03ced8SAlex Deucher 
14623f03ced8SAlex Deucher 	memset(&args, 0, sizeof(args));
14633f03ced8SAlex Deucher 
14643f03ced8SAlex Deucher 	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
14653f03ced8SAlex Deucher 		return;
14663f03ced8SAlex Deucher 
14673f03ced8SAlex Deucher 	switch (frev) {
14683f03ced8SAlex Deucher 	case 1:
14693f03ced8SAlex Deucher 		/* no params on frev 1 */
14703f03ced8SAlex Deucher 		break;
14713f03ced8SAlex Deucher 	case 2:
14723f03ced8SAlex Deucher 		switch (crev) {
14733f03ced8SAlex Deucher 		case 1:
14743f03ced8SAlex Deucher 		case 2:
14753f03ced8SAlex Deucher 			args.v1.sDigEncoder.ucAction = action;
14763f03ced8SAlex Deucher 			args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
14773f03ced8SAlex Deucher 			args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder);
14783f03ced8SAlex Deucher 
14793f03ced8SAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v1.sDigEncoder.ucEncoderMode)) {
14803f03ced8SAlex Deucher 				if (dp_clock == 270000)
14813f03ced8SAlex Deucher 					args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
14823f03ced8SAlex Deucher 				args.v1.sDigEncoder.ucLaneNum = dp_lane_count;
14839aa59993SAlex Deucher 			} else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
14843f03ced8SAlex Deucher 				args.v1.sDigEncoder.ucLaneNum = 8;
14853f03ced8SAlex Deucher 			else
14863f03ced8SAlex Deucher 				args.v1.sDigEncoder.ucLaneNum = 4;
14873f03ced8SAlex Deucher 			break;
14883f03ced8SAlex Deucher 		case 3:
14893f03ced8SAlex Deucher 			args.v3.sExtEncoder.ucAction = action;
14903f03ced8SAlex Deucher 			if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
14913f03ced8SAlex Deucher 				args.v3.sExtEncoder.usConnectorId = cpu_to_le16(connector_object_id);
14923f03ced8SAlex Deucher 			else
14933f03ced8SAlex Deucher 				args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
14943f03ced8SAlex Deucher 			args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder);
14953f03ced8SAlex Deucher 
14963f03ced8SAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v3.sExtEncoder.ucEncoderMode)) {
14973f03ced8SAlex Deucher 				if (dp_clock == 270000)
14983f03ced8SAlex Deucher 					args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
14993f03ced8SAlex Deucher 				else if (dp_clock == 540000)
15003f03ced8SAlex Deucher 					args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ;
15013f03ced8SAlex Deucher 				args.v3.sExtEncoder.ucLaneNum = dp_lane_count;
15029aa59993SAlex Deucher 			} else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
15033f03ced8SAlex Deucher 				args.v3.sExtEncoder.ucLaneNum = 8;
15043f03ced8SAlex Deucher 			else
15053f03ced8SAlex Deucher 				args.v3.sExtEncoder.ucLaneNum = 4;
15063f03ced8SAlex Deucher 			switch (ext_enum) {
15073f03ced8SAlex Deucher 			case GRAPH_OBJECT_ENUM_ID1:
15083f03ced8SAlex Deucher 				args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1;
15093f03ced8SAlex Deucher 				break;
15103f03ced8SAlex Deucher 			case GRAPH_OBJECT_ENUM_ID2:
15113f03ced8SAlex Deucher 				args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2;
15123f03ced8SAlex Deucher 				break;
15133f03ced8SAlex Deucher 			case GRAPH_OBJECT_ENUM_ID3:
15143f03ced8SAlex Deucher 				args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3;
15153f03ced8SAlex Deucher 				break;
15163f03ced8SAlex Deucher 			}
15171f0e2943SAlex Deucher 			args.v3.sExtEncoder.ucBitPerColor = radeon_atom_get_bpc(encoder);
15183f03ced8SAlex Deucher 			break;
15193f03ced8SAlex Deucher 		default:
15203f03ced8SAlex Deucher 			DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
15213f03ced8SAlex Deucher 			return;
15223f03ced8SAlex Deucher 		}
15233f03ced8SAlex Deucher 		break;
15243f03ced8SAlex Deucher 	default:
15253f03ced8SAlex Deucher 		DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
15263f03ced8SAlex Deucher 		return;
15273f03ced8SAlex Deucher 	}
15283f03ced8SAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
15293f03ced8SAlex Deucher }
15303f03ced8SAlex Deucher 
15313f03ced8SAlex Deucher static void
15323f03ced8SAlex Deucher atombios_yuv_setup(struct drm_encoder *encoder, bool enable)
15333f03ced8SAlex Deucher {
15343f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
15353f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
15363f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
15373f03ced8SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
15383f03ced8SAlex Deucher 	ENABLE_YUV_PS_ALLOCATION args;
15393f03ced8SAlex Deucher 	int index = GetIndexIntoMasterTable(COMMAND, EnableYUV);
15403f03ced8SAlex Deucher 	uint32_t temp, reg;
15413f03ced8SAlex Deucher 
15423f03ced8SAlex Deucher 	memset(&args, 0, sizeof(args));
15433f03ced8SAlex Deucher 
15443f03ced8SAlex Deucher 	if (rdev->family >= CHIP_R600)
15453f03ced8SAlex Deucher 		reg = R600_BIOS_3_SCRATCH;
15463f03ced8SAlex Deucher 	else
15473f03ced8SAlex Deucher 		reg = RADEON_BIOS_3_SCRATCH;
15483f03ced8SAlex Deucher 
15493f03ced8SAlex Deucher 	/* XXX: fix up scratch reg handling */
15503f03ced8SAlex Deucher 	temp = RREG32(reg);
15513f03ced8SAlex Deucher 	if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
15523f03ced8SAlex Deucher 		WREG32(reg, (ATOM_S3_TV1_ACTIVE |
15533f03ced8SAlex Deucher 			     (radeon_crtc->crtc_id << 18)));
15543f03ced8SAlex Deucher 	else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
15553f03ced8SAlex Deucher 		WREG32(reg, (ATOM_S3_CV_ACTIVE | (radeon_crtc->crtc_id << 24)));
15563f03ced8SAlex Deucher 	else
15573f03ced8SAlex Deucher 		WREG32(reg, 0);
15583f03ced8SAlex Deucher 
15593f03ced8SAlex Deucher 	if (enable)
15603f03ced8SAlex Deucher 		args.ucEnable = ATOM_ENABLE;
15613f03ced8SAlex Deucher 	args.ucCRTC = radeon_crtc->crtc_id;
15623f03ced8SAlex Deucher 
15633f03ced8SAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
15643f03ced8SAlex Deucher 
15653f03ced8SAlex Deucher 	WREG32(reg, temp);
15663f03ced8SAlex Deucher }
15673f03ced8SAlex Deucher 
15683f03ced8SAlex Deucher static void
15693f03ced8SAlex Deucher radeon_atom_encoder_dpms_avivo(struct drm_encoder *encoder, int mode)
15703f03ced8SAlex Deucher {
15713f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
15723f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
15733f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
15743f03ced8SAlex Deucher 	DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
15753f03ced8SAlex Deucher 	int index = 0;
15763f03ced8SAlex Deucher 
15773f03ced8SAlex Deucher 	memset(&args, 0, sizeof(args));
15783f03ced8SAlex Deucher 
15793f03ced8SAlex Deucher 	switch (radeon_encoder->encoder_id) {
15803f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
15813f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
15823f03ced8SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl);
15833f03ced8SAlex Deucher 		break;
15843f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DVO1:
15853f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DDI:
15863f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
15873f03ced8SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
15883f03ced8SAlex Deucher 		break;
15893f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_LVDS:
15903f03ced8SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
15913f03ced8SAlex Deucher 		break;
15923f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
15933f03ced8SAlex Deucher 		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
15943f03ced8SAlex Deucher 			index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
15953f03ced8SAlex Deucher 		else
15963f03ced8SAlex Deucher 			index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl);
15973f03ced8SAlex Deucher 		break;
15983f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DAC1:
15993f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
16003f03ced8SAlex Deucher 		if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
16013f03ced8SAlex Deucher 			index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
16023f03ced8SAlex Deucher 		else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
16033f03ced8SAlex Deucher 			index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
16043f03ced8SAlex Deucher 		else
16053f03ced8SAlex Deucher 			index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
16063f03ced8SAlex Deucher 		break;
16073f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DAC2:
16083f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
16093f03ced8SAlex Deucher 		if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
16103f03ced8SAlex Deucher 			index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
16113f03ced8SAlex Deucher 		else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
16123f03ced8SAlex Deucher 			index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
16133f03ced8SAlex Deucher 		else
16143f03ced8SAlex Deucher 			index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
16153f03ced8SAlex Deucher 		break;
16163f03ced8SAlex Deucher 	default:
16173f03ced8SAlex Deucher 		return;
16183f03ced8SAlex Deucher 	}
16193f03ced8SAlex Deucher 
16203f03ced8SAlex Deucher 	switch (mode) {
16213f03ced8SAlex Deucher 	case DRM_MODE_DPMS_ON:
16223f03ced8SAlex Deucher 		args.ucAction = ATOM_ENABLE;
16233f03ced8SAlex Deucher 		/* workaround for DVOOutputControl on some RS690 systems */
16243f03ced8SAlex Deucher 		if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) {
16253f03ced8SAlex Deucher 			u32 reg = RREG32(RADEON_BIOS_3_SCRATCH);
16263f03ced8SAlex Deucher 			WREG32(RADEON_BIOS_3_SCRATCH, reg & ~ATOM_S3_DFP2I_ACTIVE);
16273f03ced8SAlex Deucher 			atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
16283f03ced8SAlex Deucher 			WREG32(RADEON_BIOS_3_SCRATCH, reg);
16293f03ced8SAlex Deucher 		} else
16303f03ced8SAlex Deucher 			atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
16313f03ced8SAlex Deucher 		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
1632ae93580eSAlex Deucher 			if (rdev->mode_info.bl_encoder) {
16334281f46eSMichel Dänzer 				struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
16344281f46eSMichel Dänzer 
16354281f46eSMichel Dänzer 				atombios_set_backlight_level(radeon_encoder, dig->backlight_level);
1636ae93580eSAlex Deucher 			} else {
1637ae93580eSAlex Deucher 				args.ucAction = ATOM_LCD_BLON;
1638ae93580eSAlex Deucher 				atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
1639ae93580eSAlex Deucher 			}
16403f03ced8SAlex Deucher 		}
16413f03ced8SAlex Deucher 		break;
16423f03ced8SAlex Deucher 	case DRM_MODE_DPMS_STANDBY:
16433f03ced8SAlex Deucher 	case DRM_MODE_DPMS_SUSPEND:
16443f03ced8SAlex Deucher 	case DRM_MODE_DPMS_OFF:
16453f03ced8SAlex Deucher 		args.ucAction = ATOM_DISABLE;
16463f03ced8SAlex Deucher 		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
16473f03ced8SAlex Deucher 		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
16483f03ced8SAlex Deucher 			args.ucAction = ATOM_LCD_BLOFF;
16493f03ced8SAlex Deucher 			atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
16503f03ced8SAlex Deucher 		}
16513f03ced8SAlex Deucher 		break;
16523f03ced8SAlex Deucher 	}
16533f03ced8SAlex Deucher }
16543f03ced8SAlex Deucher 
16553f03ced8SAlex Deucher static void
16563f03ced8SAlex Deucher radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
16573f03ced8SAlex Deucher {
16583f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
16593f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
16603f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
16618d1af57aSAlex Deucher 	struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder);
16628d1af57aSAlex Deucher 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
16633f03ced8SAlex Deucher 	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
16643f03ced8SAlex Deucher 	struct radeon_connector *radeon_connector = NULL;
16653f03ced8SAlex Deucher 	struct radeon_connector_atom_dig *radeon_dig_connector = NULL;
16666f50e075SAlex Deucher 	bool travis_quirk = false;
16673f03ced8SAlex Deucher 
16683f03ced8SAlex Deucher 	if (connector) {
16693f03ced8SAlex Deucher 		radeon_connector = to_radeon_connector(connector);
16703f03ced8SAlex Deucher 		radeon_dig_connector = radeon_connector->con_priv;
16716f50e075SAlex Deucher 		if ((radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
16726f50e075SAlex Deucher 		     ENCODER_OBJECT_ID_TRAVIS) &&
16736f50e075SAlex Deucher 		    (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) &&
16746f50e075SAlex Deucher 		    !ASIC_IS_DCE5(rdev))
16756f50e075SAlex Deucher 			travis_quirk = true;
16763f03ced8SAlex Deucher 	}
16773f03ced8SAlex Deucher 
16783f03ced8SAlex Deucher 	switch (mode) {
16793f03ced8SAlex Deucher 	case DRM_MODE_DPMS_ON:
16808d1af57aSAlex Deucher 		if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) {
16818d1af57aSAlex Deucher 			if (!connector)
16828d1af57aSAlex Deucher 				dig->panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
16838d1af57aSAlex Deucher 			else
16848d1af57aSAlex Deucher 				dig->panel_mode = radeon_dp_get_panel_mode(encoder, connector);
16858d1af57aSAlex Deucher 
16868d1af57aSAlex Deucher 			/* setup and enable the encoder */
1687fcedac67SJerome Glisse 			atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0);
16888d1af57aSAlex Deucher 			atombios_dig_encoder_setup(encoder,
16898d1af57aSAlex Deucher 						   ATOM_ENCODER_CMD_SETUP_PANEL_MODE,
16908d1af57aSAlex Deucher 						   dig->panel_mode);
16918d1af57aSAlex Deucher 			if (ext_encoder) {
16928d1af57aSAlex Deucher 				if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev))
16938d1af57aSAlex Deucher 					atombios_external_encoder_setup(encoder, ext_encoder,
16948d1af57aSAlex Deucher 									EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP);
1695fcedac67SJerome Glisse 			}
16968d1af57aSAlex Deucher 		} else if (ASIC_IS_DCE4(rdev)) {
16978d1af57aSAlex Deucher 			/* setup and enable the encoder */
16988d1af57aSAlex Deucher 			atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0);
1699fcedac67SJerome Glisse 		} else {
17008d1af57aSAlex Deucher 			/* setup and enable the encoder and transmitter */
17018d1af57aSAlex Deucher 			atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0);
17028d1af57aSAlex Deucher 			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
1703fcedac67SJerome Glisse 		}
17043f03ced8SAlex Deucher 		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) {
17053f03ced8SAlex Deucher 			if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
17063f03ced8SAlex Deucher 				atombios_set_edp_panel_power(connector,
17073f03ced8SAlex Deucher 							     ATOM_TRANSMITTER_ACTION_POWER_ON);
17083f03ced8SAlex Deucher 				radeon_dig_connector->edp_on = true;
17093f03ced8SAlex Deucher 			}
17106f50e075SAlex Deucher 		}
17116f50e075SAlex Deucher 		/* enable the transmitter */
17126f50e075SAlex Deucher 		atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
17136f50e075SAlex Deucher 		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) {
17146f50e075SAlex Deucher 			/* DP_SET_POWER_D0 is set in radeon_dp_link_train */
17153f03ced8SAlex Deucher 			radeon_dp_link_train(encoder, connector);
17163f03ced8SAlex Deucher 			if (ASIC_IS_DCE4(rdev))
17173f03ced8SAlex Deucher 				atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);
17183f03ced8SAlex Deucher 		}
1719ae93580eSAlex Deucher 		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
1720ae93580eSAlex Deucher 			if (rdev->mode_info.bl_encoder)
17214281f46eSMichel Dänzer 				atombios_set_backlight_level(radeon_encoder, dig->backlight_level);
1722ae93580eSAlex Deucher 			else
1723ae93580eSAlex Deucher 				atombios_dig_transmitter_setup(encoder,
1724ae93580eSAlex Deucher 							       ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
1725ae93580eSAlex Deucher 		}
17266f50e075SAlex Deucher 		if (ext_encoder)
17276f50e075SAlex Deucher 			atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);
17283f03ced8SAlex Deucher 		break;
17293f03ced8SAlex Deucher 	case DRM_MODE_DPMS_STANDBY:
17303f03ced8SAlex Deucher 	case DRM_MODE_DPMS_SUSPEND:
17313f03ced8SAlex Deucher 	case DRM_MODE_DPMS_OFF:
17329843ead0SDave Airlie 
17339843ead0SDave Airlie 		/* don't power off encoders with active MST links */
17349843ead0SDave Airlie 		if (dig->active_mst_links)
17359843ead0SDave Airlie 			return;
17369843ead0SDave Airlie 
173740390961SAlex Deucher 		if (ASIC_IS_DCE4(rdev)) {
17386f50e075SAlex Deucher 			if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector)
17396f50e075SAlex Deucher 				atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
17406f50e075SAlex Deucher 		}
17416f50e075SAlex Deucher 		if (ext_encoder)
17426f50e075SAlex Deucher 			atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE);
17436f50e075SAlex Deucher 		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
17446f50e075SAlex Deucher 			atombios_dig_transmitter_setup(encoder,
17456f50e075SAlex Deucher 						       ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
17466f50e075SAlex Deucher 
17476f50e075SAlex Deucher 		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) &&
17486f50e075SAlex Deucher 		    connector && !travis_quirk)
17496f50e075SAlex Deucher 			radeon_dp_set_rx_power_state(connector, DP_SET_POWER_D3);
17506f50e075SAlex Deucher 		if (ASIC_IS_DCE4(rdev)) {
17518d1af57aSAlex Deucher 			/* disable the transmitter */
17526f50e075SAlex Deucher 			atombios_dig_transmitter_setup(encoder,
17536f50e075SAlex Deucher 						       ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
17548d1af57aSAlex Deucher 		} else {
17558d1af57aSAlex Deucher 			/* disable the encoder and transmitter */
17566f50e075SAlex Deucher 			atombios_dig_transmitter_setup(encoder,
17576f50e075SAlex Deucher 						       ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
17588d1af57aSAlex Deucher 			atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0);
17598d1af57aSAlex Deucher 		}
17603f03ced8SAlex Deucher 		if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) {
17616f50e075SAlex Deucher 			if (travis_quirk)
17626f50e075SAlex Deucher 				radeon_dp_set_rx_power_state(connector, DP_SET_POWER_D3);
17633f03ced8SAlex Deucher 			if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
17643f03ced8SAlex Deucher 				atombios_set_edp_panel_power(connector,
17653f03ced8SAlex Deucher 							     ATOM_TRANSMITTER_ACTION_POWER_OFF);
17663f03ced8SAlex Deucher 				radeon_dig_connector->edp_on = false;
17673f03ced8SAlex Deucher 			}
17683f03ced8SAlex Deucher 		}
17693f03ced8SAlex Deucher 		break;
17703f03ced8SAlex Deucher 	}
17713f03ced8SAlex Deucher }
17723f03ced8SAlex Deucher 
17733f03ced8SAlex Deucher static void
17743f03ced8SAlex Deucher radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
17753f03ced8SAlex Deucher {
17763f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
17773f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
17783f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
17795c046a57SAlex Deucher 	int encoder_mode = atombios_get_encoder_mode(encoder);
17803f03ced8SAlex Deucher 
17813f03ced8SAlex Deucher 	DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n",
17823f03ced8SAlex Deucher 		  radeon_encoder->encoder_id, mode, radeon_encoder->devices,
17833f03ced8SAlex Deucher 		  radeon_encoder->active_device);
17845c046a57SAlex Deucher 
178538aef154SAlex Deucher 	if ((radeon_audio != 0) &&
17865c046a57SAlex Deucher 	    ((encoder_mode == ATOM_ENCODER_MODE_HDMI) ||
178738aef154SAlex Deucher 	     ENCODER_MODE_IS_DP(encoder_mode)))
17885c046a57SAlex Deucher 		radeon_audio_dpms(encoder, mode);
17895c046a57SAlex Deucher 
17903f03ced8SAlex Deucher 	switch (radeon_encoder->encoder_id) {
17913f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
17923f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
17933f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_LVDS:
17943f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
17953f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DVO1:
17963f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DDI:
17973f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DAC2:
17983f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
17993f03ced8SAlex Deucher 		radeon_atom_encoder_dpms_avivo(encoder, mode);
18003f03ced8SAlex Deucher 		break;
18013f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
18023f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
18033f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1804e68adef8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
18053f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
18063f03ced8SAlex Deucher 		radeon_atom_encoder_dpms_dig(encoder, mode);
18073f03ced8SAlex Deucher 		break;
18083f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
18093f03ced8SAlex Deucher 		if (ASIC_IS_DCE5(rdev)) {
18103f03ced8SAlex Deucher 			switch (mode) {
18113f03ced8SAlex Deucher 			case DRM_MODE_DPMS_ON:
18123f03ced8SAlex Deucher 				atombios_dvo_setup(encoder, ATOM_ENABLE);
18133f03ced8SAlex Deucher 				break;
18143f03ced8SAlex Deucher 			case DRM_MODE_DPMS_STANDBY:
18153f03ced8SAlex Deucher 			case DRM_MODE_DPMS_SUSPEND:
18163f03ced8SAlex Deucher 			case DRM_MODE_DPMS_OFF:
18173f03ced8SAlex Deucher 				atombios_dvo_setup(encoder, ATOM_DISABLE);
18183f03ced8SAlex Deucher 				break;
18193f03ced8SAlex Deucher 			}
18203f03ced8SAlex Deucher 		} else if (ASIC_IS_DCE3(rdev))
18213f03ced8SAlex Deucher 			radeon_atom_encoder_dpms_dig(encoder, mode);
18223f03ced8SAlex Deucher 		else
18233f03ced8SAlex Deucher 			radeon_atom_encoder_dpms_avivo(encoder, mode);
18243f03ced8SAlex Deucher 		break;
18253f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DAC1:
18263f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
18273f03ced8SAlex Deucher 		if (ASIC_IS_DCE5(rdev)) {
18283f03ced8SAlex Deucher 			switch (mode) {
18293f03ced8SAlex Deucher 			case DRM_MODE_DPMS_ON:
18303f03ced8SAlex Deucher 				atombios_dac_setup(encoder, ATOM_ENABLE);
18313f03ced8SAlex Deucher 				break;
18323f03ced8SAlex Deucher 			case DRM_MODE_DPMS_STANDBY:
18333f03ced8SAlex Deucher 			case DRM_MODE_DPMS_SUSPEND:
18343f03ced8SAlex Deucher 			case DRM_MODE_DPMS_OFF:
18353f03ced8SAlex Deucher 				atombios_dac_setup(encoder, ATOM_DISABLE);
18363f03ced8SAlex Deucher 				break;
18373f03ced8SAlex Deucher 			}
18383f03ced8SAlex Deucher 		} else
18393f03ced8SAlex Deucher 			radeon_atom_encoder_dpms_avivo(encoder, mode);
18403f03ced8SAlex Deucher 		break;
18413f03ced8SAlex Deucher 	default:
18423f03ced8SAlex Deucher 		return;
18433f03ced8SAlex Deucher 	}
18443f03ced8SAlex Deucher 
18453f03ced8SAlex Deucher 	radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
18463f03ced8SAlex Deucher 
18473f03ced8SAlex Deucher }
18483f03ced8SAlex Deucher 
18493f03ced8SAlex Deucher union crtc_source_param {
18503f03ced8SAlex Deucher 	SELECT_CRTC_SOURCE_PS_ALLOCATION v1;
18513f03ced8SAlex Deucher 	SELECT_CRTC_SOURCE_PARAMETERS_V2 v2;
18523f03ced8SAlex Deucher };
18533f03ced8SAlex Deucher 
18543f03ced8SAlex Deucher static void
18553f03ced8SAlex Deucher atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
18563f03ced8SAlex Deucher {
18573f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
18583f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
18593f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
18603f03ced8SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
18613f03ced8SAlex Deucher 	union crtc_source_param args;
18623f03ced8SAlex Deucher 	int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
18633f03ced8SAlex Deucher 	uint8_t frev, crev;
18643f03ced8SAlex Deucher 	struct radeon_encoder_atom_dig *dig;
18653f03ced8SAlex Deucher 
18663f03ced8SAlex Deucher 	memset(&args, 0, sizeof(args));
18673f03ced8SAlex Deucher 
18683f03ced8SAlex Deucher 	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
18693f03ced8SAlex Deucher 		return;
18703f03ced8SAlex Deucher 
18713f03ced8SAlex Deucher 	switch (frev) {
18723f03ced8SAlex Deucher 	case 1:
18733f03ced8SAlex Deucher 		switch (crev) {
18743f03ced8SAlex Deucher 		case 1:
18753f03ced8SAlex Deucher 		default:
18763f03ced8SAlex Deucher 			if (ASIC_IS_AVIVO(rdev))
18773f03ced8SAlex Deucher 				args.v1.ucCRTC = radeon_crtc->crtc_id;
18783f03ced8SAlex Deucher 			else {
18793c20d544SWambui Karuga 				if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1)
18803f03ced8SAlex Deucher 					args.v1.ucCRTC = radeon_crtc->crtc_id;
18813c20d544SWambui Karuga 				else
18823f03ced8SAlex Deucher 					args.v1.ucCRTC = radeon_crtc->crtc_id << 2;
18833f03ced8SAlex Deucher 			}
18843f03ced8SAlex Deucher 			switch (radeon_encoder->encoder_id) {
18853f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
18863f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
18873f03ced8SAlex Deucher 				args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX;
18883f03ced8SAlex Deucher 				break;
18893f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_LVDS:
18903f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
18913f03ced8SAlex Deucher 				if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT)
18923f03ced8SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX;
18933f03ced8SAlex Deucher 				else
18943f03ced8SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX;
18953f03ced8SAlex Deucher 				break;
18963f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_DVO1:
18973f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_DDI:
18983f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
18993f03ced8SAlex Deucher 				args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX;
19003f03ced8SAlex Deucher 				break;
19013f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_DAC1:
19023f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
19033f03ced8SAlex Deucher 				if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
19043f03ced8SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
19053f03ced8SAlex Deucher 				else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
19063f03ced8SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
19073f03ced8SAlex Deucher 				else
19083f03ced8SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX;
19093f03ced8SAlex Deucher 				break;
19103f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_DAC2:
19113f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
19123f03ced8SAlex Deucher 				if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
19133f03ced8SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
19143f03ced8SAlex Deucher 				else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
19153f03ced8SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
19163f03ced8SAlex Deucher 				else
19173f03ced8SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX;
19183f03ced8SAlex Deucher 				break;
19193f03ced8SAlex Deucher 			}
19203f03ced8SAlex Deucher 			break;
19213f03ced8SAlex Deucher 		case 2:
19223f03ced8SAlex Deucher 			args.v2.ucCRTC = radeon_crtc->crtc_id;
19233f03ced8SAlex Deucher 			if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) {
19243f03ced8SAlex Deucher 				struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
19253f03ced8SAlex Deucher 
19263f03ced8SAlex Deucher 				if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
19273f03ced8SAlex Deucher 					args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS;
19283f03ced8SAlex Deucher 				else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA)
19293f03ced8SAlex Deucher 					args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT;
19303f03ced8SAlex Deucher 				else
19313f03ced8SAlex Deucher 					args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder);
193264252835SAlex Deucher 			} else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
193364252835SAlex Deucher 				args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS;
193464252835SAlex Deucher 			} else {
19353f03ced8SAlex Deucher 				args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder);
193664252835SAlex Deucher 			}
19373f03ced8SAlex Deucher 			switch (radeon_encoder->encoder_id) {
19383f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
19393f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
19403f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1941e68adef8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
19423f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
19433f03ced8SAlex Deucher 				dig = radeon_encoder->enc_priv;
19443f03ced8SAlex Deucher 				switch (dig->dig_encoder) {
19453f03ced8SAlex Deucher 				case 0:
19463f03ced8SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
19473f03ced8SAlex Deucher 					break;
19483f03ced8SAlex Deucher 				case 1:
19493f03ced8SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
19503f03ced8SAlex Deucher 					break;
19513f03ced8SAlex Deucher 				case 2:
19523f03ced8SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID;
19533f03ced8SAlex Deucher 					break;
19543f03ced8SAlex Deucher 				case 3:
19553f03ced8SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID;
19563f03ced8SAlex Deucher 					break;
19573f03ced8SAlex Deucher 				case 4:
19583f03ced8SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID;
19593f03ced8SAlex Deucher 					break;
19603f03ced8SAlex Deucher 				case 5:
19613f03ced8SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
19623f03ced8SAlex Deucher 					break;
1963e68adef8SAlex Deucher 				case 6:
1964e68adef8SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID;
1965e68adef8SAlex Deucher 					break;
19663f03ced8SAlex Deucher 				}
19673f03ced8SAlex Deucher 				break;
19683f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
19693f03ced8SAlex Deucher 				args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID;
19703f03ced8SAlex Deucher 				break;
19713f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
19723f03ced8SAlex Deucher 				if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
19733f03ced8SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
19743f03ced8SAlex Deucher 				else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
19753f03ced8SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
19763f03ced8SAlex Deucher 				else
19773f03ced8SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
19783f03ced8SAlex Deucher 				break;
19793f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
19803f03ced8SAlex Deucher 				if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
19813f03ced8SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
19823f03ced8SAlex Deucher 				else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
19833f03ced8SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
19843f03ced8SAlex Deucher 				else
19853f03ced8SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
19863f03ced8SAlex Deucher 				break;
19873f03ced8SAlex Deucher 			}
19883f03ced8SAlex Deucher 			break;
19893f03ced8SAlex Deucher 		}
19903f03ced8SAlex Deucher 		break;
19913f03ced8SAlex Deucher 	default:
19923f03ced8SAlex Deucher 		DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
19933f03ced8SAlex Deucher 		return;
19943f03ced8SAlex Deucher 	}
19953f03ced8SAlex Deucher 
19963f03ced8SAlex Deucher 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
19973f03ced8SAlex Deucher 
19983f03ced8SAlex Deucher 	/* update scratch regs with new routing */
19993f03ced8SAlex Deucher 	radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
20003f03ced8SAlex Deucher }
20013f03ced8SAlex Deucher 
20029843ead0SDave Airlie void
20039843ead0SDave Airlie atombios_set_mst_encoder_crtc_source(struct drm_encoder *encoder, int fe)
20049843ead0SDave Airlie {
20059843ead0SDave Airlie 	struct drm_device *dev = encoder->dev;
20069843ead0SDave Airlie 	struct radeon_device *rdev = dev->dev_private;
20079843ead0SDave Airlie 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
20089843ead0SDave Airlie 	int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
20099843ead0SDave Airlie 	uint8_t frev, crev;
20109843ead0SDave Airlie 	union crtc_source_param args;
20119843ead0SDave Airlie 
20129843ead0SDave Airlie 	memset(&args, 0, sizeof(args));
20139843ead0SDave Airlie 
20149843ead0SDave Airlie 	if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
20159843ead0SDave Airlie 		return;
20169843ead0SDave Airlie 
20179843ead0SDave Airlie 	if (frev != 1 && crev != 2)
20189843ead0SDave Airlie 		DRM_ERROR("Unknown table for MST %d, %d\n", frev, crev);
20199843ead0SDave Airlie 
20209843ead0SDave Airlie 	args.v2.ucCRTC = radeon_crtc->crtc_id;
20219843ead0SDave Airlie 	args.v2.ucEncodeMode = ATOM_ENCODER_MODE_DP_MST;
20229843ead0SDave Airlie 
20239843ead0SDave Airlie 	switch (fe) {
20249843ead0SDave Airlie 	case 0:
20259843ead0SDave Airlie 		args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
20269843ead0SDave Airlie 		break;
20279843ead0SDave Airlie 	case 1:
20289843ead0SDave Airlie 		args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
20299843ead0SDave Airlie 		break;
20309843ead0SDave Airlie 	case 2:
20319843ead0SDave Airlie 		args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID;
20329843ead0SDave Airlie 		break;
20339843ead0SDave Airlie 	case 3:
20349843ead0SDave Airlie 		args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID;
20359843ead0SDave Airlie 		break;
20369843ead0SDave Airlie 	case 4:
20379843ead0SDave Airlie 		args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID;
20389843ead0SDave Airlie 		break;
20399843ead0SDave Airlie 	case 5:
20409843ead0SDave Airlie 		args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
20419843ead0SDave Airlie 		break;
20429843ead0SDave Airlie 	case 6:
20439843ead0SDave Airlie 		args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID;
20449843ead0SDave Airlie 		break;
20459843ead0SDave Airlie 	}
20469843ead0SDave Airlie 	atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
20479843ead0SDave Airlie }
20489843ead0SDave Airlie 
20493f03ced8SAlex Deucher static void
20503f03ced8SAlex Deucher atombios_apply_encoder_quirks(struct drm_encoder *encoder,
20513f03ced8SAlex Deucher 			      struct drm_display_mode *mode)
20523f03ced8SAlex Deucher {
20533f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
20543f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
20553f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
20563f03ced8SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
20573f03ced8SAlex Deucher 
20583f03ced8SAlex Deucher 	/* Funky macbooks */
2059d86a4126SThomas Zimmermann 	if ((rdev->pdev->device == 0x71C5) &&
2060d86a4126SThomas Zimmermann 	    (rdev->pdev->subsystem_vendor == 0x106b) &&
2061d86a4126SThomas Zimmermann 	    (rdev->pdev->subsystem_device == 0x0080)) {
20623f03ced8SAlex Deucher 		if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) {
20633f03ced8SAlex Deucher 			uint32_t lvtma_bit_depth_control = RREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL);
20643f03ced8SAlex Deucher 
20653f03ced8SAlex Deucher 			lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN;
20663f03ced8SAlex Deucher 			lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN;
20673f03ced8SAlex Deucher 
20683f03ced8SAlex Deucher 			WREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control);
20693f03ced8SAlex Deucher 		}
20703f03ced8SAlex Deucher 	}
20713f03ced8SAlex Deucher 
20723f03ced8SAlex Deucher 	/* set scaler clears this on some chips */
20733f03ced8SAlex Deucher 	if (ASIC_IS_AVIVO(rdev) &&
20743f03ced8SAlex Deucher 	    (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) {
2075d798f2f2SAlex Deucher 		if (ASIC_IS_DCE8(rdev)) {
2076d798f2f2SAlex Deucher 			if (mode->flags & DRM_MODE_FLAG_INTERLACE)
2077d798f2f2SAlex Deucher 				WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset,
2078d798f2f2SAlex Deucher 				       CIK_INTERLEAVE_EN);
2079d798f2f2SAlex Deucher 			else
2080d798f2f2SAlex Deucher 				WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
2081d798f2f2SAlex Deucher 		} else if (ASIC_IS_DCE4(rdev)) {
20823f03ced8SAlex Deucher 			if (mode->flags & DRM_MODE_FLAG_INTERLACE)
20833f03ced8SAlex Deucher 				WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset,
20843f03ced8SAlex Deucher 				       EVERGREEN_INTERLEAVE_EN);
20853f03ced8SAlex Deucher 			else
20863f03ced8SAlex Deucher 				WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
20873f03ced8SAlex Deucher 		} else {
20883f03ced8SAlex Deucher 			if (mode->flags & DRM_MODE_FLAG_INTERLACE)
20893f03ced8SAlex Deucher 				WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
20903f03ced8SAlex Deucher 				       AVIVO_D1MODE_INTERLEAVE_EN);
20913f03ced8SAlex Deucher 			else
20923f03ced8SAlex Deucher 				WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
20933f03ced8SAlex Deucher 		}
20943f03ced8SAlex Deucher 	}
20953f03ced8SAlex Deucher }
20963f03ced8SAlex Deucher 
20978f0fc088SDave Airlie void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx)
20988f0fc088SDave Airlie {
20998f0fc088SDave Airlie 	if (enc_idx < 0)
21008f0fc088SDave Airlie 		return;
21018f0fc088SDave Airlie 	rdev->mode_info.active_encoders &= ~(1 << enc_idx);
21028f0fc088SDave Airlie }
21038f0fc088SDave Airlie 
21048f0fc088SDave Airlie int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx)
21053f03ced8SAlex Deucher {
21063f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
21073f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
21083f03ced8SAlex Deucher 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
21093f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
21103f03ced8SAlex Deucher 	struct drm_encoder *test_encoder;
211141fa5437SAlex Deucher 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
21123f03ced8SAlex Deucher 	uint32_t dig_enc_in_use = 0;
21138f0fc088SDave Airlie 	int enc_idx = -1;
21143f03ced8SAlex Deucher 
21158f0fc088SDave Airlie 	if (fe_idx >= 0) {
21168f0fc088SDave Airlie 		enc_idx = fe_idx;
21178f0fc088SDave Airlie 		goto assigned;
21188f0fc088SDave Airlie 	}
211941fa5437SAlex Deucher 	if (ASIC_IS_DCE6(rdev)) {
212041fa5437SAlex Deucher 		/* DCE6 */
212141fa5437SAlex Deucher 		switch (radeon_encoder->encoder_id) {
212241fa5437SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
212341fa5437SAlex Deucher 			if (dig->linkb)
21248f0fc088SDave Airlie 				enc_idx = 1;
212541fa5437SAlex Deucher 			else
21268f0fc088SDave Airlie 				enc_idx = 0;
212741fa5437SAlex Deucher 			break;
212841fa5437SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
212941fa5437SAlex Deucher 			if (dig->linkb)
21308f0fc088SDave Airlie 				enc_idx = 3;
213141fa5437SAlex Deucher 			else
21328f0fc088SDave Airlie 				enc_idx = 2;
213341fa5437SAlex Deucher 			break;
213441fa5437SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
213541fa5437SAlex Deucher 			if (dig->linkb)
21368f0fc088SDave Airlie 				enc_idx = 5;
213741fa5437SAlex Deucher 			else
21388f0fc088SDave Airlie 				enc_idx = 4;
213941fa5437SAlex Deucher 			break;
2140e68adef8SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
21418f0fc088SDave Airlie 			enc_idx = 6;
2142e68adef8SAlex Deucher 			break;
214341fa5437SAlex Deucher 		}
21448f0fc088SDave Airlie 		goto assigned;
214541fa5437SAlex Deucher 	} else if (ASIC_IS_DCE4(rdev)) {
21463f03ced8SAlex Deucher 		/* DCE4/5 */
214741fa5437SAlex Deucher 		if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) {
21483f03ced8SAlex Deucher 			/* ontario follows DCE4 */
21493f03ced8SAlex Deucher 			if (rdev->family == CHIP_PALM) {
21503f03ced8SAlex Deucher 				if (dig->linkb)
21518f0fc088SDave Airlie 					enc_idx = 1;
21523f03ced8SAlex Deucher 				else
21538f0fc088SDave Airlie 					enc_idx = 0;
21543f03ced8SAlex Deucher 			} else
21553f03ced8SAlex Deucher 				/* llano follows DCE3.2 */
21568f0fc088SDave Airlie 				enc_idx = radeon_crtc->crtc_id;
21573f03ced8SAlex Deucher 		} else {
21583f03ced8SAlex Deucher 			switch (radeon_encoder->encoder_id) {
21593f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
21603f03ced8SAlex Deucher 				if (dig->linkb)
21618f0fc088SDave Airlie 					enc_idx = 1;
21623f03ced8SAlex Deucher 				else
21638f0fc088SDave Airlie 					enc_idx = 0;
21643f03ced8SAlex Deucher 				break;
21653f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
21663f03ced8SAlex Deucher 				if (dig->linkb)
21678f0fc088SDave Airlie 					enc_idx = 3;
21683f03ced8SAlex Deucher 				else
21698f0fc088SDave Airlie 					enc_idx = 2;
21703f03ced8SAlex Deucher 				break;
21713f03ced8SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
21723f03ced8SAlex Deucher 				if (dig->linkb)
21738f0fc088SDave Airlie 					enc_idx = 5;
21743f03ced8SAlex Deucher 				else
21758f0fc088SDave Airlie 					enc_idx = 4;
21763f03ced8SAlex Deucher 				break;
21773f03ced8SAlex Deucher 			}
21783f03ced8SAlex Deucher 		}
21798f0fc088SDave Airlie 		goto assigned;
21803f03ced8SAlex Deucher 	}
21813f03ced8SAlex Deucher 
2182564d8a2cSMario Kleiner 	/*
2183564d8a2cSMario Kleiner 	 * On DCE32 any encoder can drive any block so usually just use crtc id,
2184564d8a2cSMario Kleiner 	 * but Apple thinks different at least on iMac10,1, so there use linkb,
2185564d8a2cSMario Kleiner 	 * otherwise the internal eDP panel will stay dark.
2186564d8a2cSMario Kleiner 	 */
21873f03ced8SAlex Deucher 	if (ASIC_IS_DCE32(rdev)) {
2188564d8a2cSMario Kleiner 		if (dmi_match(DMI_PRODUCT_NAME, "iMac10,1"))
2189564d8a2cSMario Kleiner 			enc_idx = (dig->linkb) ? 1 : 0;
2190564d8a2cSMario Kleiner 		else
21918f0fc088SDave Airlie 			enc_idx = radeon_crtc->crtc_id;
2192564d8a2cSMario Kleiner 
21938f0fc088SDave Airlie 		goto assigned;
21943f03ced8SAlex Deucher 	}
21953f03ced8SAlex Deucher 
21963f03ced8SAlex Deucher 	/* on DCE3 - LVTMA can only be driven by DIGB */
21973f03ced8SAlex Deucher 	list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
21983f03ced8SAlex Deucher 		struct radeon_encoder *radeon_test_encoder;
21993f03ced8SAlex Deucher 
22003f03ced8SAlex Deucher 		if (encoder == test_encoder)
22013f03ced8SAlex Deucher 			continue;
22023f03ced8SAlex Deucher 
22033f03ced8SAlex Deucher 		if (!radeon_encoder_is_digital(test_encoder))
22043f03ced8SAlex Deucher 			continue;
22053f03ced8SAlex Deucher 
22063f03ced8SAlex Deucher 		radeon_test_encoder = to_radeon_encoder(test_encoder);
22073f03ced8SAlex Deucher 		dig = radeon_test_encoder->enc_priv;
22083f03ced8SAlex Deucher 
22093f03ced8SAlex Deucher 		if (dig->dig_encoder >= 0)
22103f03ced8SAlex Deucher 			dig_enc_in_use |= (1 << dig->dig_encoder);
22113f03ced8SAlex Deucher 	}
22123f03ced8SAlex Deucher 
22133f03ced8SAlex Deucher 	if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) {
22143f03ced8SAlex Deucher 		if (dig_enc_in_use & 0x2)
22153f03ced8SAlex Deucher 			DRM_ERROR("LVDS required digital encoder 2 but it was in use - stealing\n");
22163f03ced8SAlex Deucher 		return 1;
22173f03ced8SAlex Deucher 	}
22183f03ced8SAlex Deucher 	if (!(dig_enc_in_use & 1))
22193f03ced8SAlex Deucher 		return 0;
22203f03ced8SAlex Deucher 	return 1;
22218f0fc088SDave Airlie 
22228f0fc088SDave Airlie assigned:
22238f0fc088SDave Airlie 	if (enc_idx == -1) {
22248f0fc088SDave Airlie 		DRM_ERROR("Got encoder index incorrect - returning 0\n");
22258f0fc088SDave Airlie 		return 0;
22268f0fc088SDave Airlie 	}
22273c20d544SWambui Karuga 	if (rdev->mode_info.active_encoders & (1 << enc_idx))
22288f0fc088SDave Airlie 		DRM_ERROR("chosen encoder in use %d\n", enc_idx);
22293c20d544SWambui Karuga 
22308f0fc088SDave Airlie 	rdev->mode_info.active_encoders |= (1 << enc_idx);
22318f0fc088SDave Airlie 	return enc_idx;
22323f03ced8SAlex Deucher }
22333f03ced8SAlex Deucher 
22343f03ced8SAlex Deucher /* This only needs to be called once at startup */
22353f03ced8SAlex Deucher void
22363f03ced8SAlex Deucher radeon_atom_encoder_init(struct radeon_device *rdev)
22373f03ced8SAlex Deucher {
22383f03ced8SAlex Deucher 	struct drm_device *dev = rdev->ddev;
22393f03ced8SAlex Deucher 	struct drm_encoder *encoder;
22403f03ced8SAlex Deucher 
22413f03ced8SAlex Deucher 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
22423f03ced8SAlex Deucher 		struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
22433f03ced8SAlex Deucher 		struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder);
22443f03ced8SAlex Deucher 
22453f03ced8SAlex Deucher 		switch (radeon_encoder->encoder_id) {
22463f03ced8SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
22473f03ced8SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
22483f03ced8SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
2249e68adef8SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
22503f03ced8SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
22513f03ced8SAlex Deucher 			atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
22523f03ced8SAlex Deucher 			break;
22533f03ced8SAlex Deucher 		default:
22543f03ced8SAlex Deucher 			break;
22553f03ced8SAlex Deucher 		}
22563f03ced8SAlex Deucher 
22571d3949c4SAlex Deucher 		if (ext_encoder && (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)))
22583f03ced8SAlex Deucher 			atombios_external_encoder_setup(encoder, ext_encoder,
22593f03ced8SAlex Deucher 							EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
22603f03ced8SAlex Deucher 	}
22613f03ced8SAlex Deucher }
22623f03ced8SAlex Deucher 
22633f03ced8SAlex Deucher static void
22643f03ced8SAlex Deucher radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
22653f03ced8SAlex Deucher 			     struct drm_display_mode *mode,
22663f03ced8SAlex Deucher 			     struct drm_display_mode *adjusted_mode)
22673f03ced8SAlex Deucher {
22683f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
22693f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
22703f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
22713473f542SAlex Deucher 	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
22726f945693SSlava Grigorev 	int encoder_mode;
22733f03ced8SAlex Deucher 
22743f03ced8SAlex Deucher 	radeon_encoder->pixel_clock = adjusted_mode->clock;
22753f03ced8SAlex Deucher 
22768d1af57aSAlex Deucher 	/* need to call this here rather than in prepare() since we need some crtc info */
22778d1af57aSAlex Deucher 	radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
22788d1af57aSAlex Deucher 
22793f03ced8SAlex Deucher 	if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE4(rdev)) {
22803f03ced8SAlex Deucher 		if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))
22813f03ced8SAlex Deucher 			atombios_yuv_setup(encoder, true);
22823f03ced8SAlex Deucher 		else
22833f03ced8SAlex Deucher 			atombios_yuv_setup(encoder, false);
22843f03ced8SAlex Deucher 	}
22853f03ced8SAlex Deucher 
22863f03ced8SAlex Deucher 	switch (radeon_encoder->encoder_id) {
22873f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
22883f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
22893f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_LVDS:
22903f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
22913f03ced8SAlex Deucher 		atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_ENABLE);
22923f03ced8SAlex Deucher 		break;
22933f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
22943f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
22953f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
2296e68adef8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
22973f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
22988d1af57aSAlex Deucher 		/* handled in dpms */
22993f03ced8SAlex Deucher 		break;
23003f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DDI:
23013f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DVO1:
23023f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
23033f03ced8SAlex Deucher 		atombios_dvo_setup(encoder, ATOM_ENABLE);
23043f03ced8SAlex Deucher 		break;
23053f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DAC1:
23063f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
23073f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DAC2:
23083f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
23093f03ced8SAlex Deucher 		atombios_dac_setup(encoder, ATOM_ENABLE);
23103f03ced8SAlex Deucher 		if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) {
23113f03ced8SAlex Deucher 			if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
23123f03ced8SAlex Deucher 				atombios_tv_setup(encoder, ATOM_ENABLE);
23133f03ced8SAlex Deucher 			else
23143f03ced8SAlex Deucher 				atombios_tv_setup(encoder, ATOM_DISABLE);
23153f03ced8SAlex Deucher 		}
23163f03ced8SAlex Deucher 		break;
23173f03ced8SAlex Deucher 	}
23183f03ced8SAlex Deucher 
23193f03ced8SAlex Deucher 	atombios_apply_encoder_quirks(encoder, adjusted_mode);
23205c046a57SAlex Deucher 
23215c046a57SAlex Deucher 	encoder_mode = atombios_get_encoder_mode(encoder);
23225c046a57SAlex Deucher 	if (connector && (radeon_audio != 0) &&
23235c046a57SAlex Deucher 	    ((encoder_mode == ATOM_ENCODER_MODE_HDMI) ||
23247726e72bSAlex Deucher 	     ENCODER_MODE_IS_DP(encoder_mode)))
23255c046a57SAlex Deucher 		radeon_audio_mode_set(encoder, adjusted_mode);
23263f03ced8SAlex Deucher }
23273f03ced8SAlex Deucher 
23283f03ced8SAlex Deucher static bool
23293f03ced8SAlex Deucher atombios_dac_load_detect(struct drm_encoder *encoder, struct drm_connector *connector)
23303f03ced8SAlex Deucher {
23313f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
23323f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
23333f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
23343f03ced8SAlex Deucher 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
23353f03ced8SAlex Deucher 
23363f03ced8SAlex Deucher 	if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT |
23373f03ced8SAlex Deucher 				       ATOM_DEVICE_CV_SUPPORT |
23383f03ced8SAlex Deucher 				       ATOM_DEVICE_CRT_SUPPORT)) {
23393f03ced8SAlex Deucher 		DAC_LOAD_DETECTION_PS_ALLOCATION args;
23403f03ced8SAlex Deucher 		int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection);
23413f03ced8SAlex Deucher 		uint8_t frev, crev;
23423f03ced8SAlex Deucher 
23433f03ced8SAlex Deucher 		memset(&args, 0, sizeof(args));
23443f03ced8SAlex Deucher 
23453f03ced8SAlex Deucher 		if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
23463f03ced8SAlex Deucher 			return false;
23473f03ced8SAlex Deucher 
23483f03ced8SAlex Deucher 		args.sDacload.ucMisc = 0;
23493f03ced8SAlex Deucher 
23503f03ced8SAlex Deucher 		if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
23513f03ced8SAlex Deucher 		    (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1))
23523f03ced8SAlex Deucher 			args.sDacload.ucDacType = ATOM_DAC_A;
23533f03ced8SAlex Deucher 		else
23543f03ced8SAlex Deucher 			args.sDacload.ucDacType = ATOM_DAC_B;
23553f03ced8SAlex Deucher 
23563f03ced8SAlex Deucher 		if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)
23573f03ced8SAlex Deucher 			args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT);
23583f03ced8SAlex Deucher 		else if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)
23593f03ced8SAlex Deucher 			args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT);
23603f03ced8SAlex Deucher 		else if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) {
23613f03ced8SAlex Deucher 			args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT);
23623f03ced8SAlex Deucher 			if (crev >= 3)
23633f03ced8SAlex Deucher 				args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
23643f03ced8SAlex Deucher 		} else if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) {
23653f03ced8SAlex Deucher 			args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT);
23663f03ced8SAlex Deucher 			if (crev >= 3)
23673f03ced8SAlex Deucher 				args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
23683f03ced8SAlex Deucher 		}
23693f03ced8SAlex Deucher 
23703f03ced8SAlex Deucher 		atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
23713f03ced8SAlex Deucher 
23723f03ced8SAlex Deucher 		return true;
23733f03ced8SAlex Deucher 	} else
23743f03ced8SAlex Deucher 		return false;
23753f03ced8SAlex Deucher }
23763f03ced8SAlex Deucher 
23773f03ced8SAlex Deucher static enum drm_connector_status
23783f03ced8SAlex Deucher radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
23793f03ced8SAlex Deucher {
23803f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
23813f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
23823f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
23833f03ced8SAlex Deucher 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
23843f03ced8SAlex Deucher 	uint32_t bios_0_scratch;
23853f03ced8SAlex Deucher 
23863f03ced8SAlex Deucher 	if (!atombios_dac_load_detect(encoder, connector)) {
23873f03ced8SAlex Deucher 		DRM_DEBUG_KMS("detect returned false \n");
23883f03ced8SAlex Deucher 		return connector_status_unknown;
23893f03ced8SAlex Deucher 	}
23903f03ced8SAlex Deucher 
23913f03ced8SAlex Deucher 	if (rdev->family >= CHIP_R600)
23923f03ced8SAlex Deucher 		bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH);
23933f03ced8SAlex Deucher 	else
23943f03ced8SAlex Deucher 		bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH);
23953f03ced8SAlex Deucher 
23963f03ced8SAlex Deucher 	DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices);
23973f03ced8SAlex Deucher 	if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) {
23983f03ced8SAlex Deucher 		if (bios_0_scratch & ATOM_S0_CRT1_MASK)
23993f03ced8SAlex Deucher 			return connector_status_connected;
24003f03ced8SAlex Deucher 	}
24013f03ced8SAlex Deucher 	if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) {
24023f03ced8SAlex Deucher 		if (bios_0_scratch & ATOM_S0_CRT2_MASK)
24033f03ced8SAlex Deucher 			return connector_status_connected;
24043f03ced8SAlex Deucher 	}
24053f03ced8SAlex Deucher 	if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) {
24063f03ced8SAlex Deucher 		if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A))
24073f03ced8SAlex Deucher 			return connector_status_connected;
24083f03ced8SAlex Deucher 	}
24093f03ced8SAlex Deucher 	if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) {
24103f03ced8SAlex Deucher 		if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
24113f03ced8SAlex Deucher 			return connector_status_connected; /* CTV */
24123f03ced8SAlex Deucher 		else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
24133f03ced8SAlex Deucher 			return connector_status_connected; /* STV */
24143f03ced8SAlex Deucher 	}
24153f03ced8SAlex Deucher 	return connector_status_disconnected;
24163f03ced8SAlex Deucher }
24173f03ced8SAlex Deucher 
24183f03ced8SAlex Deucher static enum drm_connector_status
24193f03ced8SAlex Deucher radeon_atom_dig_detect(struct drm_encoder *encoder, struct drm_connector *connector)
24203f03ced8SAlex Deucher {
24213f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
24223f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
24233f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
24243f03ced8SAlex Deucher 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
24253f03ced8SAlex Deucher 	struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder);
24263f03ced8SAlex Deucher 	u32 bios_0_scratch;
24273f03ced8SAlex Deucher 
24283f03ced8SAlex Deucher 	if (!ASIC_IS_DCE4(rdev))
24293f03ced8SAlex Deucher 		return connector_status_unknown;
24303f03ced8SAlex Deucher 
24313f03ced8SAlex Deucher 	if (!ext_encoder)
24323f03ced8SAlex Deucher 		return connector_status_unknown;
24333f03ced8SAlex Deucher 
24343f03ced8SAlex Deucher 	if ((radeon_connector->devices & ATOM_DEVICE_CRT_SUPPORT) == 0)
24353f03ced8SAlex Deucher 		return connector_status_unknown;
24363f03ced8SAlex Deucher 
24373f03ced8SAlex Deucher 	/* load detect on the dp bridge */
24383f03ced8SAlex Deucher 	atombios_external_encoder_setup(encoder, ext_encoder,
24393f03ced8SAlex Deucher 					EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION);
24403f03ced8SAlex Deucher 
24413f03ced8SAlex Deucher 	bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH);
24423f03ced8SAlex Deucher 
24433f03ced8SAlex Deucher 	DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices);
24443f03ced8SAlex Deucher 	if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) {
24453f03ced8SAlex Deucher 		if (bios_0_scratch & ATOM_S0_CRT1_MASK)
24463f03ced8SAlex Deucher 			return connector_status_connected;
24473f03ced8SAlex Deucher 	}
24483f03ced8SAlex Deucher 	if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) {
24493f03ced8SAlex Deucher 		if (bios_0_scratch & ATOM_S0_CRT2_MASK)
24503f03ced8SAlex Deucher 			return connector_status_connected;
24513f03ced8SAlex Deucher 	}
24523f03ced8SAlex Deucher 	if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) {
24533f03ced8SAlex Deucher 		if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A))
24543f03ced8SAlex Deucher 			return connector_status_connected;
24553f03ced8SAlex Deucher 	}
24563f03ced8SAlex Deucher 	if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) {
24573f03ced8SAlex Deucher 		if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
24583f03ced8SAlex Deucher 			return connector_status_connected; /* CTV */
24593f03ced8SAlex Deucher 		else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
24603f03ced8SAlex Deucher 			return connector_status_connected; /* STV */
24613f03ced8SAlex Deucher 	}
24623f03ced8SAlex Deucher 	return connector_status_disconnected;
24633f03ced8SAlex Deucher }
24643f03ced8SAlex Deucher 
24653f03ced8SAlex Deucher void
24663f03ced8SAlex Deucher radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder)
24673f03ced8SAlex Deucher {
24683f03ced8SAlex Deucher 	struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder);
24693f03ced8SAlex Deucher 
24703f03ced8SAlex Deucher 	if (ext_encoder)
24713f03ced8SAlex Deucher 		/* ddc_setup on the dp bridge */
24723f03ced8SAlex Deucher 		atombios_external_encoder_setup(encoder, ext_encoder,
24733f03ced8SAlex Deucher 						EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP);
24743f03ced8SAlex Deucher 
24753f03ced8SAlex Deucher }
24763f03ced8SAlex Deucher 
24773f03ced8SAlex Deucher static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
24783f03ced8SAlex Deucher {
2479cfcbd6d3SRafał Miłecki 	struct radeon_device *rdev = encoder->dev->dev_private;
24803f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
24813f03ced8SAlex Deucher 	struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
24823f03ced8SAlex Deucher 
24833f03ced8SAlex Deucher 	if ((radeon_encoder->active_device &
24843f03ced8SAlex Deucher 	     (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) ||
24853f03ced8SAlex Deucher 	    (radeon_encoder_get_dp_bridge_encoder_id(encoder) !=
24863f03ced8SAlex Deucher 	     ENCODER_OBJECT_ID_NONE)) {
24873f03ced8SAlex Deucher 		struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
2488cfcbd6d3SRafał Miłecki 		if (dig) {
24898f0fc088SDave Airlie 			if (dig->dig_encoder >= 0)
24908f0fc088SDave Airlie 				radeon_atom_release_dig_encoder(rdev, dig->dig_encoder);
24918f0fc088SDave Airlie 			dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder, -1);
2492cfcbd6d3SRafał Miłecki 			if (radeon_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT) {
2493cfcbd6d3SRafał Miłecki 				if (rdev->family >= CHIP_R600)
2494cfcbd6d3SRafał Miłecki 					dig->afmt = rdev->mode_info.afmt[dig->dig_encoder];
2495cfcbd6d3SRafał Miłecki 				else
2496cfcbd6d3SRafał Miłecki 					/* RS600/690/740 have only 1 afmt block */
2497cfcbd6d3SRafał Miłecki 					dig->afmt = rdev->mode_info.afmt[0];
2498cfcbd6d3SRafał Miłecki 			}
2499cfcbd6d3SRafał Miłecki 		}
25003f03ced8SAlex Deucher 	}
25013f03ced8SAlex Deucher 
25023f03ced8SAlex Deucher 	radeon_atom_output_lock(encoder, true);
25033f03ced8SAlex Deucher 
25043f03ced8SAlex Deucher 	if (connector) {
25053f03ced8SAlex Deucher 		struct radeon_connector *radeon_connector = to_radeon_connector(connector);
25063f03ced8SAlex Deucher 
25073f03ced8SAlex Deucher 		/* select the clock/data port if it uses a router */
25083f03ced8SAlex Deucher 		if (radeon_connector->router.cd_valid)
25093f03ced8SAlex Deucher 			radeon_router_select_cd_port(radeon_connector);
25103f03ced8SAlex Deucher 
25113f03ced8SAlex Deucher 		/* turn eDP panel on for mode set */
25123f03ced8SAlex Deucher 		if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
25133f03ced8SAlex Deucher 			atombios_set_edp_panel_power(connector,
25143f03ced8SAlex Deucher 						     ATOM_TRANSMITTER_ACTION_POWER_ON);
25153f03ced8SAlex Deucher 	}
25163f03ced8SAlex Deucher 
25173f03ced8SAlex Deucher 	/* this is needed for the pll/ss setup to work correctly in some cases */
25183f03ced8SAlex Deucher 	atombios_set_encoder_crtc_source(encoder);
2519134b480fSAlex Deucher 	/* set up the FMT blocks */
2520134b480fSAlex Deucher 	if (ASIC_IS_DCE8(rdev))
2521134b480fSAlex Deucher 		dce8_program_fmt(encoder);
2522134b480fSAlex Deucher 	else if (ASIC_IS_DCE4(rdev))
2523134b480fSAlex Deucher 		dce4_program_fmt(encoder);
2524134b480fSAlex Deucher 	else if (ASIC_IS_DCE3(rdev))
2525134b480fSAlex Deucher 		dce3_program_fmt(encoder);
2526134b480fSAlex Deucher 	else if (ASIC_IS_AVIVO(rdev))
2527134b480fSAlex Deucher 		avivo_program_fmt(encoder);
25283f03ced8SAlex Deucher }
25293f03ced8SAlex Deucher 
25303f03ced8SAlex Deucher static void radeon_atom_encoder_commit(struct drm_encoder *encoder)
25313f03ced8SAlex Deucher {
25328d1af57aSAlex Deucher 	/* need to call this here as we need the crtc set up */
25333f03ced8SAlex Deucher 	radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
25343f03ced8SAlex Deucher 	radeon_atom_output_lock(encoder, false);
25353f03ced8SAlex Deucher }
25363f03ced8SAlex Deucher 
25373f03ced8SAlex Deucher static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
25383f03ced8SAlex Deucher {
25393f03ced8SAlex Deucher 	struct drm_device *dev = encoder->dev;
25403f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
25413f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
25423f03ced8SAlex Deucher 	struct radeon_encoder_atom_dig *dig;
25433f03ced8SAlex Deucher 
25443f03ced8SAlex Deucher 	/* check for pre-DCE3 cards with shared encoders;
25453f03ced8SAlex Deucher 	 * can't really use the links individually, so don't disable
25463f03ced8SAlex Deucher 	 * the encoder if it's in use by another connector
25473f03ced8SAlex Deucher 	 */
25483f03ced8SAlex Deucher 	if (!ASIC_IS_DCE3(rdev)) {
25493f03ced8SAlex Deucher 		struct drm_encoder *other_encoder;
25503f03ced8SAlex Deucher 		struct radeon_encoder *other_radeon_encoder;
25513f03ced8SAlex Deucher 
25523f03ced8SAlex Deucher 		list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) {
25533f03ced8SAlex Deucher 			other_radeon_encoder = to_radeon_encoder(other_encoder);
25543f03ced8SAlex Deucher 			if ((radeon_encoder->encoder_id == other_radeon_encoder->encoder_id) &&
25553f03ced8SAlex Deucher 			    drm_helper_encoder_in_use(other_encoder))
25563f03ced8SAlex Deucher 				goto disable_done;
25573f03ced8SAlex Deucher 		}
25583f03ced8SAlex Deucher 	}
25593f03ced8SAlex Deucher 
25603f03ced8SAlex Deucher 	radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
25613f03ced8SAlex Deucher 
25623f03ced8SAlex Deucher 	switch (radeon_encoder->encoder_id) {
25633f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
25643f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
25653f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_LVDS:
25663f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
25673f03ced8SAlex Deucher 		atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_DISABLE);
25683f03ced8SAlex Deucher 		break;
25693f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
25703f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
25713f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
2572e68adef8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
25733f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
25748d1af57aSAlex Deucher 		/* handled in dpms */
25753f03ced8SAlex Deucher 		break;
25763f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DDI:
25773f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DVO1:
25783f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
25793f03ced8SAlex Deucher 		atombios_dvo_setup(encoder, ATOM_DISABLE);
25803f03ced8SAlex Deucher 		break;
25813f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DAC1:
25823f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
25833f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DAC2:
25843f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
25853f03ced8SAlex Deucher 		atombios_dac_setup(encoder, ATOM_DISABLE);
25863f03ced8SAlex Deucher 		if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
25873f03ced8SAlex Deucher 			atombios_tv_setup(encoder, ATOM_DISABLE);
25883f03ced8SAlex Deucher 		break;
25893f03ced8SAlex Deucher 	}
25903f03ced8SAlex Deucher 
25913f03ced8SAlex Deucher disable_done:
25923f03ced8SAlex Deucher 	if (radeon_encoder_is_digital(encoder)) {
25938f0fc088SDave Airlie 		if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
25948f0fc088SDave Airlie 			if (rdev->asic->display.hdmi_enable)
25958f0fc088SDave Airlie 				radeon_hdmi_enable(rdev, encoder, false);
25963f03ced8SAlex Deucher 		}
25978f0fc088SDave Airlie 		if (atombios_get_encoder_mode(encoder) != ATOM_ENCODER_MODE_DP_MST) {
25988f0fc088SDave Airlie 			dig = radeon_encoder->enc_priv;
25998f0fc088SDave Airlie 			radeon_atom_release_dig_encoder(rdev, dig->dig_encoder);
26008f0fc088SDave Airlie 			dig->dig_encoder = -1;
26018f0fc088SDave Airlie 			radeon_encoder->active_device = 0;
26028f0fc088SDave Airlie 		}
26038f0fc088SDave Airlie 	} else
26043f03ced8SAlex Deucher 		radeon_encoder->active_device = 0;
26053f03ced8SAlex Deucher }
26063f03ced8SAlex Deucher 
26073f03ced8SAlex Deucher /* these are handled by the primary encoders */
26083f03ced8SAlex Deucher static void radeon_atom_ext_prepare(struct drm_encoder *encoder)
26093f03ced8SAlex Deucher {
26103f03ced8SAlex Deucher 
26113f03ced8SAlex Deucher }
26123f03ced8SAlex Deucher 
26133f03ced8SAlex Deucher static void radeon_atom_ext_commit(struct drm_encoder *encoder)
26143f03ced8SAlex Deucher {
26153f03ced8SAlex Deucher 
26163f03ced8SAlex Deucher }
26173f03ced8SAlex Deucher 
26183f03ced8SAlex Deucher static void
26193f03ced8SAlex Deucher radeon_atom_ext_mode_set(struct drm_encoder *encoder,
26203f03ced8SAlex Deucher 			 struct drm_display_mode *mode,
26213f03ced8SAlex Deucher 			 struct drm_display_mode *adjusted_mode)
26223f03ced8SAlex Deucher {
26233f03ced8SAlex Deucher 
26243f03ced8SAlex Deucher }
26253f03ced8SAlex Deucher 
26263f03ced8SAlex Deucher static void radeon_atom_ext_disable(struct drm_encoder *encoder)
26273f03ced8SAlex Deucher {
26283f03ced8SAlex Deucher 
26293f03ced8SAlex Deucher }
26303f03ced8SAlex Deucher 
26313f03ced8SAlex Deucher static void
26323f03ced8SAlex Deucher radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode)
26333f03ced8SAlex Deucher {
26343f03ced8SAlex Deucher 
26353f03ced8SAlex Deucher }
26363f03ced8SAlex Deucher 
26373f03ced8SAlex Deucher static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = {
26383f03ced8SAlex Deucher 	.dpms = radeon_atom_ext_dpms,
26393f03ced8SAlex Deucher 	.prepare = radeon_atom_ext_prepare,
26403f03ced8SAlex Deucher 	.mode_set = radeon_atom_ext_mode_set,
26413f03ced8SAlex Deucher 	.commit = radeon_atom_ext_commit,
26423f03ced8SAlex Deucher 	.disable = radeon_atom_ext_disable,
26433f03ced8SAlex Deucher 	/* no detect for TMDS/LVDS yet */
26443f03ced8SAlex Deucher };
26453f03ced8SAlex Deucher 
26463f03ced8SAlex Deucher static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = {
26473f03ced8SAlex Deucher 	.dpms = radeon_atom_encoder_dpms,
26483f03ced8SAlex Deucher 	.mode_fixup = radeon_atom_mode_fixup,
26493f03ced8SAlex Deucher 	.prepare = radeon_atom_encoder_prepare,
26503f03ced8SAlex Deucher 	.mode_set = radeon_atom_encoder_mode_set,
26513f03ced8SAlex Deucher 	.commit = radeon_atom_encoder_commit,
26523f03ced8SAlex Deucher 	.disable = radeon_atom_encoder_disable,
26533f03ced8SAlex Deucher 	.detect = radeon_atom_dig_detect,
26543f03ced8SAlex Deucher };
26553f03ced8SAlex Deucher 
26563f03ced8SAlex Deucher static const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = {
26573f03ced8SAlex Deucher 	.dpms = radeon_atom_encoder_dpms,
26583f03ced8SAlex Deucher 	.mode_fixup = radeon_atom_mode_fixup,
26593f03ced8SAlex Deucher 	.prepare = radeon_atom_encoder_prepare,
26603f03ced8SAlex Deucher 	.mode_set = radeon_atom_encoder_mode_set,
26613f03ced8SAlex Deucher 	.commit = radeon_atom_encoder_commit,
26623f03ced8SAlex Deucher 	.detect = radeon_atom_dac_detect,
26633f03ced8SAlex Deucher };
26643f03ced8SAlex Deucher 
26653f03ced8SAlex Deucher void radeon_enc_destroy(struct drm_encoder *encoder)
26663f03ced8SAlex Deucher {
26673f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
2668f3728734SAlex Deucher 	if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
2669f3728734SAlex Deucher 		radeon_atom_backlight_exit(radeon_encoder);
26703f03ced8SAlex Deucher 	kfree(radeon_encoder->enc_priv);
26713f03ced8SAlex Deucher 	drm_encoder_cleanup(encoder);
26723f03ced8SAlex Deucher 	kfree(radeon_encoder);
26733f03ced8SAlex Deucher }
26743f03ced8SAlex Deucher 
26753f03ced8SAlex Deucher static const struct drm_encoder_funcs radeon_atom_enc_funcs = {
26763f03ced8SAlex Deucher 	.destroy = radeon_enc_destroy,
26773f03ced8SAlex Deucher };
26783f03ced8SAlex Deucher 
26791109ca09SLauri Kasanen static struct radeon_encoder_atom_dac *
26803f03ced8SAlex Deucher radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder)
26813f03ced8SAlex Deucher {
26823f03ced8SAlex Deucher 	struct drm_device *dev = radeon_encoder->base.dev;
26833f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
26843f03ced8SAlex Deucher 	struct radeon_encoder_atom_dac *dac = kzalloc(sizeof(struct radeon_encoder_atom_dac), GFP_KERNEL);
26853f03ced8SAlex Deucher 
26863f03ced8SAlex Deucher 	if (!dac)
26873f03ced8SAlex Deucher 		return NULL;
26883f03ced8SAlex Deucher 
26893f03ced8SAlex Deucher 	dac->tv_std = radeon_atombios_get_tv_info(rdev);
26903f03ced8SAlex Deucher 	return dac;
26913f03ced8SAlex Deucher }
26923f03ced8SAlex Deucher 
26931109ca09SLauri Kasanen static struct radeon_encoder_atom_dig *
26943f03ced8SAlex Deucher radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder)
26953f03ced8SAlex Deucher {
26963f03ced8SAlex Deucher 	int encoder_enum = (radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
26973f03ced8SAlex Deucher 	struct radeon_encoder_atom_dig *dig = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL);
26983f03ced8SAlex Deucher 
26993f03ced8SAlex Deucher 	if (!dig)
27003f03ced8SAlex Deucher 		return NULL;
27013f03ced8SAlex Deucher 
27023f03ced8SAlex Deucher 	/* coherent mode by default */
27033f03ced8SAlex Deucher 	dig->coherent_mode = true;
27043f03ced8SAlex Deucher 	dig->dig_encoder = -1;
27053f03ced8SAlex Deucher 
27063f03ced8SAlex Deucher 	if (encoder_enum == 2)
27073f03ced8SAlex Deucher 		dig->linkb = true;
27083f03ced8SAlex Deucher 	else
27093f03ced8SAlex Deucher 		dig->linkb = false;
27103f03ced8SAlex Deucher 
27113f03ced8SAlex Deucher 	return dig;
27123f03ced8SAlex Deucher }
27133f03ced8SAlex Deucher 
27143f03ced8SAlex Deucher void
27153f03ced8SAlex Deucher radeon_add_atom_encoder(struct drm_device *dev,
27163f03ced8SAlex Deucher 			uint32_t encoder_enum,
27173f03ced8SAlex Deucher 			uint32_t supported_device,
27183f03ced8SAlex Deucher 			u16 caps)
27193f03ced8SAlex Deucher {
27203f03ced8SAlex Deucher 	struct radeon_device *rdev = dev->dev_private;
27213f03ced8SAlex Deucher 	struct drm_encoder *encoder;
27223f03ced8SAlex Deucher 	struct radeon_encoder *radeon_encoder;
27233f03ced8SAlex Deucher 
27243f03ced8SAlex Deucher 	/* see if we already added it */
27253f03ced8SAlex Deucher 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
27263f03ced8SAlex Deucher 		radeon_encoder = to_radeon_encoder(encoder);
27273f03ced8SAlex Deucher 		if (radeon_encoder->encoder_enum == encoder_enum) {
27283f03ced8SAlex Deucher 			radeon_encoder->devices |= supported_device;
27293f03ced8SAlex Deucher 			return;
27303f03ced8SAlex Deucher 		}
27313f03ced8SAlex Deucher 
27323f03ced8SAlex Deucher 	}
27333f03ced8SAlex Deucher 
27343f03ced8SAlex Deucher 	/* add a new one */
27353f03ced8SAlex Deucher 	radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL);
27363f03ced8SAlex Deucher 	if (!radeon_encoder)
27373f03ced8SAlex Deucher 		return;
27383f03ced8SAlex Deucher 
27393f03ced8SAlex Deucher 	encoder = &radeon_encoder->base;
27403f03ced8SAlex Deucher 	switch (rdev->num_crtc) {
27413f03ced8SAlex Deucher 	case 1:
27423f03ced8SAlex Deucher 		encoder->possible_crtcs = 0x1;
27433f03ced8SAlex Deucher 		break;
27443f03ced8SAlex Deucher 	case 2:
27453f03ced8SAlex Deucher 	default:
27463f03ced8SAlex Deucher 		encoder->possible_crtcs = 0x3;
27473f03ced8SAlex Deucher 		break;
27483f03ced8SAlex Deucher 	case 4:
27493f03ced8SAlex Deucher 		encoder->possible_crtcs = 0xf;
27503f03ced8SAlex Deucher 		break;
27513f03ced8SAlex Deucher 	case 6:
27523f03ced8SAlex Deucher 		encoder->possible_crtcs = 0x3f;
27533f03ced8SAlex Deucher 		break;
27543f03ced8SAlex Deucher 	}
27553f03ced8SAlex Deucher 
27563f03ced8SAlex Deucher 	radeon_encoder->enc_priv = NULL;
27573f03ced8SAlex Deucher 
27583f03ced8SAlex Deucher 	radeon_encoder->encoder_enum = encoder_enum;
27593f03ced8SAlex Deucher 	radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
27603f03ced8SAlex Deucher 	radeon_encoder->devices = supported_device;
27613f03ced8SAlex Deucher 	radeon_encoder->rmx_type = RMX_OFF;
27623f03ced8SAlex Deucher 	radeon_encoder->underscan_type = UNDERSCAN_OFF;
27633f03ced8SAlex Deucher 	radeon_encoder->is_ext_encoder = false;
27643f03ced8SAlex Deucher 	radeon_encoder->caps = caps;
27653f03ced8SAlex Deucher 
27663f03ced8SAlex Deucher 	switch (radeon_encoder->encoder_id) {
27673f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_LVDS:
27683f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
27693f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
27703f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
27713f03ced8SAlex Deucher 		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
27723f03ced8SAlex Deucher 			radeon_encoder->rmx_type = RMX_FULL;
277313a3d91fSVille Syrjälä 			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
277413a3d91fSVille Syrjälä 					 DRM_MODE_ENCODER_LVDS, NULL);
27753f03ced8SAlex Deucher 			radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder);
27763f03ced8SAlex Deucher 		} else {
277713a3d91fSVille Syrjälä 			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
277813a3d91fSVille Syrjälä 					 DRM_MODE_ENCODER_TMDS, NULL);
27793f03ced8SAlex Deucher 			radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
27803f03ced8SAlex Deucher 		}
27813f03ced8SAlex Deucher 		drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
27823f03ced8SAlex Deucher 		break;
27833f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DAC1:
278413a3d91fSVille Syrjälä 		drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
278513a3d91fSVille Syrjälä 				 DRM_MODE_ENCODER_DAC, NULL);
27863f03ced8SAlex Deucher 		radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder);
27873f03ced8SAlex Deucher 		drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs);
27883f03ced8SAlex Deucher 		break;
27893f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DAC2:
27903f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
27913f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
279213a3d91fSVille Syrjälä 		drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
279313a3d91fSVille Syrjälä 				 DRM_MODE_ENCODER_TVDAC, NULL);
27943f03ced8SAlex Deucher 		radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder);
27953f03ced8SAlex Deucher 		drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs);
27963f03ced8SAlex Deucher 		break;
27973f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DVO1:
27983f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
27993f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DDI:
28003f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
28013f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
28023f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
28033f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
2804e68adef8SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
28053f03ced8SAlex Deucher 		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
28063f03ced8SAlex Deucher 			radeon_encoder->rmx_type = RMX_FULL;
280713a3d91fSVille Syrjälä 			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
280813a3d91fSVille Syrjälä 					 DRM_MODE_ENCODER_LVDS, NULL);
28093f03ced8SAlex Deucher 			radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder);
28103f03ced8SAlex Deucher 		} else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) {
281113a3d91fSVille Syrjälä 			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
281213a3d91fSVille Syrjälä 					 DRM_MODE_ENCODER_DAC, NULL);
28133f03ced8SAlex Deucher 			radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
28143f03ced8SAlex Deucher 		} else {
281513a3d91fSVille Syrjälä 			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
281613a3d91fSVille Syrjälä 					 DRM_MODE_ENCODER_TMDS, NULL);
28173f03ced8SAlex Deucher 			radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
28183f03ced8SAlex Deucher 		}
28193f03ced8SAlex Deucher 		drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
28203f03ced8SAlex Deucher 		break;
28213f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_SI170B:
28223f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_CH7303:
28233f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_EXTERNAL_SDVOA:
28243f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_EXTERNAL_SDVOB:
28253f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_TITFP513:
28263f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_VT1623:
28273f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_HDMI_SI1930:
28283f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_TRAVIS:
28293f03ced8SAlex Deucher 	case ENCODER_OBJECT_ID_NUTMEG:
28303f03ced8SAlex Deucher 		/* these are handled by the primary encoders */
28313f03ced8SAlex Deucher 		radeon_encoder->is_ext_encoder = true;
28323f03ced8SAlex Deucher 		if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
283313a3d91fSVille Syrjälä 			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
283413a3d91fSVille Syrjälä 					 DRM_MODE_ENCODER_LVDS, NULL);
28353f03ced8SAlex Deucher 		else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
283613a3d91fSVille Syrjälä 			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
283713a3d91fSVille Syrjälä 					 DRM_MODE_ENCODER_DAC, NULL);
28383f03ced8SAlex Deucher 		else
283913a3d91fSVille Syrjälä 			drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs,
284013a3d91fSVille Syrjälä 					 DRM_MODE_ENCODER_TMDS, NULL);
28413f03ced8SAlex Deucher 		drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs);
28423f03ced8SAlex Deucher 		break;
28433f03ced8SAlex Deucher 	}
28443f03ced8SAlex Deucher }
2845