xref: /openbmc/linux/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c (revision 34d6f206a88c2651d216bd3487ac956a40b2ba8e)
1d38ceaf9SAlex Deucher /*
2d38ceaf9SAlex Deucher  * Copyright 2007-11 Advanced Micro Devices, Inc.
3d38ceaf9SAlex Deucher  * Copyright 2008 Red Hat Inc.
4d38ceaf9SAlex Deucher  *
5d38ceaf9SAlex Deucher  * Permission is hereby granted, free of charge, to any person obtaining a
6d38ceaf9SAlex Deucher  * copy of this software and associated documentation files (the "Software"),
7d38ceaf9SAlex Deucher  * to deal in the Software without restriction, including without limitation
8d38ceaf9SAlex Deucher  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9d38ceaf9SAlex Deucher  * and/or sell copies of the Software, and to permit persons to whom the
10d38ceaf9SAlex Deucher  * Software is furnished to do so, subject to the following conditions:
11d38ceaf9SAlex Deucher  *
12d38ceaf9SAlex Deucher  * The above copyright notice and this permission notice shall be included in
13d38ceaf9SAlex Deucher  * all copies or substantial portions of the Software.
14d38ceaf9SAlex Deucher  *
15d38ceaf9SAlex Deucher  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16d38ceaf9SAlex Deucher  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17d38ceaf9SAlex Deucher  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18d38ceaf9SAlex Deucher  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19d38ceaf9SAlex Deucher  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20d38ceaf9SAlex Deucher  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21d38ceaf9SAlex Deucher  * OTHER DEALINGS IN THE SOFTWARE.
22d38ceaf9SAlex Deucher  *
23d38ceaf9SAlex Deucher  * Authors: Dave Airlie
24d38ceaf9SAlex Deucher  *          Alex Deucher
25d38ceaf9SAlex Deucher  */
2647b757fbSSam Ravnborg 
2747b757fbSSam Ravnborg #include <linux/pci.h>
2847b757fbSSam Ravnborg 
29da11ef83SHans de Goede #include <acpi/video.h>
30da11ef83SHans de Goede 
31d38ceaf9SAlex Deucher #include <drm/amdgpu_drm.h>
32d38ceaf9SAlex Deucher #include "amdgpu.h"
33d38ceaf9SAlex Deucher #include "amdgpu_connectors.h"
345df58525SHuang Rui #include "amdgpu_display.h"
35d38ceaf9SAlex Deucher #include "atom.h"
36d38ceaf9SAlex Deucher #include "atombios_encoders.h"
37d38ceaf9SAlex Deucher #include "atombios_dp.h"
38d38ceaf9SAlex Deucher #include <linux/backlight.h>
39d38ceaf9SAlex Deucher #include "bif/bif_4_1_d.h"
40d38ceaf9SAlex Deucher 
41b5e32413SAlex Deucher u8
amdgpu_atombios_encoder_get_backlight_level_from_reg(struct amdgpu_device * adev)42d38ceaf9SAlex Deucher amdgpu_atombios_encoder_get_backlight_level_from_reg(struct amdgpu_device *adev)
43d38ceaf9SAlex Deucher {
44d38ceaf9SAlex Deucher 	u8 backlight_level;
45d38ceaf9SAlex Deucher 	u32 bios_2_scratch;
46d38ceaf9SAlex Deucher 
47d38ceaf9SAlex Deucher 	bios_2_scratch = RREG32(mmBIOS_SCRATCH_2);
48d38ceaf9SAlex Deucher 
49d38ceaf9SAlex Deucher 	backlight_level = ((bios_2_scratch & ATOM_S2_CURRENT_BL_LEVEL_MASK) >>
50d38ceaf9SAlex Deucher 			   ATOM_S2_CURRENT_BL_LEVEL_SHIFT);
51d38ceaf9SAlex Deucher 
52d38ceaf9SAlex Deucher 	return backlight_level;
53d38ceaf9SAlex Deucher }
54d38ceaf9SAlex Deucher 
55b5e32413SAlex Deucher void
amdgpu_atombios_encoder_set_backlight_level_to_reg(struct amdgpu_device * adev,u8 backlight_level)56d38ceaf9SAlex Deucher amdgpu_atombios_encoder_set_backlight_level_to_reg(struct amdgpu_device *adev,
57d38ceaf9SAlex Deucher 					    u8 backlight_level)
58d38ceaf9SAlex Deucher {
59d38ceaf9SAlex Deucher 	u32 bios_2_scratch;
60d38ceaf9SAlex Deucher 
61d38ceaf9SAlex Deucher 	bios_2_scratch = RREG32(mmBIOS_SCRATCH_2);
62d38ceaf9SAlex Deucher 
63d38ceaf9SAlex Deucher 	bios_2_scratch &= ~ATOM_S2_CURRENT_BL_LEVEL_MASK;
64d38ceaf9SAlex Deucher 	bios_2_scratch |= ((backlight_level << ATOM_S2_CURRENT_BL_LEVEL_SHIFT) &
65d38ceaf9SAlex Deucher 			   ATOM_S2_CURRENT_BL_LEVEL_MASK);
66d38ceaf9SAlex Deucher 
67d38ceaf9SAlex Deucher 	WREG32(mmBIOS_SCRATCH_2, bios_2_scratch);
68d38ceaf9SAlex Deucher }
69d38ceaf9SAlex Deucher 
70d38ceaf9SAlex Deucher u8
amdgpu_atombios_encoder_get_backlight_level(struct amdgpu_encoder * amdgpu_encoder)71d38ceaf9SAlex Deucher amdgpu_atombios_encoder_get_backlight_level(struct amdgpu_encoder *amdgpu_encoder)
72d38ceaf9SAlex Deucher {
73d38ceaf9SAlex Deucher 	struct drm_device *dev = amdgpu_encoder->base.dev;
741348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
75d38ceaf9SAlex Deucher 
76d38ceaf9SAlex Deucher 	if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
77d38ceaf9SAlex Deucher 		return 0;
78d38ceaf9SAlex Deucher 
79d38ceaf9SAlex Deucher 	return amdgpu_atombios_encoder_get_backlight_level_from_reg(adev);
80d38ceaf9SAlex Deucher }
81d38ceaf9SAlex Deucher 
82d38ceaf9SAlex Deucher void
amdgpu_atombios_encoder_set_backlight_level(struct amdgpu_encoder * amdgpu_encoder,u8 level)83d38ceaf9SAlex Deucher amdgpu_atombios_encoder_set_backlight_level(struct amdgpu_encoder *amdgpu_encoder,
84d38ceaf9SAlex Deucher 				     u8 level)
85d38ceaf9SAlex Deucher {
86d38ceaf9SAlex Deucher 	struct drm_encoder *encoder = &amdgpu_encoder->base;
87d38ceaf9SAlex Deucher 	struct drm_device *dev = amdgpu_encoder->base.dev;
881348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
89d38ceaf9SAlex Deucher 	struct amdgpu_encoder_atom_dig *dig;
90d38ceaf9SAlex Deucher 
91d38ceaf9SAlex Deucher 	if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
92d38ceaf9SAlex Deucher 		return;
93d38ceaf9SAlex Deucher 
94d38ceaf9SAlex Deucher 	if ((amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) &&
95d38ceaf9SAlex Deucher 	    amdgpu_encoder->enc_priv) {
96d38ceaf9SAlex Deucher 		dig = amdgpu_encoder->enc_priv;
97d38ceaf9SAlex Deucher 		dig->backlight_level = level;
98d38ceaf9SAlex Deucher 		amdgpu_atombios_encoder_set_backlight_level_to_reg(adev, dig->backlight_level);
99d38ceaf9SAlex Deucher 
100d38ceaf9SAlex Deucher 		switch (amdgpu_encoder->encoder_id) {
101d38ceaf9SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
102d38ceaf9SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
103d38ceaf9SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
104d38ceaf9SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
105dba6c4faSAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
106d38ceaf9SAlex Deucher 			if (dig->backlight_level == 0)
107d38ceaf9SAlex Deucher 				amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
108d38ceaf9SAlex Deucher 								       ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
109d38ceaf9SAlex Deucher 			else {
110d38ceaf9SAlex Deucher 				amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
111d38ceaf9SAlex Deucher 								       ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL, 0, 0);
112d38ceaf9SAlex Deucher 				amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
113d38ceaf9SAlex Deucher 								       ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
114d38ceaf9SAlex Deucher 			}
115d38ceaf9SAlex Deucher 			break;
116d38ceaf9SAlex Deucher 		default:
117d38ceaf9SAlex Deucher 			break;
118d38ceaf9SAlex Deucher 		}
119d38ceaf9SAlex Deucher 	}
120d38ceaf9SAlex Deucher }
121d38ceaf9SAlex Deucher 
amdgpu_atombios_encoder_backlight_level(struct backlight_device * bd)122d38ceaf9SAlex Deucher static u8 amdgpu_atombios_encoder_backlight_level(struct backlight_device *bd)
123d38ceaf9SAlex Deucher {
124d38ceaf9SAlex Deucher 	u8 level;
125d38ceaf9SAlex Deucher 
126d38ceaf9SAlex Deucher 	/* Convert brightness to hardware level */
127d38ceaf9SAlex Deucher 	if (bd->props.brightness < 0)
128d38ceaf9SAlex Deucher 		level = 0;
129d38ceaf9SAlex Deucher 	else if (bd->props.brightness > AMDGPU_MAX_BL_LEVEL)
130d38ceaf9SAlex Deucher 		level = AMDGPU_MAX_BL_LEVEL;
131d38ceaf9SAlex Deucher 	else
132d38ceaf9SAlex Deucher 		level = bd->props.brightness;
133d38ceaf9SAlex Deucher 
134d38ceaf9SAlex Deucher 	return level;
135d38ceaf9SAlex Deucher }
136d38ceaf9SAlex Deucher 
amdgpu_atombios_encoder_update_backlight_status(struct backlight_device * bd)137d38ceaf9SAlex Deucher static int amdgpu_atombios_encoder_update_backlight_status(struct backlight_device *bd)
138d38ceaf9SAlex Deucher {
139d38ceaf9SAlex Deucher 	struct amdgpu_backlight_privdata *pdata = bl_get_data(bd);
140d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = pdata->encoder;
141d38ceaf9SAlex Deucher 
142d38ceaf9SAlex Deucher 	amdgpu_atombios_encoder_set_backlight_level(amdgpu_encoder,
143d38ceaf9SAlex Deucher 					     amdgpu_atombios_encoder_backlight_level(bd));
144d38ceaf9SAlex Deucher 
145d38ceaf9SAlex Deucher 	return 0;
146d38ceaf9SAlex Deucher }
147d38ceaf9SAlex Deucher 
148d38ceaf9SAlex Deucher static int
amdgpu_atombios_encoder_get_backlight_brightness(struct backlight_device * bd)149d38ceaf9SAlex Deucher amdgpu_atombios_encoder_get_backlight_brightness(struct backlight_device *bd)
150d38ceaf9SAlex Deucher {
151d38ceaf9SAlex Deucher 	struct amdgpu_backlight_privdata *pdata = bl_get_data(bd);
152d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = pdata->encoder;
153d38ceaf9SAlex Deucher 	struct drm_device *dev = amdgpu_encoder->base.dev;
1541348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
155d38ceaf9SAlex Deucher 
156d38ceaf9SAlex Deucher 	return amdgpu_atombios_encoder_get_backlight_level_from_reg(adev);
157d38ceaf9SAlex Deucher }
158d38ceaf9SAlex Deucher 
159d38ceaf9SAlex Deucher static const struct backlight_ops amdgpu_atombios_encoder_backlight_ops = {
160d38ceaf9SAlex Deucher 	.get_brightness = amdgpu_atombios_encoder_get_backlight_brightness,
161d38ceaf9SAlex Deucher 	.update_status	= amdgpu_atombios_encoder_update_backlight_status,
162d38ceaf9SAlex Deucher };
163d38ceaf9SAlex Deucher 
amdgpu_atombios_encoder_init_backlight(struct amdgpu_encoder * amdgpu_encoder,struct drm_connector * drm_connector)164d38ceaf9SAlex Deucher void amdgpu_atombios_encoder_init_backlight(struct amdgpu_encoder *amdgpu_encoder,
165d38ceaf9SAlex Deucher 				     struct drm_connector *drm_connector)
166d38ceaf9SAlex Deucher {
167d38ceaf9SAlex Deucher 	struct drm_device *dev = amdgpu_encoder->base.dev;
1681348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
169d38ceaf9SAlex Deucher 	struct backlight_device *bd;
170d38ceaf9SAlex Deucher 	struct backlight_properties props;
171d38ceaf9SAlex Deucher 	struct amdgpu_backlight_privdata *pdata;
172d38ceaf9SAlex Deucher 	struct amdgpu_encoder_atom_dig *dig;
173d38ceaf9SAlex Deucher 	char bl_name[16];
174d38ceaf9SAlex Deucher 
175d38ceaf9SAlex Deucher 	/* Mac laptops with multiple GPUs use the gmux driver for backlight
176d38ceaf9SAlex Deucher 	 * so don't register a backlight device
177d38ceaf9SAlex Deucher 	 */
178d38ceaf9SAlex Deucher 	if ((adev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
179d38ceaf9SAlex Deucher 	    (adev->pdev->device == 0x6741))
180d38ceaf9SAlex Deucher 		return;
181d38ceaf9SAlex Deucher 
182d38ceaf9SAlex Deucher 	if (!amdgpu_encoder->enc_priv)
183d38ceaf9SAlex Deucher 		return;
184d38ceaf9SAlex Deucher 
185d38ceaf9SAlex Deucher 	if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
186c0f50c5dSHans de Goede 		goto register_acpi_backlight;
187d38ceaf9SAlex Deucher 
188da11ef83SHans de Goede 	if (!acpi_video_backlight_use_native()) {
189da11ef83SHans de Goede 		drm_info(dev, "Skipping amdgpu atom DIG backlight registration\n");
190c0f50c5dSHans de Goede 		goto register_acpi_backlight;
191da11ef83SHans de Goede 	}
192da11ef83SHans de Goede 
193d38ceaf9SAlex Deucher 	pdata = kmalloc(sizeof(struct amdgpu_backlight_privdata), GFP_KERNEL);
194d38ceaf9SAlex Deucher 	if (!pdata) {
195d38ceaf9SAlex Deucher 		DRM_ERROR("Memory allocation failed\n");
196d38ceaf9SAlex Deucher 		goto error;
197d38ceaf9SAlex Deucher 	}
198d38ceaf9SAlex Deucher 
199d38ceaf9SAlex Deucher 	memset(&props, 0, sizeof(props));
200d38ceaf9SAlex Deucher 	props.max_brightness = AMDGPU_MAX_BL_LEVEL;
201d38ceaf9SAlex Deucher 	props.type = BACKLIGHT_RAW;
202d38ceaf9SAlex Deucher 	snprintf(bl_name, sizeof(bl_name),
203d38ceaf9SAlex Deucher 		 "amdgpu_bl%d", dev->primary->index);
204d38ceaf9SAlex Deucher 	bd = backlight_device_register(bl_name, drm_connector->kdev,
205d38ceaf9SAlex Deucher 				       pdata, &amdgpu_atombios_encoder_backlight_ops, &props);
206d38ceaf9SAlex Deucher 	if (IS_ERR(bd)) {
207d38ceaf9SAlex Deucher 		DRM_ERROR("Backlight registration failed\n");
208d38ceaf9SAlex Deucher 		goto error;
209d38ceaf9SAlex Deucher 	}
210d38ceaf9SAlex Deucher 
211d38ceaf9SAlex Deucher 	pdata->encoder = amdgpu_encoder;
212d38ceaf9SAlex Deucher 
213d38ceaf9SAlex Deucher 	dig = amdgpu_encoder->enc_priv;
214d38ceaf9SAlex Deucher 	dig->bl_dev = bd;
215d38ceaf9SAlex Deucher 
216d38ceaf9SAlex Deucher 	bd->props.brightness = amdgpu_atombios_encoder_get_backlight_brightness(bd);
217d38ceaf9SAlex Deucher 	bd->props.power = FB_BLANK_UNBLANK;
218d38ceaf9SAlex Deucher 	backlight_update_status(bd);
219d38ceaf9SAlex Deucher 
220d38ceaf9SAlex Deucher 	DRM_INFO("amdgpu atom DIG backlight initialized\n");
221d38ceaf9SAlex Deucher 
222d38ceaf9SAlex Deucher 	return;
223d38ceaf9SAlex Deucher 
224d38ceaf9SAlex Deucher error:
225d38ceaf9SAlex Deucher 	kfree(pdata);
226d38ceaf9SAlex Deucher 	return;
227c0f50c5dSHans de Goede 
228c0f50c5dSHans de Goede register_acpi_backlight:
229c0f50c5dSHans de Goede 	/* Try registering an ACPI video backlight device instead. */
230c0f50c5dSHans de Goede 	acpi_video_register_backlight();
231c0f50c5dSHans de Goede 	return;
232d38ceaf9SAlex Deucher }
233d38ceaf9SAlex Deucher 
234d38ceaf9SAlex Deucher void
amdgpu_atombios_encoder_fini_backlight(struct amdgpu_encoder * amdgpu_encoder)235d38ceaf9SAlex Deucher amdgpu_atombios_encoder_fini_backlight(struct amdgpu_encoder *amdgpu_encoder)
236d38ceaf9SAlex Deucher {
237d38ceaf9SAlex Deucher 	struct drm_device *dev = amdgpu_encoder->base.dev;
2381348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
239d38ceaf9SAlex Deucher 	struct backlight_device *bd = NULL;
240d38ceaf9SAlex Deucher 	struct amdgpu_encoder_atom_dig *dig;
241d38ceaf9SAlex Deucher 
242d38ceaf9SAlex Deucher 	if (!amdgpu_encoder->enc_priv)
243d38ceaf9SAlex Deucher 		return;
244d38ceaf9SAlex Deucher 
245d38ceaf9SAlex Deucher 	if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
246d38ceaf9SAlex Deucher 		return;
247d38ceaf9SAlex Deucher 
248d38ceaf9SAlex Deucher 	dig = amdgpu_encoder->enc_priv;
249d38ceaf9SAlex Deucher 	bd = dig->bl_dev;
250d38ceaf9SAlex Deucher 	dig->bl_dev = NULL;
251d38ceaf9SAlex Deucher 
252d38ceaf9SAlex Deucher 	if (bd) {
253d38ceaf9SAlex Deucher 		struct amdgpu_legacy_backlight_privdata *pdata;
254d38ceaf9SAlex Deucher 
255d38ceaf9SAlex Deucher 		pdata = bl_get_data(bd);
256d38ceaf9SAlex Deucher 		backlight_device_unregister(bd);
257d38ceaf9SAlex Deucher 		kfree(pdata);
258d38ceaf9SAlex Deucher 
259d38ceaf9SAlex Deucher 		DRM_INFO("amdgpu atom LVDS backlight unloaded\n");
260d38ceaf9SAlex Deucher 	}
261d38ceaf9SAlex Deucher }
262d38ceaf9SAlex Deucher 
amdgpu_atombios_encoder_is_digital(struct drm_encoder * encoder)263d38ceaf9SAlex Deucher bool amdgpu_atombios_encoder_is_digital(struct drm_encoder *encoder)
264d38ceaf9SAlex Deucher {
265d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
266d38ceaf9SAlex Deucher 	switch (amdgpu_encoder->encoder_id) {
267d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
268d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
269d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
270d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
271d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
272d38ceaf9SAlex Deucher 		return true;
273d38ceaf9SAlex Deucher 	default:
274d38ceaf9SAlex Deucher 		return false;
275d38ceaf9SAlex Deucher 	}
276d38ceaf9SAlex Deucher }
277d38ceaf9SAlex Deucher 
amdgpu_atombios_encoder_mode_fixup(struct drm_encoder * encoder,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)278d38ceaf9SAlex Deucher bool amdgpu_atombios_encoder_mode_fixup(struct drm_encoder *encoder,
279d38ceaf9SAlex Deucher 				 const struct drm_display_mode *mode,
280d38ceaf9SAlex Deucher 				 struct drm_display_mode *adjusted_mode)
281d38ceaf9SAlex Deucher {
282d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
283d38ceaf9SAlex Deucher 
284d38ceaf9SAlex Deucher 	/* set the active encoder to connector routing */
285d38ceaf9SAlex Deucher 	amdgpu_encoder_set_active_device(encoder);
286d38ceaf9SAlex Deucher 	drm_mode_set_crtcinfo(adjusted_mode, 0);
287d38ceaf9SAlex Deucher 
288d38ceaf9SAlex Deucher 	/* hw bug */
289d38ceaf9SAlex Deucher 	if ((mode->flags & DRM_MODE_FLAG_INTERLACE)
290d38ceaf9SAlex Deucher 	    && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2)))
291d38ceaf9SAlex Deucher 		adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2;
292d38ceaf9SAlex Deucher 
2930126d4b9SAlex Deucher 	/* vertical FP must be at least 1 */
2940126d4b9SAlex Deucher 	if (mode->crtc_vsync_start == mode->crtc_vdisplay)
2950126d4b9SAlex Deucher 		adjusted_mode->crtc_vsync_start++;
2960126d4b9SAlex Deucher 
297d38ceaf9SAlex Deucher 	/* get the native mode for scaling */
298d38ceaf9SAlex Deucher 	if (amdgpu_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT))
299d38ceaf9SAlex Deucher 		amdgpu_panel_mode_fixup(encoder, adjusted_mode);
300d38ceaf9SAlex Deucher 	else if (amdgpu_encoder->rmx_type != RMX_OFF)
301d38ceaf9SAlex Deucher 		amdgpu_panel_mode_fixup(encoder, adjusted_mode);
302d38ceaf9SAlex Deucher 
303d38ceaf9SAlex Deucher 	if ((amdgpu_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) ||
304d38ceaf9SAlex Deucher 	    (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) {
305d38ceaf9SAlex Deucher 		struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
306d38ceaf9SAlex Deucher 		amdgpu_atombios_dp_set_link_config(connector, adjusted_mode);
307d38ceaf9SAlex Deucher 	}
308d38ceaf9SAlex Deucher 
309d38ceaf9SAlex Deucher 	return true;
310d38ceaf9SAlex Deucher }
311d38ceaf9SAlex Deucher 
312d38ceaf9SAlex Deucher static void
amdgpu_atombios_encoder_setup_dac(struct drm_encoder * encoder,int action)313d38ceaf9SAlex Deucher amdgpu_atombios_encoder_setup_dac(struct drm_encoder *encoder, int action)
314d38ceaf9SAlex Deucher {
315d38ceaf9SAlex Deucher 	struct drm_device *dev = encoder->dev;
3161348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
317d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
318d38ceaf9SAlex Deucher 	DAC_ENCODER_CONTROL_PS_ALLOCATION args;
319d38ceaf9SAlex Deucher 	int index = 0;
320d38ceaf9SAlex Deucher 
321d38ceaf9SAlex Deucher 	memset(&args, 0, sizeof(args));
322d38ceaf9SAlex Deucher 
323d38ceaf9SAlex Deucher 	switch (amdgpu_encoder->encoder_id) {
324d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DAC1:
325d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
326d38ceaf9SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl);
327d38ceaf9SAlex Deucher 		break;
328d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_DAC2:
329d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
330d38ceaf9SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl);
331d38ceaf9SAlex Deucher 		break;
332d38ceaf9SAlex Deucher 	}
333d38ceaf9SAlex Deucher 
334d38ceaf9SAlex Deucher 	args.ucAction = action;
335d38ceaf9SAlex Deucher 	args.ucDacStandard = ATOM_DAC1_PS2;
336d38ceaf9SAlex Deucher 	args.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
337d38ceaf9SAlex Deucher 
338d38ceaf9SAlex Deucher 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
339d38ceaf9SAlex Deucher 
340d38ceaf9SAlex Deucher }
341d38ceaf9SAlex Deucher 
amdgpu_atombios_encoder_get_bpc(struct drm_encoder * encoder)342d38ceaf9SAlex Deucher static u8 amdgpu_atombios_encoder_get_bpc(struct drm_encoder *encoder)
343d38ceaf9SAlex Deucher {
344d38ceaf9SAlex Deucher 	int bpc = 8;
345d38ceaf9SAlex Deucher 
346d38ceaf9SAlex Deucher 	if (encoder->crtc) {
347d38ceaf9SAlex Deucher 		struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
348d38ceaf9SAlex Deucher 		bpc = amdgpu_crtc->bpc;
349d38ceaf9SAlex Deucher 	}
350d38ceaf9SAlex Deucher 
351d38ceaf9SAlex Deucher 	switch (bpc) {
352d38ceaf9SAlex Deucher 	case 0:
353d38ceaf9SAlex Deucher 		return PANEL_BPC_UNDEFINE;
354d38ceaf9SAlex Deucher 	case 6:
355d38ceaf9SAlex Deucher 		return PANEL_6BIT_PER_COLOR;
356d38ceaf9SAlex Deucher 	case 8:
357d38ceaf9SAlex Deucher 	default:
358d38ceaf9SAlex Deucher 		return PANEL_8BIT_PER_COLOR;
359d38ceaf9SAlex Deucher 	case 10:
360d38ceaf9SAlex Deucher 		return PANEL_10BIT_PER_COLOR;
361d38ceaf9SAlex Deucher 	case 12:
362d38ceaf9SAlex Deucher 		return PANEL_12BIT_PER_COLOR;
363d38ceaf9SAlex Deucher 	case 16:
364d38ceaf9SAlex Deucher 		return PANEL_16BIT_PER_COLOR;
365d38ceaf9SAlex Deucher 	}
366d38ceaf9SAlex Deucher }
367d38ceaf9SAlex Deucher 
368d38ceaf9SAlex Deucher union dvo_encoder_control {
369d38ceaf9SAlex Deucher 	ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds;
370d38ceaf9SAlex Deucher 	DVO_ENCODER_CONTROL_PS_ALLOCATION dvo;
371d38ceaf9SAlex Deucher 	DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3;
372d38ceaf9SAlex Deucher 	DVO_ENCODER_CONTROL_PS_ALLOCATION_V1_4 dvo_v4;
373d38ceaf9SAlex Deucher };
374d38ceaf9SAlex Deucher 
375d38ceaf9SAlex Deucher static void
amdgpu_atombios_encoder_setup_dvo(struct drm_encoder * encoder,int action)376d38ceaf9SAlex Deucher amdgpu_atombios_encoder_setup_dvo(struct drm_encoder *encoder, int action)
377d38ceaf9SAlex Deucher {
378d38ceaf9SAlex Deucher 	struct drm_device *dev = encoder->dev;
3791348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
380d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
381d38ceaf9SAlex Deucher 	union dvo_encoder_control args;
382d38ceaf9SAlex Deucher 	int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
383d38ceaf9SAlex Deucher 	uint8_t frev, crev;
384d38ceaf9SAlex Deucher 
385d38ceaf9SAlex Deucher 	memset(&args, 0, sizeof(args));
386d38ceaf9SAlex Deucher 
387d38ceaf9SAlex Deucher 	if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
388d38ceaf9SAlex Deucher 		return;
389d38ceaf9SAlex Deucher 
390d38ceaf9SAlex Deucher 	switch (frev) {
391d38ceaf9SAlex Deucher 	case 1:
392d38ceaf9SAlex Deucher 		switch (crev) {
393d38ceaf9SAlex Deucher 		case 1:
394d38ceaf9SAlex Deucher 			/* R4xx, R5xx */
395d38ceaf9SAlex Deucher 			args.ext_tmds.sXTmdsEncoder.ucEnable = action;
396d38ceaf9SAlex Deucher 
397d38ceaf9SAlex Deucher 			if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
398d38ceaf9SAlex Deucher 				args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL;
399d38ceaf9SAlex Deucher 
400d38ceaf9SAlex Deucher 			args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB;
401d38ceaf9SAlex Deucher 			break;
402d38ceaf9SAlex Deucher 		case 2:
403d38ceaf9SAlex Deucher 			/* RS600/690/740 */
404d38ceaf9SAlex Deucher 			args.dvo.sDVOEncoder.ucAction = action;
405d38ceaf9SAlex Deucher 			args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
406d38ceaf9SAlex Deucher 			/* DFP1, CRT1, TV1 depending on the type of port */
407d38ceaf9SAlex Deucher 			args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX;
408d38ceaf9SAlex Deucher 
409d38ceaf9SAlex Deucher 			if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
410d38ceaf9SAlex Deucher 				args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL;
411d38ceaf9SAlex Deucher 			break;
412d38ceaf9SAlex Deucher 		case 3:
413d38ceaf9SAlex Deucher 			/* R6xx */
414d38ceaf9SAlex Deucher 			args.dvo_v3.ucAction = action;
415d38ceaf9SAlex Deucher 			args.dvo_v3.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
416d38ceaf9SAlex Deucher 			args.dvo_v3.ucDVOConfig = 0; /* XXX */
417d38ceaf9SAlex Deucher 			break;
418d38ceaf9SAlex Deucher 		case 4:
419d38ceaf9SAlex Deucher 			/* DCE8 */
420d38ceaf9SAlex Deucher 			args.dvo_v4.ucAction = action;
421d38ceaf9SAlex Deucher 			args.dvo_v4.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
422d38ceaf9SAlex Deucher 			args.dvo_v4.ucDVOConfig = 0; /* XXX */
423d38ceaf9SAlex Deucher 			args.dvo_v4.ucBitPerColor = amdgpu_atombios_encoder_get_bpc(encoder);
424d38ceaf9SAlex Deucher 			break;
425d38ceaf9SAlex Deucher 		default:
426d38ceaf9SAlex Deucher 			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
427d38ceaf9SAlex Deucher 			break;
428d38ceaf9SAlex Deucher 		}
429d38ceaf9SAlex Deucher 		break;
430d38ceaf9SAlex Deucher 	default:
431d38ceaf9SAlex Deucher 		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
432d38ceaf9SAlex Deucher 		break;
433d38ceaf9SAlex Deucher 	}
434d38ceaf9SAlex Deucher 
435d38ceaf9SAlex Deucher 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
436d38ceaf9SAlex Deucher }
437d38ceaf9SAlex Deucher 
amdgpu_atombios_encoder_get_encoder_mode(struct drm_encoder * encoder)438d38ceaf9SAlex Deucher int amdgpu_atombios_encoder_get_encoder_mode(struct drm_encoder *encoder)
439d38ceaf9SAlex Deucher {
440d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
441d38ceaf9SAlex Deucher 	struct drm_connector *connector;
442d38ceaf9SAlex Deucher 	struct amdgpu_connector *amdgpu_connector;
443d38ceaf9SAlex Deucher 	struct amdgpu_connector_atom_dig *dig_connector;
444d38ceaf9SAlex Deucher 
445d38ceaf9SAlex Deucher 	/* dp bridges are always DP */
446d38ceaf9SAlex Deucher 	if (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)
447d38ceaf9SAlex Deucher 		return ATOM_ENCODER_MODE_DP;
448d38ceaf9SAlex Deucher 
449d38ceaf9SAlex Deucher 	/* DVO is always DVO */
450d38ceaf9SAlex Deucher 	if ((amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DVO1) ||
451d38ceaf9SAlex Deucher 	    (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1))
452d38ceaf9SAlex Deucher 		return ATOM_ENCODER_MODE_DVO;
453d38ceaf9SAlex Deucher 
454d38ceaf9SAlex Deucher 	connector = amdgpu_get_connector_for_encoder(encoder);
455d38ceaf9SAlex Deucher 	/* if we don't have an active device yet, just use one of
456d38ceaf9SAlex Deucher 	 * the connectors tied to the encoder.
457d38ceaf9SAlex Deucher 	 */
458d38ceaf9SAlex Deucher 	if (!connector)
459d38ceaf9SAlex Deucher 		connector = amdgpu_get_connector_for_encoder_init(encoder);
460d38ceaf9SAlex Deucher 	amdgpu_connector = to_amdgpu_connector(connector);
461d38ceaf9SAlex Deucher 
462d38ceaf9SAlex Deucher 	switch (connector->connector_type) {
463d38ceaf9SAlex Deucher 	case DRM_MODE_CONNECTOR_DVII:
464d38ceaf9SAlex Deucher 	case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */
465d38ceaf9SAlex Deucher 		if (amdgpu_audio != 0) {
466d38ceaf9SAlex Deucher 			if (amdgpu_connector->use_digital &&
467d38ceaf9SAlex Deucher 			    (amdgpu_connector->audio == AMDGPU_AUDIO_ENABLE))
468d38ceaf9SAlex Deucher 				return ATOM_ENCODER_MODE_HDMI;
4693c021931SClaudio Suarez 			else if (connector->display_info.is_hdmi &&
470d38ceaf9SAlex Deucher 				 (amdgpu_connector->audio == AMDGPU_AUDIO_AUTO))
471d38ceaf9SAlex Deucher 				return ATOM_ENCODER_MODE_HDMI;
472d38ceaf9SAlex Deucher 			else if (amdgpu_connector->use_digital)
473d38ceaf9SAlex Deucher 				return ATOM_ENCODER_MODE_DVI;
474d38ceaf9SAlex Deucher 			else
475d38ceaf9SAlex Deucher 				return ATOM_ENCODER_MODE_CRT;
476d38ceaf9SAlex Deucher 		} else if (amdgpu_connector->use_digital) {
477d38ceaf9SAlex Deucher 			return ATOM_ENCODER_MODE_DVI;
478d38ceaf9SAlex Deucher 		} else {
479d38ceaf9SAlex Deucher 			return ATOM_ENCODER_MODE_CRT;
480d38ceaf9SAlex Deucher 		}
481d38ceaf9SAlex Deucher 		break;
482d38ceaf9SAlex Deucher 	case DRM_MODE_CONNECTOR_DVID:
483d38ceaf9SAlex Deucher 	case DRM_MODE_CONNECTOR_HDMIA:
484d38ceaf9SAlex Deucher 	default:
485d38ceaf9SAlex Deucher 		if (amdgpu_audio != 0) {
486d38ceaf9SAlex Deucher 			if (amdgpu_connector->audio == AMDGPU_AUDIO_ENABLE)
487d38ceaf9SAlex Deucher 				return ATOM_ENCODER_MODE_HDMI;
4883c021931SClaudio Suarez 			else if (connector->display_info.is_hdmi &&
489d38ceaf9SAlex Deucher 				 (amdgpu_connector->audio == AMDGPU_AUDIO_AUTO))
490d38ceaf9SAlex Deucher 				return ATOM_ENCODER_MODE_HDMI;
491d38ceaf9SAlex Deucher 			else
492d38ceaf9SAlex Deucher 				return ATOM_ENCODER_MODE_DVI;
493d38ceaf9SAlex Deucher 		} else {
494d38ceaf9SAlex Deucher 			return ATOM_ENCODER_MODE_DVI;
495d38ceaf9SAlex Deucher 		}
496d38ceaf9SAlex Deucher 	case DRM_MODE_CONNECTOR_LVDS:
497d38ceaf9SAlex Deucher 		return ATOM_ENCODER_MODE_LVDS;
498d38ceaf9SAlex Deucher 	case DRM_MODE_CONNECTOR_DisplayPort:
499d38ceaf9SAlex Deucher 		dig_connector = amdgpu_connector->con_priv;
500d38ceaf9SAlex Deucher 		if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
501d38ceaf9SAlex Deucher 		    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
502d38ceaf9SAlex Deucher 			return ATOM_ENCODER_MODE_DP;
503d38ceaf9SAlex Deucher 		} else if (amdgpu_audio != 0) {
504d38ceaf9SAlex Deucher 			if (amdgpu_connector->audio == AMDGPU_AUDIO_ENABLE)
505d38ceaf9SAlex Deucher 				return ATOM_ENCODER_MODE_HDMI;
5063c021931SClaudio Suarez 			else if (connector->display_info.is_hdmi &&
507d38ceaf9SAlex Deucher 				 (amdgpu_connector->audio == AMDGPU_AUDIO_AUTO))
508d38ceaf9SAlex Deucher 				return ATOM_ENCODER_MODE_HDMI;
509d38ceaf9SAlex Deucher 			else
510d38ceaf9SAlex Deucher 				return ATOM_ENCODER_MODE_DVI;
511d38ceaf9SAlex Deucher 		} else {
512d38ceaf9SAlex Deucher 			return ATOM_ENCODER_MODE_DVI;
513d38ceaf9SAlex Deucher 		}
514d38ceaf9SAlex Deucher 	case DRM_MODE_CONNECTOR_eDP:
515d38ceaf9SAlex Deucher 		return ATOM_ENCODER_MODE_DP;
516d38ceaf9SAlex Deucher 	case DRM_MODE_CONNECTOR_DVIA:
517d38ceaf9SAlex Deucher 	case DRM_MODE_CONNECTOR_VGA:
518d38ceaf9SAlex Deucher 		return ATOM_ENCODER_MODE_CRT;
519d38ceaf9SAlex Deucher 	case DRM_MODE_CONNECTOR_Composite:
520d38ceaf9SAlex Deucher 	case DRM_MODE_CONNECTOR_SVIDEO:
521d38ceaf9SAlex Deucher 	case DRM_MODE_CONNECTOR_9PinDIN:
522d38ceaf9SAlex Deucher 		/* fix me */
523d38ceaf9SAlex Deucher 		return ATOM_ENCODER_MODE_TV;
524d38ceaf9SAlex Deucher 	}
525d38ceaf9SAlex Deucher }
526d38ceaf9SAlex Deucher 
527d38ceaf9SAlex Deucher /*
528d38ceaf9SAlex Deucher  * DIG Encoder/Transmitter Setup
529d38ceaf9SAlex Deucher  *
530d38ceaf9SAlex Deucher  * DCE 6.0
531d38ceaf9SAlex Deucher  * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B).
532d38ceaf9SAlex Deucher  * Supports up to 6 digital outputs
533d38ceaf9SAlex Deucher  * - 6 DIG encoder blocks.
534d38ceaf9SAlex Deucher  * - DIG to PHY mapping is hardcoded
535d38ceaf9SAlex Deucher  * DIG1 drives UNIPHY0 link A, A+B
536d38ceaf9SAlex Deucher  * DIG2 drives UNIPHY0 link B
537d38ceaf9SAlex Deucher  * DIG3 drives UNIPHY1 link A, A+B
538d38ceaf9SAlex Deucher  * DIG4 drives UNIPHY1 link B
539d38ceaf9SAlex Deucher  * DIG5 drives UNIPHY2 link A, A+B
540d38ceaf9SAlex Deucher  * DIG6 drives UNIPHY2 link B
541d38ceaf9SAlex Deucher  *
542d38ceaf9SAlex Deucher  * Routing
543d38ceaf9SAlex Deucher  * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links)
544d38ceaf9SAlex Deucher  * Examples:
545d38ceaf9SAlex Deucher  * crtc0 -> dig2 -> LVTMA   links A+B -> TMDS/HDMI
546d38ceaf9SAlex Deucher  * crtc1 -> dig1 -> UNIPHY0 link  B   -> DP
547d38ceaf9SAlex Deucher  * crtc0 -> dig1 -> UNIPHY2 link  A   -> LVDS
548d38ceaf9SAlex Deucher  * crtc1 -> dig2 -> UNIPHY1 link  B+A -> TMDS/HDMI
549d38ceaf9SAlex Deucher  */
550d38ceaf9SAlex Deucher 
551d38ceaf9SAlex Deucher union dig_encoder_control {
552d38ceaf9SAlex Deucher 	DIG_ENCODER_CONTROL_PS_ALLOCATION v1;
553d38ceaf9SAlex Deucher 	DIG_ENCODER_CONTROL_PARAMETERS_V2 v2;
554d38ceaf9SAlex Deucher 	DIG_ENCODER_CONTROL_PARAMETERS_V3 v3;
555d38ceaf9SAlex Deucher 	DIG_ENCODER_CONTROL_PARAMETERS_V4 v4;
5564b5844e8SAlex Deucher 	DIG_ENCODER_CONTROL_PARAMETERS_V5 v5;
557d38ceaf9SAlex Deucher };
558d38ceaf9SAlex Deucher 
559d38ceaf9SAlex Deucher void
amdgpu_atombios_encoder_setup_dig_encoder(struct drm_encoder * encoder,int action,int panel_mode)560d38ceaf9SAlex Deucher amdgpu_atombios_encoder_setup_dig_encoder(struct drm_encoder *encoder,
561d38ceaf9SAlex Deucher 				   int action, int panel_mode)
562d38ceaf9SAlex Deucher {
563d38ceaf9SAlex Deucher 	struct drm_device *dev = encoder->dev;
5641348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
565d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
566d38ceaf9SAlex Deucher 	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
567d38ceaf9SAlex Deucher 	struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
568d38ceaf9SAlex Deucher 	union dig_encoder_control args;
569d38ceaf9SAlex Deucher 	int index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl);
570d38ceaf9SAlex Deucher 	uint8_t frev, crev;
571d38ceaf9SAlex Deucher 	int dp_clock = 0;
572d38ceaf9SAlex Deucher 	int dp_lane_count = 0;
573d38ceaf9SAlex Deucher 	int hpd_id = AMDGPU_HPD_NONE;
574d38ceaf9SAlex Deucher 
575d38ceaf9SAlex Deucher 	if (connector) {
576d38ceaf9SAlex Deucher 		struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
577d38ceaf9SAlex Deucher 		struct amdgpu_connector_atom_dig *dig_connector =
578d38ceaf9SAlex Deucher 			amdgpu_connector->con_priv;
579d38ceaf9SAlex Deucher 
580d38ceaf9SAlex Deucher 		dp_clock = dig_connector->dp_clock;
581d38ceaf9SAlex Deucher 		dp_lane_count = dig_connector->dp_lane_count;
582d38ceaf9SAlex Deucher 		hpd_id = amdgpu_connector->hpd.hpd;
583d38ceaf9SAlex Deucher 	}
584d38ceaf9SAlex Deucher 
585d38ceaf9SAlex Deucher 	/* no dig encoder assigned */
586d38ceaf9SAlex Deucher 	if (dig->dig_encoder == -1)
587d38ceaf9SAlex Deucher 		return;
588d38ceaf9SAlex Deucher 
589d38ceaf9SAlex Deucher 	memset(&args, 0, sizeof(args));
590d38ceaf9SAlex Deucher 
591d38ceaf9SAlex Deucher 	if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
592d38ceaf9SAlex Deucher 		return;
593d38ceaf9SAlex Deucher 
594d38ceaf9SAlex Deucher 	switch (frev) {
595d38ceaf9SAlex Deucher 	case 1:
596d38ceaf9SAlex Deucher 		switch (crev) {
597d38ceaf9SAlex Deucher 		case 1:
598d38ceaf9SAlex Deucher 			args.v1.ucAction = action;
599d38ceaf9SAlex Deucher 			args.v1.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
600d38ceaf9SAlex Deucher 			if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
601d38ceaf9SAlex Deucher 				args.v3.ucPanelMode = panel_mode;
602d38ceaf9SAlex Deucher 			else
603d38ceaf9SAlex Deucher 				args.v1.ucEncoderMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
604d38ceaf9SAlex Deucher 
605d38ceaf9SAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode))
606d38ceaf9SAlex Deucher 				args.v1.ucLaneNum = dp_lane_count;
607d38ceaf9SAlex Deucher 			else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
608d38ceaf9SAlex Deucher 				args.v1.ucLaneNum = 8;
609d38ceaf9SAlex Deucher 			else
610d38ceaf9SAlex Deucher 				args.v1.ucLaneNum = 4;
611d38ceaf9SAlex Deucher 
612d38ceaf9SAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000))
613d38ceaf9SAlex Deucher 				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
614d38ceaf9SAlex Deucher 			switch (amdgpu_encoder->encoder_id) {
615d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
616d38ceaf9SAlex Deucher 				args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
617d38ceaf9SAlex Deucher 				break;
618d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
619d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
620d38ceaf9SAlex Deucher 				args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2;
621d38ceaf9SAlex Deucher 				break;
622d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
623d38ceaf9SAlex Deucher 				args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3;
624d38ceaf9SAlex Deucher 				break;
625d38ceaf9SAlex Deucher 			}
626d38ceaf9SAlex Deucher 			if (dig->linkb)
627d38ceaf9SAlex Deucher 				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
628d38ceaf9SAlex Deucher 			else
629d38ceaf9SAlex Deucher 				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
630d38ceaf9SAlex Deucher 			break;
631d38ceaf9SAlex Deucher 		case 2:
632d38ceaf9SAlex Deucher 		case 3:
633d38ceaf9SAlex Deucher 			args.v3.ucAction = action;
634d38ceaf9SAlex Deucher 			args.v3.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
635d38ceaf9SAlex Deucher 			if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
636d38ceaf9SAlex Deucher 				args.v3.ucPanelMode = panel_mode;
637d38ceaf9SAlex Deucher 			else
638d38ceaf9SAlex Deucher 				args.v3.ucEncoderMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
639d38ceaf9SAlex Deucher 
640d38ceaf9SAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode))
641d38ceaf9SAlex Deucher 				args.v3.ucLaneNum = dp_lane_count;
642d38ceaf9SAlex Deucher 			else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
643d38ceaf9SAlex Deucher 				args.v3.ucLaneNum = 8;
644d38ceaf9SAlex Deucher 			else
645d38ceaf9SAlex Deucher 				args.v3.ucLaneNum = 4;
646d38ceaf9SAlex Deucher 
647d38ceaf9SAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v3.ucEncoderMode) && (dp_clock == 270000))
648d38ceaf9SAlex Deucher 				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
649d38ceaf9SAlex Deucher 			args.v3.acConfig.ucDigSel = dig->dig_encoder;
650d38ceaf9SAlex Deucher 			args.v3.ucBitPerColor = amdgpu_atombios_encoder_get_bpc(encoder);
651d38ceaf9SAlex Deucher 			break;
652d38ceaf9SAlex Deucher 		case 4:
653d38ceaf9SAlex Deucher 			args.v4.ucAction = action;
654d38ceaf9SAlex Deucher 			args.v4.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
655d38ceaf9SAlex Deucher 			if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
656d38ceaf9SAlex Deucher 				args.v4.ucPanelMode = panel_mode;
657d38ceaf9SAlex Deucher 			else
658d38ceaf9SAlex Deucher 				args.v4.ucEncoderMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
659d38ceaf9SAlex Deucher 
660d38ceaf9SAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode))
661d38ceaf9SAlex Deucher 				args.v4.ucLaneNum = dp_lane_count;
662d38ceaf9SAlex Deucher 			else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
663d38ceaf9SAlex Deucher 				args.v4.ucLaneNum = 8;
664d38ceaf9SAlex Deucher 			else
665d38ceaf9SAlex Deucher 				args.v4.ucLaneNum = 4;
666d38ceaf9SAlex Deucher 
667d38ceaf9SAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) {
668d38ceaf9SAlex Deucher 				if (dp_clock == 540000)
669d38ceaf9SAlex Deucher 					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ;
670d38ceaf9SAlex Deucher 				else if (dp_clock == 324000)
671d38ceaf9SAlex Deucher 					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_3_24GHZ;
672d38ceaf9SAlex Deucher 				else if (dp_clock == 270000)
673d38ceaf9SAlex Deucher 					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ;
674d38ceaf9SAlex Deucher 				else
675d38ceaf9SAlex Deucher 					args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ;
676d38ceaf9SAlex Deucher 			}
677d38ceaf9SAlex Deucher 			args.v4.acConfig.ucDigSel = dig->dig_encoder;
678d38ceaf9SAlex Deucher 			args.v4.ucBitPerColor = amdgpu_atombios_encoder_get_bpc(encoder);
679d38ceaf9SAlex Deucher 			if (hpd_id == AMDGPU_HPD_NONE)
680d38ceaf9SAlex Deucher 				args.v4.ucHPD_ID = 0;
681d38ceaf9SAlex Deucher 			else
682d38ceaf9SAlex Deucher 				args.v4.ucHPD_ID = hpd_id + 1;
683d38ceaf9SAlex Deucher 			break;
6844b5844e8SAlex Deucher 		case 5:
6854b5844e8SAlex Deucher 			switch (action) {
6864b5844e8SAlex Deucher 			case ATOM_ENCODER_CMD_SETUP_PANEL_MODE:
6874b5844e8SAlex Deucher 				args.v5.asDPPanelModeParam.ucAction = action;
6884b5844e8SAlex Deucher 				args.v5.asDPPanelModeParam.ucPanelMode = panel_mode;
6894b5844e8SAlex Deucher 				args.v5.asDPPanelModeParam.ucDigId = dig->dig_encoder;
6904b5844e8SAlex Deucher 				break;
6914b5844e8SAlex Deucher 			case ATOM_ENCODER_CMD_STREAM_SETUP:
6924b5844e8SAlex Deucher 				args.v5.asStreamParam.ucAction = action;
6934b5844e8SAlex Deucher 				args.v5.asStreamParam.ucDigId = dig->dig_encoder;
6944b5844e8SAlex Deucher 				args.v5.asStreamParam.ucDigMode =
6954b5844e8SAlex Deucher 					amdgpu_atombios_encoder_get_encoder_mode(encoder);
6964b5844e8SAlex Deucher 				if (ENCODER_MODE_IS_DP(args.v5.asStreamParam.ucDigMode))
6974b5844e8SAlex Deucher 					args.v5.asStreamParam.ucLaneNum = dp_lane_count;
6984b5844e8SAlex Deucher 				else if (amdgpu_dig_monitor_is_duallink(encoder,
6994b5844e8SAlex Deucher 									amdgpu_encoder->pixel_clock))
7004b5844e8SAlex Deucher 					args.v5.asStreamParam.ucLaneNum = 8;
7014b5844e8SAlex Deucher 				else
7024b5844e8SAlex Deucher 					args.v5.asStreamParam.ucLaneNum = 4;
7034b5844e8SAlex Deucher 				args.v5.asStreamParam.ulPixelClock =
7044b5844e8SAlex Deucher 					cpu_to_le32(amdgpu_encoder->pixel_clock / 10);
7054b5844e8SAlex Deucher 				args.v5.asStreamParam.ucBitPerColor =
7064b5844e8SAlex Deucher 					amdgpu_atombios_encoder_get_bpc(encoder);
7074b5844e8SAlex Deucher 				args.v5.asStreamParam.ucLinkRateIn270Mhz = dp_clock / 27000;
7084b5844e8SAlex Deucher 				break;
7094b5844e8SAlex Deucher 			case ATOM_ENCODER_CMD_DP_LINK_TRAINING_START:
7104b5844e8SAlex Deucher 			case ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1:
7114b5844e8SAlex Deucher 			case ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2:
7124b5844e8SAlex Deucher 			case ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3:
7134b5844e8SAlex Deucher 			case ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN4:
7144b5844e8SAlex Deucher 			case ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE:
7154b5844e8SAlex Deucher 			case ATOM_ENCODER_CMD_DP_VIDEO_OFF:
7164b5844e8SAlex Deucher 			case ATOM_ENCODER_CMD_DP_VIDEO_ON:
7174b5844e8SAlex Deucher 				args.v5.asCmdParam.ucAction = action;
7184b5844e8SAlex Deucher 				args.v5.asCmdParam.ucDigId = dig->dig_encoder;
7194b5844e8SAlex Deucher 				break;
7204b5844e8SAlex Deucher 			default:
7214b5844e8SAlex Deucher 				DRM_ERROR("Unsupported action 0x%x\n", action);
7224b5844e8SAlex Deucher 				break;
7234b5844e8SAlex Deucher 			}
7244b5844e8SAlex Deucher 			break;
725d38ceaf9SAlex Deucher 		default:
726d38ceaf9SAlex Deucher 			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
727d38ceaf9SAlex Deucher 			break;
728d38ceaf9SAlex Deucher 		}
729d38ceaf9SAlex Deucher 		break;
730d38ceaf9SAlex Deucher 	default:
731d38ceaf9SAlex Deucher 		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
732d38ceaf9SAlex Deucher 		break;
733d38ceaf9SAlex Deucher 	}
734d38ceaf9SAlex Deucher 
735d38ceaf9SAlex Deucher 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
736d38ceaf9SAlex Deucher 
737d38ceaf9SAlex Deucher }
738d38ceaf9SAlex Deucher 
739d38ceaf9SAlex Deucher union dig_transmitter_control {
740d38ceaf9SAlex Deucher 	DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
741d38ceaf9SAlex Deucher 	DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
742d38ceaf9SAlex Deucher 	DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3;
743d38ceaf9SAlex Deucher 	DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4;
744d38ceaf9SAlex Deucher 	DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5 v5;
745d031287aSAlex Deucher 	DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_6 v6;
746d38ceaf9SAlex Deucher };
747d38ceaf9SAlex Deucher 
748d38ceaf9SAlex Deucher void
amdgpu_atombios_encoder_setup_dig_transmitter(struct drm_encoder * encoder,int action,uint8_t lane_num,uint8_t lane_set)749d38ceaf9SAlex Deucher amdgpu_atombios_encoder_setup_dig_transmitter(struct drm_encoder *encoder, int action,
750d38ceaf9SAlex Deucher 					      uint8_t lane_num, uint8_t lane_set)
751d38ceaf9SAlex Deucher {
752d38ceaf9SAlex Deucher 	struct drm_device *dev = encoder->dev;
7531348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
754d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
755d38ceaf9SAlex Deucher 	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
756d38ceaf9SAlex Deucher 	struct drm_connector *connector;
757d38ceaf9SAlex Deucher 	union dig_transmitter_control args;
758d38ceaf9SAlex Deucher 	int index = 0;
759d38ceaf9SAlex Deucher 	uint8_t frev, crev;
760d38ceaf9SAlex Deucher 	bool is_dp = false;
761d38ceaf9SAlex Deucher 	int pll_id = 0;
762d38ceaf9SAlex Deucher 	int dp_clock = 0;
763d38ceaf9SAlex Deucher 	int dp_lane_count = 0;
764d38ceaf9SAlex Deucher 	int connector_object_id = 0;
765d38ceaf9SAlex Deucher 	int dig_encoder = dig->dig_encoder;
766d38ceaf9SAlex Deucher 	int hpd_id = AMDGPU_HPD_NONE;
767d38ceaf9SAlex Deucher 
768d38ceaf9SAlex Deucher 	if (action == ATOM_TRANSMITTER_ACTION_INIT) {
769d38ceaf9SAlex Deucher 		connector = amdgpu_get_connector_for_encoder_init(encoder);
770d38ceaf9SAlex Deucher 		/* just needed to avoid bailing in the encoder check.  the encoder
771d38ceaf9SAlex Deucher 		 * isn't used for init
772d38ceaf9SAlex Deucher 		 */
773d38ceaf9SAlex Deucher 		dig_encoder = 0;
774d38ceaf9SAlex Deucher 	} else
775d38ceaf9SAlex Deucher 		connector = amdgpu_get_connector_for_encoder(encoder);
776d38ceaf9SAlex Deucher 
777d38ceaf9SAlex Deucher 	if (connector) {
778d38ceaf9SAlex Deucher 		struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
779d38ceaf9SAlex Deucher 		struct amdgpu_connector_atom_dig *dig_connector =
780d38ceaf9SAlex Deucher 			amdgpu_connector->con_priv;
781d38ceaf9SAlex Deucher 
782d38ceaf9SAlex Deucher 		hpd_id = amdgpu_connector->hpd.hpd;
783d38ceaf9SAlex Deucher 		dp_clock = dig_connector->dp_clock;
784d38ceaf9SAlex Deucher 		dp_lane_count = dig_connector->dp_lane_count;
785d38ceaf9SAlex Deucher 		connector_object_id =
786d38ceaf9SAlex Deucher 			(amdgpu_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
787d38ceaf9SAlex Deucher 	}
788d38ceaf9SAlex Deucher 
789d38ceaf9SAlex Deucher 	if (encoder->crtc) {
790d38ceaf9SAlex Deucher 		struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
791d38ceaf9SAlex Deucher 		pll_id = amdgpu_crtc->pll_id;
792d38ceaf9SAlex Deucher 	}
793d38ceaf9SAlex Deucher 
794d38ceaf9SAlex Deucher 	/* no dig encoder assigned */
795d38ceaf9SAlex Deucher 	if (dig_encoder == -1)
796d38ceaf9SAlex Deucher 		return;
797d38ceaf9SAlex Deucher 
798d38ceaf9SAlex Deucher 	if (ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(encoder)))
799d38ceaf9SAlex Deucher 		is_dp = true;
800d38ceaf9SAlex Deucher 
801d38ceaf9SAlex Deucher 	memset(&args, 0, sizeof(args));
802d38ceaf9SAlex Deucher 
803d38ceaf9SAlex Deucher 	switch (amdgpu_encoder->encoder_id) {
804d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
805d38ceaf9SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
806d38ceaf9SAlex Deucher 		break;
807d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
808d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
809d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
810d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
811d38ceaf9SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
812d38ceaf9SAlex Deucher 		break;
813d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
814d38ceaf9SAlex Deucher 		index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl);
815d38ceaf9SAlex Deucher 		break;
816d38ceaf9SAlex Deucher 	}
817d38ceaf9SAlex Deucher 
818d38ceaf9SAlex Deucher 	if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
819d38ceaf9SAlex Deucher 		return;
820d38ceaf9SAlex Deucher 
821d38ceaf9SAlex Deucher 	switch (frev) {
822d38ceaf9SAlex Deucher 	case 1:
823d38ceaf9SAlex Deucher 		switch (crev) {
824d38ceaf9SAlex Deucher 		case 1:
825d38ceaf9SAlex Deucher 			args.v1.ucAction = action;
826d38ceaf9SAlex Deucher 			if (action == ATOM_TRANSMITTER_ACTION_INIT) {
827d38ceaf9SAlex Deucher 				args.v1.usInitInfo = cpu_to_le16(connector_object_id);
828d38ceaf9SAlex Deucher 			} else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
829d38ceaf9SAlex Deucher 				args.v1.asMode.ucLaneSel = lane_num;
830d38ceaf9SAlex Deucher 				args.v1.asMode.ucLaneSet = lane_set;
831d38ceaf9SAlex Deucher 			} else {
832d38ceaf9SAlex Deucher 				if (is_dp)
833d38ceaf9SAlex Deucher 					args.v1.usPixelClock = cpu_to_le16(dp_clock / 10);
834d38ceaf9SAlex Deucher 				else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
835d38ceaf9SAlex Deucher 					args.v1.usPixelClock = cpu_to_le16((amdgpu_encoder->pixel_clock / 2) / 10);
836d38ceaf9SAlex Deucher 				else
837d38ceaf9SAlex Deucher 					args.v1.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
838d38ceaf9SAlex Deucher 			}
839d38ceaf9SAlex Deucher 
840d38ceaf9SAlex Deucher 			args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
841d38ceaf9SAlex Deucher 
842d38ceaf9SAlex Deucher 			if (dig_encoder)
843d38ceaf9SAlex Deucher 				args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
844d38ceaf9SAlex Deucher 			else
845d38ceaf9SAlex Deucher 				args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
846d38ceaf9SAlex Deucher 
847d38ceaf9SAlex Deucher 			if (dig->linkb)
848d38ceaf9SAlex Deucher 				args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB;
849d38ceaf9SAlex Deucher 			else
850d38ceaf9SAlex Deucher 				args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
851d38ceaf9SAlex Deucher 
852d38ceaf9SAlex Deucher 			if (is_dp)
853d38ceaf9SAlex Deucher 				args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
854d38ceaf9SAlex Deucher 			else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
855d38ceaf9SAlex Deucher 				if (dig->coherent_mode)
856d38ceaf9SAlex Deucher 					args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
857d38ceaf9SAlex Deucher 				if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
858d38ceaf9SAlex Deucher 					args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK;
859d38ceaf9SAlex Deucher 			}
860d38ceaf9SAlex Deucher 			break;
861d38ceaf9SAlex Deucher 		case 2:
862d38ceaf9SAlex Deucher 			args.v2.ucAction = action;
863d38ceaf9SAlex Deucher 			if (action == ATOM_TRANSMITTER_ACTION_INIT) {
864d38ceaf9SAlex Deucher 				args.v2.usInitInfo = cpu_to_le16(connector_object_id);
865d38ceaf9SAlex Deucher 			} else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
866d38ceaf9SAlex Deucher 				args.v2.asMode.ucLaneSel = lane_num;
867d38ceaf9SAlex Deucher 				args.v2.asMode.ucLaneSet = lane_set;
868d38ceaf9SAlex Deucher 			} else {
869d38ceaf9SAlex Deucher 				if (is_dp)
870d38ceaf9SAlex Deucher 					args.v2.usPixelClock = cpu_to_le16(dp_clock / 10);
871d38ceaf9SAlex Deucher 				else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
872d38ceaf9SAlex Deucher 					args.v2.usPixelClock = cpu_to_le16((amdgpu_encoder->pixel_clock / 2) / 10);
873d38ceaf9SAlex Deucher 				else
874d38ceaf9SAlex Deucher 					args.v2.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
875d38ceaf9SAlex Deucher 			}
876d38ceaf9SAlex Deucher 
877d38ceaf9SAlex Deucher 			args.v2.acConfig.ucEncoderSel = dig_encoder;
878d38ceaf9SAlex Deucher 			if (dig->linkb)
879d38ceaf9SAlex Deucher 				args.v2.acConfig.ucLinkSel = 1;
880d38ceaf9SAlex Deucher 
881d38ceaf9SAlex Deucher 			switch (amdgpu_encoder->encoder_id) {
882d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
883d38ceaf9SAlex Deucher 				args.v2.acConfig.ucTransmitterSel = 0;
884d38ceaf9SAlex Deucher 				break;
885d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
886d38ceaf9SAlex Deucher 				args.v2.acConfig.ucTransmitterSel = 1;
887d38ceaf9SAlex Deucher 				break;
888d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
889d38ceaf9SAlex Deucher 				args.v2.acConfig.ucTransmitterSel = 2;
890d38ceaf9SAlex Deucher 				break;
891d38ceaf9SAlex Deucher 			}
892d38ceaf9SAlex Deucher 
893d38ceaf9SAlex Deucher 			if (is_dp) {
894d38ceaf9SAlex Deucher 				args.v2.acConfig.fCoherentMode = 1;
895d38ceaf9SAlex Deucher 				args.v2.acConfig.fDPConnector = 1;
896d38ceaf9SAlex Deucher 			} else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
897d38ceaf9SAlex Deucher 				if (dig->coherent_mode)
898d38ceaf9SAlex Deucher 					args.v2.acConfig.fCoherentMode = 1;
899d38ceaf9SAlex Deucher 				if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
900d38ceaf9SAlex Deucher 					args.v2.acConfig.fDualLinkConnector = 1;
901d38ceaf9SAlex Deucher 			}
902d38ceaf9SAlex Deucher 			break;
903d38ceaf9SAlex Deucher 		case 3:
904d38ceaf9SAlex Deucher 			args.v3.ucAction = action;
905d38ceaf9SAlex Deucher 			if (action == ATOM_TRANSMITTER_ACTION_INIT) {
906d38ceaf9SAlex Deucher 				args.v3.usInitInfo = cpu_to_le16(connector_object_id);
907d38ceaf9SAlex Deucher 			} else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
908d38ceaf9SAlex Deucher 				args.v3.asMode.ucLaneSel = lane_num;
909d38ceaf9SAlex Deucher 				args.v3.asMode.ucLaneSet = lane_set;
910d38ceaf9SAlex Deucher 			} else {
911d38ceaf9SAlex Deucher 				if (is_dp)
912d38ceaf9SAlex Deucher 					args.v3.usPixelClock = cpu_to_le16(dp_clock / 10);
913d38ceaf9SAlex Deucher 				else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
914d38ceaf9SAlex Deucher 					args.v3.usPixelClock = cpu_to_le16((amdgpu_encoder->pixel_clock / 2) / 10);
915d38ceaf9SAlex Deucher 				else
916d38ceaf9SAlex Deucher 					args.v3.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
917d38ceaf9SAlex Deucher 			}
918d38ceaf9SAlex Deucher 
919d38ceaf9SAlex Deucher 			if (is_dp)
920d38ceaf9SAlex Deucher 				args.v3.ucLaneNum = dp_lane_count;
921d38ceaf9SAlex Deucher 			else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
922d38ceaf9SAlex Deucher 				args.v3.ucLaneNum = 8;
923d38ceaf9SAlex Deucher 			else
924d38ceaf9SAlex Deucher 				args.v3.ucLaneNum = 4;
925d38ceaf9SAlex Deucher 
926d38ceaf9SAlex Deucher 			if (dig->linkb)
927d38ceaf9SAlex Deucher 				args.v3.acConfig.ucLinkSel = 1;
928d38ceaf9SAlex Deucher 			if (dig_encoder & 1)
929d38ceaf9SAlex Deucher 				args.v3.acConfig.ucEncoderSel = 1;
930d38ceaf9SAlex Deucher 
931d38ceaf9SAlex Deucher 			/* Select the PLL for the PHY
932d38ceaf9SAlex Deucher 			 * DP PHY should be clocked from external src if there is
933d38ceaf9SAlex Deucher 			 * one.
934d38ceaf9SAlex Deucher 			 */
935d38ceaf9SAlex Deucher 			/* On DCE4, if there is an external clock, it generates the DP ref clock */
936d38ceaf9SAlex Deucher 			if (is_dp && adev->clock.dp_extclk)
937d38ceaf9SAlex Deucher 				args.v3.acConfig.ucRefClkSource = 2; /* external src */
938d38ceaf9SAlex Deucher 			else
939d38ceaf9SAlex Deucher 				args.v3.acConfig.ucRefClkSource = pll_id;
940d38ceaf9SAlex Deucher 
941d38ceaf9SAlex Deucher 			switch (amdgpu_encoder->encoder_id) {
942d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
943d38ceaf9SAlex Deucher 				args.v3.acConfig.ucTransmitterSel = 0;
944d38ceaf9SAlex Deucher 				break;
945d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
946d38ceaf9SAlex Deucher 				args.v3.acConfig.ucTransmitterSel = 1;
947d38ceaf9SAlex Deucher 				break;
948d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
949d38ceaf9SAlex Deucher 				args.v3.acConfig.ucTransmitterSel = 2;
950d38ceaf9SAlex Deucher 				break;
951d38ceaf9SAlex Deucher 			}
952d38ceaf9SAlex Deucher 
953d38ceaf9SAlex Deucher 			if (is_dp)
954d38ceaf9SAlex Deucher 				args.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */
955d38ceaf9SAlex Deucher 			else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
956d38ceaf9SAlex Deucher 				if (dig->coherent_mode)
957d38ceaf9SAlex Deucher 					args.v3.acConfig.fCoherentMode = 1;
958d38ceaf9SAlex Deucher 				if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
959d38ceaf9SAlex Deucher 					args.v3.acConfig.fDualLinkConnector = 1;
960d38ceaf9SAlex Deucher 			}
961d38ceaf9SAlex Deucher 			break;
962d38ceaf9SAlex Deucher 		case 4:
963d38ceaf9SAlex Deucher 			args.v4.ucAction = action;
964d38ceaf9SAlex Deucher 			if (action == ATOM_TRANSMITTER_ACTION_INIT) {
965d38ceaf9SAlex Deucher 				args.v4.usInitInfo = cpu_to_le16(connector_object_id);
966d38ceaf9SAlex Deucher 			} else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
967d38ceaf9SAlex Deucher 				args.v4.asMode.ucLaneSel = lane_num;
968d38ceaf9SAlex Deucher 				args.v4.asMode.ucLaneSet = lane_set;
969d38ceaf9SAlex Deucher 			} else {
970d38ceaf9SAlex Deucher 				if (is_dp)
971d38ceaf9SAlex Deucher 					args.v4.usPixelClock = cpu_to_le16(dp_clock / 10);
972d38ceaf9SAlex Deucher 				else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
973d38ceaf9SAlex Deucher 					args.v4.usPixelClock = cpu_to_le16((amdgpu_encoder->pixel_clock / 2) / 10);
974d38ceaf9SAlex Deucher 				else
975d38ceaf9SAlex Deucher 					args.v4.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
976d38ceaf9SAlex Deucher 			}
977d38ceaf9SAlex Deucher 
978d38ceaf9SAlex Deucher 			if (is_dp)
979d38ceaf9SAlex Deucher 				args.v4.ucLaneNum = dp_lane_count;
980d38ceaf9SAlex Deucher 			else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
981d38ceaf9SAlex Deucher 				args.v4.ucLaneNum = 8;
982d38ceaf9SAlex Deucher 			else
983d38ceaf9SAlex Deucher 				args.v4.ucLaneNum = 4;
984d38ceaf9SAlex Deucher 
985d38ceaf9SAlex Deucher 			if (dig->linkb)
986d38ceaf9SAlex Deucher 				args.v4.acConfig.ucLinkSel = 1;
987d38ceaf9SAlex Deucher 			if (dig_encoder & 1)
988d38ceaf9SAlex Deucher 				args.v4.acConfig.ucEncoderSel = 1;
989d38ceaf9SAlex Deucher 
990d38ceaf9SAlex Deucher 			/* Select the PLL for the PHY
991d38ceaf9SAlex Deucher 			 * DP PHY should be clocked from external src if there is
992d38ceaf9SAlex Deucher 			 * one.
993d38ceaf9SAlex Deucher 			 */
994d38ceaf9SAlex Deucher 			/* On DCE5 DCPLL usually generates the DP ref clock */
995d38ceaf9SAlex Deucher 			if (is_dp) {
996d38ceaf9SAlex Deucher 				if (adev->clock.dp_extclk)
997d38ceaf9SAlex Deucher 					args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_EXTCLK;
998d38ceaf9SAlex Deucher 				else
999d38ceaf9SAlex Deucher 					args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_DCPLL;
1000d38ceaf9SAlex Deucher 			} else
1001d38ceaf9SAlex Deucher 				args.v4.acConfig.ucRefClkSource = pll_id;
1002d38ceaf9SAlex Deucher 
1003d38ceaf9SAlex Deucher 			switch (amdgpu_encoder->encoder_id) {
1004d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1005d38ceaf9SAlex Deucher 				args.v4.acConfig.ucTransmitterSel = 0;
1006d38ceaf9SAlex Deucher 				break;
1007d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1008d38ceaf9SAlex Deucher 				args.v4.acConfig.ucTransmitterSel = 1;
1009d38ceaf9SAlex Deucher 				break;
1010d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1011d38ceaf9SAlex Deucher 				args.v4.acConfig.ucTransmitterSel = 2;
1012d38ceaf9SAlex Deucher 				break;
1013d38ceaf9SAlex Deucher 			}
1014d38ceaf9SAlex Deucher 
1015d38ceaf9SAlex Deucher 			if (is_dp)
1016d38ceaf9SAlex Deucher 				args.v4.acConfig.fCoherentMode = 1; /* DP requires coherent */
1017d38ceaf9SAlex Deucher 			else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
1018d38ceaf9SAlex Deucher 				if (dig->coherent_mode)
1019d38ceaf9SAlex Deucher 					args.v4.acConfig.fCoherentMode = 1;
1020d38ceaf9SAlex Deucher 				if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
1021d38ceaf9SAlex Deucher 					args.v4.acConfig.fDualLinkConnector = 1;
1022d38ceaf9SAlex Deucher 			}
1023d38ceaf9SAlex Deucher 			break;
1024d38ceaf9SAlex Deucher 		case 5:
1025d38ceaf9SAlex Deucher 			args.v5.ucAction = action;
1026d38ceaf9SAlex Deucher 			if (is_dp)
1027d38ceaf9SAlex Deucher 				args.v5.usSymClock = cpu_to_le16(dp_clock / 10);
1028d38ceaf9SAlex Deucher 			else
1029d38ceaf9SAlex Deucher 				args.v5.usSymClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
1030d38ceaf9SAlex Deucher 
1031d38ceaf9SAlex Deucher 			switch (amdgpu_encoder->encoder_id) {
1032d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1033d38ceaf9SAlex Deucher 				if (dig->linkb)
1034d38ceaf9SAlex Deucher 					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYB;
1035d38ceaf9SAlex Deucher 				else
1036d38ceaf9SAlex Deucher 					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYA;
1037d38ceaf9SAlex Deucher 				break;
1038d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1039d38ceaf9SAlex Deucher 				if (dig->linkb)
1040d38ceaf9SAlex Deucher 					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYD;
1041d38ceaf9SAlex Deucher 				else
1042d38ceaf9SAlex Deucher 					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYC;
1043d38ceaf9SAlex Deucher 				break;
1044d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1045d38ceaf9SAlex Deucher 				if (dig->linkb)
1046d38ceaf9SAlex Deucher 					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYF;
1047d38ceaf9SAlex Deucher 				else
1048d38ceaf9SAlex Deucher 					args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYE;
1049d38ceaf9SAlex Deucher 				break;
1050d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
1051d38ceaf9SAlex Deucher 				args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYG;
1052d38ceaf9SAlex Deucher 				break;
1053d38ceaf9SAlex Deucher 			}
1054d38ceaf9SAlex Deucher 			if (is_dp)
1055d38ceaf9SAlex Deucher 				args.v5.ucLaneNum = dp_lane_count;
1056d38ceaf9SAlex Deucher 			else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
1057d38ceaf9SAlex Deucher 				args.v5.ucLaneNum = 8;
1058d38ceaf9SAlex Deucher 			else
1059d38ceaf9SAlex Deucher 				args.v5.ucLaneNum = 4;
1060d38ceaf9SAlex Deucher 			args.v5.ucConnObjId = connector_object_id;
1061d38ceaf9SAlex Deucher 			args.v5.ucDigMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
1062d38ceaf9SAlex Deucher 
1063d38ceaf9SAlex Deucher 			if (is_dp && adev->clock.dp_extclk)
1064d38ceaf9SAlex Deucher 				args.v5.asConfig.ucPhyClkSrcId = ENCODER_REFCLK_SRC_EXTCLK;
1065d38ceaf9SAlex Deucher 			else
1066d38ceaf9SAlex Deucher 				args.v5.asConfig.ucPhyClkSrcId = pll_id;
1067d38ceaf9SAlex Deucher 
1068d38ceaf9SAlex Deucher 			if (is_dp)
1069d38ceaf9SAlex Deucher 				args.v5.asConfig.ucCoherentMode = 1; /* DP requires coherent */
1070d38ceaf9SAlex Deucher 			else if (amdgpu_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
1071d38ceaf9SAlex Deucher 				if (dig->coherent_mode)
1072d38ceaf9SAlex Deucher 					args.v5.asConfig.ucCoherentMode = 1;
1073d38ceaf9SAlex Deucher 			}
1074d38ceaf9SAlex Deucher 			if (hpd_id == AMDGPU_HPD_NONE)
1075d38ceaf9SAlex Deucher 				args.v5.asConfig.ucHPDSel = 0;
1076d38ceaf9SAlex Deucher 			else
1077d38ceaf9SAlex Deucher 				args.v5.asConfig.ucHPDSel = hpd_id + 1;
1078d38ceaf9SAlex Deucher 			args.v5.ucDigEncoderSel = 1 << dig_encoder;
1079d38ceaf9SAlex Deucher 			args.v5.ucDPLaneSet = lane_set;
1080d38ceaf9SAlex Deucher 			break;
1081d031287aSAlex Deucher 		case 6:
1082d031287aSAlex Deucher 			args.v6.ucAction = action;
1083d031287aSAlex Deucher 			if (is_dp)
1084d031287aSAlex Deucher 				args.v6.ulSymClock = cpu_to_le32(dp_clock / 10);
1085d031287aSAlex Deucher 			else
1086d031287aSAlex Deucher 				args.v6.ulSymClock = cpu_to_le32(amdgpu_encoder->pixel_clock / 10);
1087d031287aSAlex Deucher 
1088d031287aSAlex Deucher 			switch (amdgpu_encoder->encoder_id) {
1089d031287aSAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1090d031287aSAlex Deucher 				if (dig->linkb)
1091d031287aSAlex Deucher 					args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYB;
1092d031287aSAlex Deucher 				else
1093d031287aSAlex Deucher 					args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYA;
1094d031287aSAlex Deucher 				break;
1095d031287aSAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1096d031287aSAlex Deucher 				if (dig->linkb)
1097d031287aSAlex Deucher 					args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYD;
1098d031287aSAlex Deucher 				else
1099d031287aSAlex Deucher 					args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYC;
1100d031287aSAlex Deucher 				break;
1101d031287aSAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1102d031287aSAlex Deucher 				if (dig->linkb)
1103d031287aSAlex Deucher 					args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYF;
1104d031287aSAlex Deucher 				else
1105d031287aSAlex Deucher 					args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYE;
1106d031287aSAlex Deucher 				break;
1107d031287aSAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
1108d031287aSAlex Deucher 				args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYG;
1109d031287aSAlex Deucher 				break;
1110d031287aSAlex Deucher 			}
1111d031287aSAlex Deucher 			if (is_dp)
1112d031287aSAlex Deucher 				args.v6.ucLaneNum = dp_lane_count;
1113d031287aSAlex Deucher 			else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
1114d031287aSAlex Deucher 				args.v6.ucLaneNum = 8;
1115d031287aSAlex Deucher 			else
1116d031287aSAlex Deucher 				args.v6.ucLaneNum = 4;
1117d031287aSAlex Deucher 			args.v6.ucConnObjId = connector_object_id;
1118d031287aSAlex Deucher 			if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH)
1119d031287aSAlex Deucher 				args.v6.ucDPLaneSet = lane_set;
1120d031287aSAlex Deucher 			else
1121d031287aSAlex Deucher 				args.v6.ucDigMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
1122d031287aSAlex Deucher 
1123d031287aSAlex Deucher 			if (hpd_id == AMDGPU_HPD_NONE)
1124d031287aSAlex Deucher 				args.v6.ucHPDSel = 0;
1125d031287aSAlex Deucher 			else
1126d031287aSAlex Deucher 				args.v6.ucHPDSel = hpd_id + 1;
1127d031287aSAlex Deucher 			args.v6.ucDigEncoderSel = 1 << dig_encoder;
1128d031287aSAlex Deucher 			break;
1129d38ceaf9SAlex Deucher 		default:
1130d38ceaf9SAlex Deucher 			DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
1131d38ceaf9SAlex Deucher 			break;
1132d38ceaf9SAlex Deucher 		}
1133d38ceaf9SAlex Deucher 		break;
1134d38ceaf9SAlex Deucher 	default:
1135d38ceaf9SAlex Deucher 		DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
1136d38ceaf9SAlex Deucher 		break;
1137d38ceaf9SAlex Deucher 	}
1138d38ceaf9SAlex Deucher 
1139d38ceaf9SAlex Deucher 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
1140d38ceaf9SAlex Deucher }
1141d38ceaf9SAlex Deucher 
1142d38ceaf9SAlex Deucher bool
amdgpu_atombios_encoder_set_edp_panel_power(struct drm_connector * connector,int action)1143d38ceaf9SAlex Deucher amdgpu_atombios_encoder_set_edp_panel_power(struct drm_connector *connector,
1144d38ceaf9SAlex Deucher 				     int action)
1145d38ceaf9SAlex Deucher {
1146d38ceaf9SAlex Deucher 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
1147d38ceaf9SAlex Deucher 	struct drm_device *dev = amdgpu_connector->base.dev;
11481348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
1149d38ceaf9SAlex Deucher 	union dig_transmitter_control args;
1150d38ceaf9SAlex Deucher 	int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
1151d38ceaf9SAlex Deucher 	uint8_t frev, crev;
1152d38ceaf9SAlex Deucher 
1153d38ceaf9SAlex Deucher 	if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
1154d38ceaf9SAlex Deucher 		goto done;
1155d38ceaf9SAlex Deucher 
1156d38ceaf9SAlex Deucher 	if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) &&
1157d38ceaf9SAlex Deucher 	    (action != ATOM_TRANSMITTER_ACTION_POWER_OFF))
1158d38ceaf9SAlex Deucher 		goto done;
1159d38ceaf9SAlex Deucher 
1160d38ceaf9SAlex Deucher 	if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
1161d38ceaf9SAlex Deucher 		goto done;
1162d38ceaf9SAlex Deucher 
1163d38ceaf9SAlex Deucher 	memset(&args, 0, sizeof(args));
1164d38ceaf9SAlex Deucher 
1165d38ceaf9SAlex Deucher 	args.v1.ucAction = action;
1166d38ceaf9SAlex Deucher 
1167d38ceaf9SAlex Deucher 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
1168d38ceaf9SAlex Deucher 
1169d38ceaf9SAlex Deucher 	/* wait for the panel to power up */
1170d38ceaf9SAlex Deucher 	if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) {
1171d38ceaf9SAlex Deucher 		int i;
1172d38ceaf9SAlex Deucher 
1173d38ceaf9SAlex Deucher 		for (i = 0; i < 300; i++) {
1174d38ceaf9SAlex Deucher 			if (amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd))
1175d38ceaf9SAlex Deucher 				return true;
1176d38ceaf9SAlex Deucher 			mdelay(1);
1177d38ceaf9SAlex Deucher 		}
1178d38ceaf9SAlex Deucher 		return false;
1179d38ceaf9SAlex Deucher 	}
1180d38ceaf9SAlex Deucher done:
1181d38ceaf9SAlex Deucher 	return true;
1182d38ceaf9SAlex Deucher }
1183d38ceaf9SAlex Deucher 
1184d38ceaf9SAlex Deucher union external_encoder_control {
1185d38ceaf9SAlex Deucher 	EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1;
1186d38ceaf9SAlex Deucher 	EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3;
1187d38ceaf9SAlex Deucher };
1188d38ceaf9SAlex Deucher 
1189d38ceaf9SAlex Deucher static void
amdgpu_atombios_encoder_setup_external_encoder(struct drm_encoder * encoder,struct drm_encoder * ext_encoder,int action)1190d38ceaf9SAlex Deucher amdgpu_atombios_encoder_setup_external_encoder(struct drm_encoder *encoder,
1191d38ceaf9SAlex Deucher 					struct drm_encoder *ext_encoder,
1192d38ceaf9SAlex Deucher 					int action)
1193d38ceaf9SAlex Deucher {
1194d38ceaf9SAlex Deucher 	struct drm_device *dev = encoder->dev;
11951348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
1196d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
1197d38ceaf9SAlex Deucher 	struct amdgpu_encoder *ext_amdgpu_encoder = to_amdgpu_encoder(ext_encoder);
1198d38ceaf9SAlex Deucher 	union external_encoder_control args;
1199d38ceaf9SAlex Deucher 	struct drm_connector *connector;
1200d38ceaf9SAlex Deucher 	int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl);
1201d38ceaf9SAlex Deucher 	u8 frev, crev;
1202d38ceaf9SAlex Deucher 	int dp_clock = 0;
1203d38ceaf9SAlex Deucher 	int dp_lane_count = 0;
1204d38ceaf9SAlex Deucher 	int connector_object_id = 0;
1205d38ceaf9SAlex Deucher 	u32 ext_enum = (ext_amdgpu_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
1206d38ceaf9SAlex Deucher 
1207d38ceaf9SAlex Deucher 	if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
1208d38ceaf9SAlex Deucher 		connector = amdgpu_get_connector_for_encoder_init(encoder);
1209d38ceaf9SAlex Deucher 	else
1210d38ceaf9SAlex Deucher 		connector = amdgpu_get_connector_for_encoder(encoder);
1211d38ceaf9SAlex Deucher 
1212d38ceaf9SAlex Deucher 	if (connector) {
1213d38ceaf9SAlex Deucher 		struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
1214d38ceaf9SAlex Deucher 		struct amdgpu_connector_atom_dig *dig_connector =
1215d38ceaf9SAlex Deucher 			amdgpu_connector->con_priv;
1216d38ceaf9SAlex Deucher 
1217d38ceaf9SAlex Deucher 		dp_clock = dig_connector->dp_clock;
1218d38ceaf9SAlex Deucher 		dp_lane_count = dig_connector->dp_lane_count;
1219d38ceaf9SAlex Deucher 		connector_object_id =
1220d38ceaf9SAlex Deucher 			(amdgpu_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
1221d38ceaf9SAlex Deucher 	}
1222d38ceaf9SAlex Deucher 
1223d38ceaf9SAlex Deucher 	memset(&args, 0, sizeof(args));
1224d38ceaf9SAlex Deucher 
1225d38ceaf9SAlex Deucher 	if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
1226d38ceaf9SAlex Deucher 		return;
1227d38ceaf9SAlex Deucher 
1228d38ceaf9SAlex Deucher 	switch (frev) {
1229d38ceaf9SAlex Deucher 	case 1:
1230d38ceaf9SAlex Deucher 		/* no params on frev 1 */
1231d38ceaf9SAlex Deucher 		break;
1232d38ceaf9SAlex Deucher 	case 2:
1233d38ceaf9SAlex Deucher 		switch (crev) {
1234d38ceaf9SAlex Deucher 		case 1:
1235d38ceaf9SAlex Deucher 		case 2:
1236d38ceaf9SAlex Deucher 			args.v1.sDigEncoder.ucAction = action;
1237d38ceaf9SAlex Deucher 			args.v1.sDigEncoder.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
1238d38ceaf9SAlex Deucher 			args.v1.sDigEncoder.ucEncoderMode =
1239d38ceaf9SAlex Deucher 				amdgpu_atombios_encoder_get_encoder_mode(encoder);
1240d38ceaf9SAlex Deucher 
1241d38ceaf9SAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v1.sDigEncoder.ucEncoderMode)) {
1242d38ceaf9SAlex Deucher 				if (dp_clock == 270000)
1243d38ceaf9SAlex Deucher 					args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
1244d38ceaf9SAlex Deucher 				args.v1.sDigEncoder.ucLaneNum = dp_lane_count;
1245d38ceaf9SAlex Deucher 			} else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
1246d38ceaf9SAlex Deucher 				args.v1.sDigEncoder.ucLaneNum = 8;
1247d38ceaf9SAlex Deucher 			else
1248d38ceaf9SAlex Deucher 				args.v1.sDigEncoder.ucLaneNum = 4;
1249d38ceaf9SAlex Deucher 			break;
1250d38ceaf9SAlex Deucher 		case 3:
1251d38ceaf9SAlex Deucher 			args.v3.sExtEncoder.ucAction = action;
1252d38ceaf9SAlex Deucher 			if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
1253d38ceaf9SAlex Deucher 				args.v3.sExtEncoder.usConnectorId = cpu_to_le16(connector_object_id);
1254d38ceaf9SAlex Deucher 			else
1255d38ceaf9SAlex Deucher 				args.v3.sExtEncoder.usPixelClock = cpu_to_le16(amdgpu_encoder->pixel_clock / 10);
1256d38ceaf9SAlex Deucher 			args.v3.sExtEncoder.ucEncoderMode =
1257d38ceaf9SAlex Deucher 				amdgpu_atombios_encoder_get_encoder_mode(encoder);
1258d38ceaf9SAlex Deucher 
1259d38ceaf9SAlex Deucher 			if (ENCODER_MODE_IS_DP(args.v3.sExtEncoder.ucEncoderMode)) {
1260d38ceaf9SAlex Deucher 				if (dp_clock == 270000)
1261d38ceaf9SAlex Deucher 					args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
1262d38ceaf9SAlex Deucher 				else if (dp_clock == 540000)
1263d38ceaf9SAlex Deucher 					args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ;
1264d38ceaf9SAlex Deucher 				args.v3.sExtEncoder.ucLaneNum = dp_lane_count;
1265d38ceaf9SAlex Deucher 			} else if (amdgpu_dig_monitor_is_duallink(encoder, amdgpu_encoder->pixel_clock))
1266d38ceaf9SAlex Deucher 				args.v3.sExtEncoder.ucLaneNum = 8;
1267d38ceaf9SAlex Deucher 			else
1268d38ceaf9SAlex Deucher 				args.v3.sExtEncoder.ucLaneNum = 4;
1269d38ceaf9SAlex Deucher 			switch (ext_enum) {
1270d38ceaf9SAlex Deucher 			case GRAPH_OBJECT_ENUM_ID1:
1271d38ceaf9SAlex Deucher 				args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1;
1272d38ceaf9SAlex Deucher 				break;
1273d38ceaf9SAlex Deucher 			case GRAPH_OBJECT_ENUM_ID2:
1274d38ceaf9SAlex Deucher 				args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2;
1275d38ceaf9SAlex Deucher 				break;
1276d38ceaf9SAlex Deucher 			case GRAPH_OBJECT_ENUM_ID3:
1277d38ceaf9SAlex Deucher 				args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3;
1278d38ceaf9SAlex Deucher 				break;
1279d38ceaf9SAlex Deucher 			}
1280d38ceaf9SAlex Deucher 			args.v3.sExtEncoder.ucBitPerColor = amdgpu_atombios_encoder_get_bpc(encoder);
1281d38ceaf9SAlex Deucher 			break;
1282d38ceaf9SAlex Deucher 		default:
1283d38ceaf9SAlex Deucher 			DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
1284d38ceaf9SAlex Deucher 			return;
1285d38ceaf9SAlex Deucher 		}
1286d38ceaf9SAlex Deucher 		break;
1287d38ceaf9SAlex Deucher 	default:
1288d38ceaf9SAlex Deucher 		DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
1289d38ceaf9SAlex Deucher 		return;
1290d38ceaf9SAlex Deucher 	}
1291d38ceaf9SAlex Deucher 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
1292d38ceaf9SAlex Deucher }
1293d38ceaf9SAlex Deucher 
1294d38ceaf9SAlex Deucher static void
amdgpu_atombios_encoder_setup_dig(struct drm_encoder * encoder,int action)1295d38ceaf9SAlex Deucher amdgpu_atombios_encoder_setup_dig(struct drm_encoder *encoder, int action)
1296d38ceaf9SAlex Deucher {
1297d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
1298d38ceaf9SAlex Deucher 	struct drm_encoder *ext_encoder = amdgpu_get_external_encoder(encoder);
1299d38ceaf9SAlex Deucher 	struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
1300d38ceaf9SAlex Deucher 	struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
1301d38ceaf9SAlex Deucher 	struct amdgpu_connector *amdgpu_connector = NULL;
1302d38ceaf9SAlex Deucher 	struct amdgpu_connector_atom_dig *amdgpu_dig_connector = NULL;
1303d38ceaf9SAlex Deucher 
1304d38ceaf9SAlex Deucher 	if (connector) {
1305d38ceaf9SAlex Deucher 		amdgpu_connector = to_amdgpu_connector(connector);
1306d38ceaf9SAlex Deucher 		amdgpu_dig_connector = amdgpu_connector->con_priv;
1307d38ceaf9SAlex Deucher 	}
1308d38ceaf9SAlex Deucher 
1309d38ceaf9SAlex Deucher 	if (action == ATOM_ENABLE) {
1310d38ceaf9SAlex Deucher 		if (!connector)
1311d38ceaf9SAlex Deucher 			dig->panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
1312d38ceaf9SAlex Deucher 		else
1313d38ceaf9SAlex Deucher 			dig->panel_mode = amdgpu_atombios_dp_get_panel_mode(encoder, connector);
1314d38ceaf9SAlex Deucher 
1315d38ceaf9SAlex Deucher 		/* setup and enable the encoder */
1316d38ceaf9SAlex Deucher 		amdgpu_atombios_encoder_setup_dig_encoder(encoder, ATOM_ENCODER_CMD_SETUP, 0);
1317d38ceaf9SAlex Deucher 		amdgpu_atombios_encoder_setup_dig_encoder(encoder,
1318d38ceaf9SAlex Deucher 						   ATOM_ENCODER_CMD_SETUP_PANEL_MODE,
1319d38ceaf9SAlex Deucher 						   dig->panel_mode);
1320d38ceaf9SAlex Deucher 		if (ext_encoder)
1321d38ceaf9SAlex Deucher 			amdgpu_atombios_encoder_setup_external_encoder(encoder, ext_encoder,
1322d38ceaf9SAlex Deucher 								EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP);
1323d38ceaf9SAlex Deucher 		if (ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(encoder)) &&
1324d38ceaf9SAlex Deucher 		    connector) {
1325d38ceaf9SAlex Deucher 			if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
1326d38ceaf9SAlex Deucher 				amdgpu_atombios_encoder_set_edp_panel_power(connector,
1327d38ceaf9SAlex Deucher 								     ATOM_TRANSMITTER_ACTION_POWER_ON);
1328d38ceaf9SAlex Deucher 				amdgpu_dig_connector->edp_on = true;
1329d38ceaf9SAlex Deucher 			}
1330d38ceaf9SAlex Deucher 		}
1331d38ceaf9SAlex Deucher 		/* enable the transmitter */
1332d38ceaf9SAlex Deucher 		amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
1333d38ceaf9SAlex Deucher 						       ATOM_TRANSMITTER_ACTION_ENABLE,
1334d38ceaf9SAlex Deucher 						       0, 0);
1335d38ceaf9SAlex Deucher 		if (ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(encoder)) &&
1336d38ceaf9SAlex Deucher 		    connector) {
1337d38ceaf9SAlex Deucher 			/* DP_SET_POWER_D0 is set in amdgpu_atombios_dp_link_train */
1338d38ceaf9SAlex Deucher 			amdgpu_atombios_dp_link_train(encoder, connector);
1339d38ceaf9SAlex Deucher 			amdgpu_atombios_encoder_setup_dig_encoder(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);
1340d38ceaf9SAlex Deucher 		}
1341d38ceaf9SAlex Deucher 		if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
134274b3112eSAlex Deucher 			amdgpu_atombios_encoder_set_backlight_level(amdgpu_encoder, dig->backlight_level);
1343d38ceaf9SAlex Deucher 		if (ext_encoder)
1344d38ceaf9SAlex Deucher 			amdgpu_atombios_encoder_setup_external_encoder(encoder, ext_encoder, ATOM_ENABLE);
1345d38ceaf9SAlex Deucher 	} else {
1346d38ceaf9SAlex Deucher 		if (ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(encoder)) &&
1347d38ceaf9SAlex Deucher 		    connector)
1348d38ceaf9SAlex Deucher 			amdgpu_atombios_encoder_setup_dig_encoder(encoder,
1349d38ceaf9SAlex Deucher 							   ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
1350d38ceaf9SAlex Deucher 		if (ext_encoder)
1351d38ceaf9SAlex Deucher 			amdgpu_atombios_encoder_setup_external_encoder(encoder, ext_encoder, ATOM_DISABLE);
1352d38ceaf9SAlex Deucher 		if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
1353d38ceaf9SAlex Deucher 			amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
1354d38ceaf9SAlex Deucher 							       ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
1355d38ceaf9SAlex Deucher 
1356d38ceaf9SAlex Deucher 		if (ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(encoder)) &&
1357d38ceaf9SAlex Deucher 		    connector)
1358d38ceaf9SAlex Deucher 			amdgpu_atombios_dp_set_rx_power_state(connector, DP_SET_POWER_D3);
1359d38ceaf9SAlex Deucher 		/* disable the transmitter */
1360d38ceaf9SAlex Deucher 		amdgpu_atombios_encoder_setup_dig_transmitter(encoder,
1361d38ceaf9SAlex Deucher 						       ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
1362d38ceaf9SAlex Deucher 		if (ENCODER_MODE_IS_DP(amdgpu_atombios_encoder_get_encoder_mode(encoder)) &&
1363d38ceaf9SAlex Deucher 		    connector) {
1364d38ceaf9SAlex Deucher 			if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
1365d38ceaf9SAlex Deucher 				amdgpu_atombios_encoder_set_edp_panel_power(connector,
1366d38ceaf9SAlex Deucher 								     ATOM_TRANSMITTER_ACTION_POWER_OFF);
1367d38ceaf9SAlex Deucher 				amdgpu_dig_connector->edp_on = false;
1368d38ceaf9SAlex Deucher 			}
1369d38ceaf9SAlex Deucher 		}
1370d38ceaf9SAlex Deucher 	}
1371d38ceaf9SAlex Deucher }
1372d38ceaf9SAlex Deucher 
1373d38ceaf9SAlex Deucher void
amdgpu_atombios_encoder_dpms(struct drm_encoder * encoder,int mode)1374d38ceaf9SAlex Deucher amdgpu_atombios_encoder_dpms(struct drm_encoder *encoder, int mode)
1375d38ceaf9SAlex Deucher {
1376d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
1377d38ceaf9SAlex Deucher 
1378d38ceaf9SAlex Deucher 	DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n",
1379d38ceaf9SAlex Deucher 		  amdgpu_encoder->encoder_id, mode, amdgpu_encoder->devices,
1380d38ceaf9SAlex Deucher 		  amdgpu_encoder->active_device);
1381d38ceaf9SAlex Deucher 	switch (amdgpu_encoder->encoder_id) {
1382d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1383d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1384d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1385d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
1386d38ceaf9SAlex Deucher 		switch (mode) {
1387d38ceaf9SAlex Deucher 		case DRM_MODE_DPMS_ON:
1388d38ceaf9SAlex Deucher 			amdgpu_atombios_encoder_setup_dig(encoder, ATOM_ENABLE);
1389d38ceaf9SAlex Deucher 			break;
1390d38ceaf9SAlex Deucher 		case DRM_MODE_DPMS_STANDBY:
1391d38ceaf9SAlex Deucher 		case DRM_MODE_DPMS_SUSPEND:
1392d38ceaf9SAlex Deucher 		case DRM_MODE_DPMS_OFF:
1393d38ceaf9SAlex Deucher 			amdgpu_atombios_encoder_setup_dig(encoder, ATOM_DISABLE);
1394d38ceaf9SAlex Deucher 			break;
1395d38ceaf9SAlex Deucher 		}
1396d38ceaf9SAlex Deucher 		break;
1397d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1398d38ceaf9SAlex Deucher 		switch (mode) {
1399d38ceaf9SAlex Deucher 		case DRM_MODE_DPMS_ON:
1400d38ceaf9SAlex Deucher 			amdgpu_atombios_encoder_setup_dvo(encoder, ATOM_ENABLE);
1401d38ceaf9SAlex Deucher 			break;
1402d38ceaf9SAlex Deucher 		case DRM_MODE_DPMS_STANDBY:
1403d38ceaf9SAlex Deucher 		case DRM_MODE_DPMS_SUSPEND:
1404d38ceaf9SAlex Deucher 		case DRM_MODE_DPMS_OFF:
1405d38ceaf9SAlex Deucher 			amdgpu_atombios_encoder_setup_dvo(encoder, ATOM_DISABLE);
1406d38ceaf9SAlex Deucher 			break;
1407d38ceaf9SAlex Deucher 		}
1408d38ceaf9SAlex Deucher 		break;
1409d38ceaf9SAlex Deucher 	case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1410d38ceaf9SAlex Deucher 		switch (mode) {
1411d38ceaf9SAlex Deucher 		case DRM_MODE_DPMS_ON:
1412d38ceaf9SAlex Deucher 			amdgpu_atombios_encoder_setup_dac(encoder, ATOM_ENABLE);
1413d38ceaf9SAlex Deucher 			break;
1414d38ceaf9SAlex Deucher 		case DRM_MODE_DPMS_STANDBY:
1415d38ceaf9SAlex Deucher 		case DRM_MODE_DPMS_SUSPEND:
1416d38ceaf9SAlex Deucher 		case DRM_MODE_DPMS_OFF:
1417d38ceaf9SAlex Deucher 			amdgpu_atombios_encoder_setup_dac(encoder, ATOM_DISABLE);
1418d38ceaf9SAlex Deucher 			break;
1419d38ceaf9SAlex Deucher 		}
1420d38ceaf9SAlex Deucher 		break;
1421d38ceaf9SAlex Deucher 	default:
1422d38ceaf9SAlex Deucher 		return;
1423d38ceaf9SAlex Deucher 	}
1424d38ceaf9SAlex Deucher }
1425d38ceaf9SAlex Deucher 
1426d38ceaf9SAlex Deucher union crtc_source_param {
1427d38ceaf9SAlex Deucher 	SELECT_CRTC_SOURCE_PS_ALLOCATION v1;
1428d38ceaf9SAlex Deucher 	SELECT_CRTC_SOURCE_PARAMETERS_V2 v2;
1429d38ceaf9SAlex Deucher 	SELECT_CRTC_SOURCE_PARAMETERS_V3 v3;
1430d38ceaf9SAlex Deucher };
1431d38ceaf9SAlex Deucher 
1432d38ceaf9SAlex Deucher void
amdgpu_atombios_encoder_set_crtc_source(struct drm_encoder * encoder)1433d38ceaf9SAlex Deucher amdgpu_atombios_encoder_set_crtc_source(struct drm_encoder *encoder)
1434d38ceaf9SAlex Deucher {
1435d38ceaf9SAlex Deucher 	struct drm_device *dev = encoder->dev;
14361348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
1437d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
1438d38ceaf9SAlex Deucher 	struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(encoder->crtc);
1439d38ceaf9SAlex Deucher 	union crtc_source_param args;
1440d38ceaf9SAlex Deucher 	int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
1441d38ceaf9SAlex Deucher 	uint8_t frev, crev;
1442d38ceaf9SAlex Deucher 	struct amdgpu_encoder_atom_dig *dig;
1443d38ceaf9SAlex Deucher 
1444d38ceaf9SAlex Deucher 	memset(&args, 0, sizeof(args));
1445d38ceaf9SAlex Deucher 
1446d38ceaf9SAlex Deucher 	if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
1447d38ceaf9SAlex Deucher 		return;
1448d38ceaf9SAlex Deucher 
1449d38ceaf9SAlex Deucher 	switch (frev) {
1450d38ceaf9SAlex Deucher 	case 1:
1451d38ceaf9SAlex Deucher 		switch (crev) {
1452d38ceaf9SAlex Deucher 		case 1:
1453d38ceaf9SAlex Deucher 		default:
1454d38ceaf9SAlex Deucher 			args.v1.ucCRTC = amdgpu_crtc->crtc_id;
1455d38ceaf9SAlex Deucher 			switch (amdgpu_encoder->encoder_id) {
1456d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1457d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1458d38ceaf9SAlex Deucher 				args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX;
1459d38ceaf9SAlex Deucher 				break;
1460d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1461d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1462d38ceaf9SAlex Deucher 				if (amdgpu_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT)
1463d38ceaf9SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX;
1464d38ceaf9SAlex Deucher 				else
1465d38ceaf9SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX;
1466d38ceaf9SAlex Deucher 				break;
1467d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1468d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_DDI:
1469d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1470d38ceaf9SAlex Deucher 				args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX;
1471d38ceaf9SAlex Deucher 				break;
1472d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1473d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1474d38ceaf9SAlex Deucher 				if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
1475d38ceaf9SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
1476d38ceaf9SAlex Deucher 				else if (amdgpu_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
1477d38ceaf9SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
1478d38ceaf9SAlex Deucher 				else
1479d38ceaf9SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX;
1480d38ceaf9SAlex Deucher 				break;
1481d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1482d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1483d38ceaf9SAlex Deucher 				if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
1484d38ceaf9SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
1485d38ceaf9SAlex Deucher 				else if (amdgpu_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
1486d38ceaf9SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
1487d38ceaf9SAlex Deucher 				else
1488d38ceaf9SAlex Deucher 					args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX;
1489d38ceaf9SAlex Deucher 				break;
1490d38ceaf9SAlex Deucher 			}
1491d38ceaf9SAlex Deucher 			break;
1492d38ceaf9SAlex Deucher 		case 2:
1493d38ceaf9SAlex Deucher 			args.v2.ucCRTC = amdgpu_crtc->crtc_id;
1494d38ceaf9SAlex Deucher 			if (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) {
1495d38ceaf9SAlex Deucher 				struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
1496d38ceaf9SAlex Deucher 
1497d38ceaf9SAlex Deucher 				if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1498d38ceaf9SAlex Deucher 					args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS;
1499d38ceaf9SAlex Deucher 				else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA)
1500d38ceaf9SAlex Deucher 					args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT;
1501d38ceaf9SAlex Deucher 				else
1502d38ceaf9SAlex Deucher 					args.v2.ucEncodeMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
1503d38ceaf9SAlex Deucher 			} else if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
1504d38ceaf9SAlex Deucher 				args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS;
1505d38ceaf9SAlex Deucher 			} else {
1506d38ceaf9SAlex Deucher 				args.v2.ucEncodeMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
1507d38ceaf9SAlex Deucher 			}
1508d38ceaf9SAlex Deucher 			switch (amdgpu_encoder->encoder_id) {
1509d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1510d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1511d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1512d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
1513d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1514d38ceaf9SAlex Deucher 				dig = amdgpu_encoder->enc_priv;
1515d38ceaf9SAlex Deucher 				switch (dig->dig_encoder) {
1516d38ceaf9SAlex Deucher 				case 0:
1517d38ceaf9SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
1518d38ceaf9SAlex Deucher 					break;
1519d38ceaf9SAlex Deucher 				case 1:
1520d38ceaf9SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
1521d38ceaf9SAlex Deucher 					break;
1522d38ceaf9SAlex Deucher 				case 2:
1523d38ceaf9SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID;
1524d38ceaf9SAlex Deucher 					break;
1525d38ceaf9SAlex Deucher 				case 3:
1526d38ceaf9SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID;
1527d38ceaf9SAlex Deucher 					break;
1528d38ceaf9SAlex Deucher 				case 4:
1529d38ceaf9SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID;
1530d38ceaf9SAlex Deucher 					break;
1531d38ceaf9SAlex Deucher 				case 5:
1532d38ceaf9SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
1533d38ceaf9SAlex Deucher 					break;
1534d38ceaf9SAlex Deucher 				case 6:
1535d38ceaf9SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID;
1536d38ceaf9SAlex Deucher 					break;
1537d38ceaf9SAlex Deucher 				}
1538d38ceaf9SAlex Deucher 				break;
1539d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1540d38ceaf9SAlex Deucher 				args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID;
1541d38ceaf9SAlex Deucher 				break;
1542d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1543d38ceaf9SAlex Deucher 				if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
1544d38ceaf9SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1545d38ceaf9SAlex Deucher 				else if (amdgpu_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
1546d38ceaf9SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1547d38ceaf9SAlex Deucher 				else
1548d38ceaf9SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
1549d38ceaf9SAlex Deucher 				break;
1550d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1551d38ceaf9SAlex Deucher 				if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
1552d38ceaf9SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1553d38ceaf9SAlex Deucher 				else if (amdgpu_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
1554d38ceaf9SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1555d38ceaf9SAlex Deucher 				else
1556d38ceaf9SAlex Deucher 					args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
1557d38ceaf9SAlex Deucher 				break;
1558d38ceaf9SAlex Deucher 			}
1559d38ceaf9SAlex Deucher 			break;
1560d38ceaf9SAlex Deucher 		case 3:
1561d38ceaf9SAlex Deucher 			args.v3.ucCRTC = amdgpu_crtc->crtc_id;
1562d38ceaf9SAlex Deucher 			if (amdgpu_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) {
1563d38ceaf9SAlex Deucher 				struct drm_connector *connector = amdgpu_get_connector_for_encoder(encoder);
1564d38ceaf9SAlex Deucher 
1565d38ceaf9SAlex Deucher 				if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
1566d38ceaf9SAlex Deucher 					args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS;
1567d38ceaf9SAlex Deucher 				else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA)
1568d38ceaf9SAlex Deucher 					args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT;
1569d38ceaf9SAlex Deucher 				else
1570d38ceaf9SAlex Deucher 					args.v2.ucEncodeMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
1571d38ceaf9SAlex Deucher 			} else if (amdgpu_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
1572d38ceaf9SAlex Deucher 				args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS;
1573d38ceaf9SAlex Deucher 			} else {
1574d38ceaf9SAlex Deucher 				args.v2.ucEncodeMode = amdgpu_atombios_encoder_get_encoder_mode(encoder);
1575d38ceaf9SAlex Deucher 			}
1576d38ceaf9SAlex Deucher 			args.v3.ucDstBpc = amdgpu_atombios_encoder_get_bpc(encoder);
1577d38ceaf9SAlex Deucher 			switch (amdgpu_encoder->encoder_id) {
1578d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1579d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1580d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1581d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
1582d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1583d38ceaf9SAlex Deucher 				dig = amdgpu_encoder->enc_priv;
1584d38ceaf9SAlex Deucher 				switch (dig->dig_encoder) {
1585d38ceaf9SAlex Deucher 				case 0:
1586d38ceaf9SAlex Deucher 					args.v3.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
1587d38ceaf9SAlex Deucher 					break;
1588d38ceaf9SAlex Deucher 				case 1:
1589d38ceaf9SAlex Deucher 					args.v3.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
1590d38ceaf9SAlex Deucher 					break;
1591d38ceaf9SAlex Deucher 				case 2:
1592d38ceaf9SAlex Deucher 					args.v3.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID;
1593d38ceaf9SAlex Deucher 					break;
1594d38ceaf9SAlex Deucher 				case 3:
1595d38ceaf9SAlex Deucher 					args.v3.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID;
1596d38ceaf9SAlex Deucher 					break;
1597d38ceaf9SAlex Deucher 				case 4:
1598d38ceaf9SAlex Deucher 					args.v3.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID;
1599d38ceaf9SAlex Deucher 					break;
1600d38ceaf9SAlex Deucher 				case 5:
1601d38ceaf9SAlex Deucher 					args.v3.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
1602d38ceaf9SAlex Deucher 					break;
1603d38ceaf9SAlex Deucher 				case 6:
1604d38ceaf9SAlex Deucher 					args.v3.ucEncoderID = ASIC_INT_DIG7_ENCODER_ID;
1605d38ceaf9SAlex Deucher 					break;
1606d38ceaf9SAlex Deucher 				}
1607d38ceaf9SAlex Deucher 				break;
1608d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1609d38ceaf9SAlex Deucher 				args.v3.ucEncoderID = ASIC_INT_DVO_ENCODER_ID;
1610d38ceaf9SAlex Deucher 				break;
1611d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1612d38ceaf9SAlex Deucher 				if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
1613d38ceaf9SAlex Deucher 					args.v3.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1614d38ceaf9SAlex Deucher 				else if (amdgpu_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
1615d38ceaf9SAlex Deucher 					args.v3.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1616d38ceaf9SAlex Deucher 				else
1617d38ceaf9SAlex Deucher 					args.v3.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
1618d38ceaf9SAlex Deucher 				break;
1619d38ceaf9SAlex Deucher 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1620d38ceaf9SAlex Deucher 				if (amdgpu_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
1621d38ceaf9SAlex Deucher 					args.v3.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1622d38ceaf9SAlex Deucher 				else if (amdgpu_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
1623d38ceaf9SAlex Deucher 					args.v3.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
1624d38ceaf9SAlex Deucher 				else
1625d38ceaf9SAlex Deucher 					args.v3.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
1626d38ceaf9SAlex Deucher 				break;
1627d38ceaf9SAlex Deucher 			}
1628d38ceaf9SAlex Deucher 			break;
1629d38ceaf9SAlex Deucher 		}
1630d38ceaf9SAlex Deucher 		break;
1631d38ceaf9SAlex Deucher 	default:
1632d38ceaf9SAlex Deucher 		DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
1633d38ceaf9SAlex Deucher 		return;
1634d38ceaf9SAlex Deucher 	}
1635d38ceaf9SAlex Deucher 
1636d38ceaf9SAlex Deucher 	amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
1637d38ceaf9SAlex Deucher }
1638d38ceaf9SAlex Deucher 
1639d38ceaf9SAlex Deucher /* This only needs to be called once at startup */
1640d38ceaf9SAlex Deucher void
amdgpu_atombios_encoder_init_dig(struct amdgpu_device * adev)1641d38ceaf9SAlex Deucher amdgpu_atombios_encoder_init_dig(struct amdgpu_device *adev)
1642d38ceaf9SAlex Deucher {
16434a580877SLuben Tuikov 	struct drm_device *dev = adev_to_drm(adev);
1644d38ceaf9SAlex Deucher 	struct drm_encoder *encoder;
1645d38ceaf9SAlex Deucher 
1646d38ceaf9SAlex Deucher 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
1647d38ceaf9SAlex Deucher 		struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
1648d38ceaf9SAlex Deucher 		struct drm_encoder *ext_encoder = amdgpu_get_external_encoder(encoder);
1649d38ceaf9SAlex Deucher 
1650d38ceaf9SAlex Deucher 		switch (amdgpu_encoder->encoder_id) {
1651d38ceaf9SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1652d38ceaf9SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1653d38ceaf9SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1654d38ceaf9SAlex Deucher 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
1655d38ceaf9SAlex Deucher 			amdgpu_atombios_encoder_setup_dig_transmitter(encoder, ATOM_TRANSMITTER_ACTION_INIT,
1656d38ceaf9SAlex Deucher 							       0, 0);
1657d38ceaf9SAlex Deucher 			break;
1658d38ceaf9SAlex Deucher 		}
1659d38ceaf9SAlex Deucher 
1660d38ceaf9SAlex Deucher 		if (ext_encoder)
1661d38ceaf9SAlex Deucher 			amdgpu_atombios_encoder_setup_external_encoder(encoder, ext_encoder,
1662d38ceaf9SAlex Deucher 								EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
1663d38ceaf9SAlex Deucher 	}
1664d38ceaf9SAlex Deucher }
1665d38ceaf9SAlex Deucher 
1666d38ceaf9SAlex Deucher static bool
amdgpu_atombios_encoder_dac_load_detect(struct drm_encoder * encoder,struct drm_connector * connector)1667d38ceaf9SAlex Deucher amdgpu_atombios_encoder_dac_load_detect(struct drm_encoder *encoder,
1668d38ceaf9SAlex Deucher 				 struct drm_connector *connector)
1669d38ceaf9SAlex Deucher {
1670d38ceaf9SAlex Deucher 	struct drm_device *dev = encoder->dev;
16711348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
1672d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
1673d38ceaf9SAlex Deucher 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
1674d38ceaf9SAlex Deucher 
1675d38ceaf9SAlex Deucher 	if (amdgpu_encoder->devices & (ATOM_DEVICE_TV_SUPPORT |
1676d38ceaf9SAlex Deucher 				       ATOM_DEVICE_CV_SUPPORT |
1677d38ceaf9SAlex Deucher 				       ATOM_DEVICE_CRT_SUPPORT)) {
1678d38ceaf9SAlex Deucher 		DAC_LOAD_DETECTION_PS_ALLOCATION args;
1679d38ceaf9SAlex Deucher 		int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection);
1680d38ceaf9SAlex Deucher 		uint8_t frev, crev;
1681d38ceaf9SAlex Deucher 
1682d38ceaf9SAlex Deucher 		memset(&args, 0, sizeof(args));
1683d38ceaf9SAlex Deucher 
1684d38ceaf9SAlex Deucher 		if (!amdgpu_atom_parse_cmd_header(adev->mode_info.atom_context, index, &frev, &crev))
1685d38ceaf9SAlex Deucher 			return false;
1686d38ceaf9SAlex Deucher 
1687d38ceaf9SAlex Deucher 		args.sDacload.ucMisc = 0;
1688d38ceaf9SAlex Deucher 
1689d38ceaf9SAlex Deucher 		if ((amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
1690d38ceaf9SAlex Deucher 		    (amdgpu_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1))
1691d38ceaf9SAlex Deucher 			args.sDacload.ucDacType = ATOM_DAC_A;
1692d38ceaf9SAlex Deucher 		else
1693d38ceaf9SAlex Deucher 			args.sDacload.ucDacType = ATOM_DAC_B;
1694d38ceaf9SAlex Deucher 
1695d38ceaf9SAlex Deucher 		if (amdgpu_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)
1696d38ceaf9SAlex Deucher 			args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT);
1697d38ceaf9SAlex Deucher 		else if (amdgpu_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)
1698d38ceaf9SAlex Deucher 			args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT);
1699d38ceaf9SAlex Deucher 		else if (amdgpu_connector->devices & ATOM_DEVICE_CV_SUPPORT) {
1700d38ceaf9SAlex Deucher 			args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT);
1701d38ceaf9SAlex Deucher 			if (crev >= 3)
1702d38ceaf9SAlex Deucher 				args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
1703d38ceaf9SAlex Deucher 		} else if (amdgpu_connector->devices & ATOM_DEVICE_TV1_SUPPORT) {
1704d38ceaf9SAlex Deucher 			args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT);
1705d38ceaf9SAlex Deucher 			if (crev >= 3)
1706d38ceaf9SAlex Deucher 				args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
1707d38ceaf9SAlex Deucher 		}
1708d38ceaf9SAlex Deucher 
1709d38ceaf9SAlex Deucher 		amdgpu_atom_execute_table(adev->mode_info.atom_context, index, (uint32_t *)&args);
1710d38ceaf9SAlex Deucher 
1711d38ceaf9SAlex Deucher 		return true;
1712d38ceaf9SAlex Deucher 	} else
1713d38ceaf9SAlex Deucher 		return false;
1714d38ceaf9SAlex Deucher }
1715d38ceaf9SAlex Deucher 
1716d38ceaf9SAlex Deucher enum drm_connector_status
amdgpu_atombios_encoder_dac_detect(struct drm_encoder * encoder,struct drm_connector * connector)1717d38ceaf9SAlex Deucher amdgpu_atombios_encoder_dac_detect(struct drm_encoder *encoder,
1718d38ceaf9SAlex Deucher 			    struct drm_connector *connector)
1719d38ceaf9SAlex Deucher {
1720d38ceaf9SAlex Deucher 	struct drm_device *dev = encoder->dev;
17211348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
1722d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
1723d38ceaf9SAlex Deucher 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
1724d38ceaf9SAlex Deucher 	uint32_t bios_0_scratch;
1725d38ceaf9SAlex Deucher 
1726d38ceaf9SAlex Deucher 	if (!amdgpu_atombios_encoder_dac_load_detect(encoder, connector)) {
1727d38ceaf9SAlex Deucher 		DRM_DEBUG_KMS("detect returned false \n");
1728d38ceaf9SAlex Deucher 		return connector_status_unknown;
1729d38ceaf9SAlex Deucher 	}
1730d38ceaf9SAlex Deucher 
1731d38ceaf9SAlex Deucher 	bios_0_scratch = RREG32(mmBIOS_SCRATCH_0);
1732d38ceaf9SAlex Deucher 
1733d38ceaf9SAlex Deucher 	DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, amdgpu_encoder->devices);
1734d38ceaf9SAlex Deucher 	if (amdgpu_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) {
1735d38ceaf9SAlex Deucher 		if (bios_0_scratch & ATOM_S0_CRT1_MASK)
1736d38ceaf9SAlex Deucher 			return connector_status_connected;
1737d38ceaf9SAlex Deucher 	}
1738d38ceaf9SAlex Deucher 	if (amdgpu_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) {
1739d38ceaf9SAlex Deucher 		if (bios_0_scratch & ATOM_S0_CRT2_MASK)
1740d38ceaf9SAlex Deucher 			return connector_status_connected;
1741d38ceaf9SAlex Deucher 	}
1742d38ceaf9SAlex Deucher 	if (amdgpu_connector->devices & ATOM_DEVICE_CV_SUPPORT) {
1743d38ceaf9SAlex Deucher 		if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A))
1744d38ceaf9SAlex Deucher 			return connector_status_connected;
1745d38ceaf9SAlex Deucher 	}
1746d38ceaf9SAlex Deucher 	if (amdgpu_connector->devices & ATOM_DEVICE_TV1_SUPPORT) {
1747d38ceaf9SAlex Deucher 		if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
1748d38ceaf9SAlex Deucher 			return connector_status_connected; /* CTV */
1749d38ceaf9SAlex Deucher 		else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
1750d38ceaf9SAlex Deucher 			return connector_status_connected; /* STV */
1751d38ceaf9SAlex Deucher 	}
1752d38ceaf9SAlex Deucher 	return connector_status_disconnected;
1753d38ceaf9SAlex Deucher }
1754d38ceaf9SAlex Deucher 
1755d38ceaf9SAlex Deucher enum drm_connector_status
amdgpu_atombios_encoder_dig_detect(struct drm_encoder * encoder,struct drm_connector * connector)1756d38ceaf9SAlex Deucher amdgpu_atombios_encoder_dig_detect(struct drm_encoder *encoder,
1757d38ceaf9SAlex Deucher 			    struct drm_connector *connector)
1758d38ceaf9SAlex Deucher {
1759d38ceaf9SAlex Deucher 	struct drm_device *dev = encoder->dev;
17601348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
1761d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
1762d38ceaf9SAlex Deucher 	struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector);
1763d38ceaf9SAlex Deucher 	struct drm_encoder *ext_encoder = amdgpu_get_external_encoder(encoder);
1764d38ceaf9SAlex Deucher 	u32 bios_0_scratch;
1765d38ceaf9SAlex Deucher 
1766d38ceaf9SAlex Deucher 	if (!ext_encoder)
1767d38ceaf9SAlex Deucher 		return connector_status_unknown;
1768d38ceaf9SAlex Deucher 
1769d38ceaf9SAlex Deucher 	if ((amdgpu_connector->devices & ATOM_DEVICE_CRT_SUPPORT) == 0)
1770d38ceaf9SAlex Deucher 		return connector_status_unknown;
1771d38ceaf9SAlex Deucher 
1772d38ceaf9SAlex Deucher 	/* load detect on the dp bridge */
1773d38ceaf9SAlex Deucher 	amdgpu_atombios_encoder_setup_external_encoder(encoder, ext_encoder,
1774d38ceaf9SAlex Deucher 						EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION);
1775d38ceaf9SAlex Deucher 
1776d38ceaf9SAlex Deucher 	bios_0_scratch = RREG32(mmBIOS_SCRATCH_0);
1777d38ceaf9SAlex Deucher 
1778d38ceaf9SAlex Deucher 	DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, amdgpu_encoder->devices);
1779d38ceaf9SAlex Deucher 	if (amdgpu_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) {
1780d38ceaf9SAlex Deucher 		if (bios_0_scratch & ATOM_S0_CRT1_MASK)
1781d38ceaf9SAlex Deucher 			return connector_status_connected;
1782d38ceaf9SAlex Deucher 	}
1783d38ceaf9SAlex Deucher 	if (amdgpu_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) {
1784d38ceaf9SAlex Deucher 		if (bios_0_scratch & ATOM_S0_CRT2_MASK)
1785d38ceaf9SAlex Deucher 			return connector_status_connected;
1786d38ceaf9SAlex Deucher 	}
1787d38ceaf9SAlex Deucher 	if (amdgpu_connector->devices & ATOM_DEVICE_CV_SUPPORT) {
1788d38ceaf9SAlex Deucher 		if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A))
1789d38ceaf9SAlex Deucher 			return connector_status_connected;
1790d38ceaf9SAlex Deucher 	}
1791d38ceaf9SAlex Deucher 	if (amdgpu_connector->devices & ATOM_DEVICE_TV1_SUPPORT) {
1792d38ceaf9SAlex Deucher 		if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
1793d38ceaf9SAlex Deucher 			return connector_status_connected; /* CTV */
1794d38ceaf9SAlex Deucher 		else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
1795d38ceaf9SAlex Deucher 			return connector_status_connected; /* STV */
1796d38ceaf9SAlex Deucher 	}
1797d38ceaf9SAlex Deucher 	return connector_status_disconnected;
1798d38ceaf9SAlex Deucher }
1799d38ceaf9SAlex Deucher 
1800d38ceaf9SAlex Deucher void
amdgpu_atombios_encoder_setup_ext_encoder_ddc(struct drm_encoder * encoder)1801d38ceaf9SAlex Deucher amdgpu_atombios_encoder_setup_ext_encoder_ddc(struct drm_encoder *encoder)
1802d38ceaf9SAlex Deucher {
1803d38ceaf9SAlex Deucher 	struct drm_encoder *ext_encoder = amdgpu_get_external_encoder(encoder);
1804d38ceaf9SAlex Deucher 
1805d38ceaf9SAlex Deucher 	if (ext_encoder)
1806d38ceaf9SAlex Deucher 		/* ddc_setup on the dp bridge */
1807d38ceaf9SAlex Deucher 		amdgpu_atombios_encoder_setup_external_encoder(encoder, ext_encoder,
1808d38ceaf9SAlex Deucher 							EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP);
1809d38ceaf9SAlex Deucher 
1810d38ceaf9SAlex Deucher }
1811d38ceaf9SAlex Deucher 
1812d38ceaf9SAlex Deucher void
amdgpu_atombios_encoder_set_bios_scratch_regs(struct drm_connector * connector,struct drm_encoder * encoder,bool connected)1813d38ceaf9SAlex Deucher amdgpu_atombios_encoder_set_bios_scratch_regs(struct drm_connector *connector,
1814d38ceaf9SAlex Deucher 				       struct drm_encoder *encoder,
1815d38ceaf9SAlex Deucher 				       bool connected)
1816d38ceaf9SAlex Deucher {
1817d38ceaf9SAlex Deucher 	struct drm_device *dev = connector->dev;
18181348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
1819d38ceaf9SAlex Deucher 	struct amdgpu_connector *amdgpu_connector =
1820d38ceaf9SAlex Deucher 	    to_amdgpu_connector(connector);
1821d38ceaf9SAlex Deucher 	struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
1822d38ceaf9SAlex Deucher 	uint32_t bios_0_scratch, bios_3_scratch, bios_6_scratch;
1823d38ceaf9SAlex Deucher 
1824d38ceaf9SAlex Deucher 	bios_0_scratch = RREG32(mmBIOS_SCRATCH_0);
1825d38ceaf9SAlex Deucher 	bios_3_scratch = RREG32(mmBIOS_SCRATCH_3);
1826d38ceaf9SAlex Deucher 	bios_6_scratch = RREG32(mmBIOS_SCRATCH_6);
1827d38ceaf9SAlex Deucher 
1828d38ceaf9SAlex Deucher 	if ((amdgpu_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) &&
1829d38ceaf9SAlex Deucher 	    (amdgpu_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) {
1830d38ceaf9SAlex Deucher 		if (connected) {
1831d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("LCD1 connected\n");
1832d38ceaf9SAlex Deucher 			bios_0_scratch |= ATOM_S0_LCD1;
1833d38ceaf9SAlex Deucher 			bios_3_scratch |= ATOM_S3_LCD1_ACTIVE;
1834d38ceaf9SAlex Deucher 			bios_6_scratch |= ATOM_S6_ACC_REQ_LCD1;
1835d38ceaf9SAlex Deucher 		} else {
1836d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("LCD1 disconnected\n");
1837d38ceaf9SAlex Deucher 			bios_0_scratch &= ~ATOM_S0_LCD1;
1838d38ceaf9SAlex Deucher 			bios_3_scratch &= ~ATOM_S3_LCD1_ACTIVE;
1839d38ceaf9SAlex Deucher 			bios_6_scratch &= ~ATOM_S6_ACC_REQ_LCD1;
1840d38ceaf9SAlex Deucher 		}
1841d38ceaf9SAlex Deucher 	}
1842d38ceaf9SAlex Deucher 	if ((amdgpu_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) &&
1843d38ceaf9SAlex Deucher 	    (amdgpu_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) {
1844d38ceaf9SAlex Deucher 		if (connected) {
1845d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("CRT1 connected\n");
1846d38ceaf9SAlex Deucher 			bios_0_scratch |= ATOM_S0_CRT1_COLOR;
1847d38ceaf9SAlex Deucher 			bios_3_scratch |= ATOM_S3_CRT1_ACTIVE;
1848d38ceaf9SAlex Deucher 			bios_6_scratch |= ATOM_S6_ACC_REQ_CRT1;
1849d38ceaf9SAlex Deucher 		} else {
1850d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("CRT1 disconnected\n");
1851d38ceaf9SAlex Deucher 			bios_0_scratch &= ~ATOM_S0_CRT1_MASK;
1852d38ceaf9SAlex Deucher 			bios_3_scratch &= ~ATOM_S3_CRT1_ACTIVE;
1853d38ceaf9SAlex Deucher 			bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT1;
1854d38ceaf9SAlex Deucher 		}
1855d38ceaf9SAlex Deucher 	}
1856d38ceaf9SAlex Deucher 	if ((amdgpu_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) &&
1857d38ceaf9SAlex Deucher 	    (amdgpu_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) {
1858d38ceaf9SAlex Deucher 		if (connected) {
1859d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("CRT2 connected\n");
1860d38ceaf9SAlex Deucher 			bios_0_scratch |= ATOM_S0_CRT2_COLOR;
1861d38ceaf9SAlex Deucher 			bios_3_scratch |= ATOM_S3_CRT2_ACTIVE;
1862d38ceaf9SAlex Deucher 			bios_6_scratch |= ATOM_S6_ACC_REQ_CRT2;
1863d38ceaf9SAlex Deucher 		} else {
1864d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("CRT2 disconnected\n");
1865d38ceaf9SAlex Deucher 			bios_0_scratch &= ~ATOM_S0_CRT2_MASK;
1866d38ceaf9SAlex Deucher 			bios_3_scratch &= ~ATOM_S3_CRT2_ACTIVE;
1867d38ceaf9SAlex Deucher 			bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT2;
1868d38ceaf9SAlex Deucher 		}
1869d38ceaf9SAlex Deucher 	}
1870d38ceaf9SAlex Deucher 	if ((amdgpu_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) &&
1871d38ceaf9SAlex Deucher 	    (amdgpu_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) {
1872d38ceaf9SAlex Deucher 		if (connected) {
1873d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("DFP1 connected\n");
1874d38ceaf9SAlex Deucher 			bios_0_scratch |= ATOM_S0_DFP1;
1875d38ceaf9SAlex Deucher 			bios_3_scratch |= ATOM_S3_DFP1_ACTIVE;
1876d38ceaf9SAlex Deucher 			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP1;
1877d38ceaf9SAlex Deucher 		} else {
1878d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("DFP1 disconnected\n");
1879d38ceaf9SAlex Deucher 			bios_0_scratch &= ~ATOM_S0_DFP1;
1880d38ceaf9SAlex Deucher 			bios_3_scratch &= ~ATOM_S3_DFP1_ACTIVE;
1881d38ceaf9SAlex Deucher 			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP1;
1882d38ceaf9SAlex Deucher 		}
1883d38ceaf9SAlex Deucher 	}
1884d38ceaf9SAlex Deucher 	if ((amdgpu_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) &&
1885d38ceaf9SAlex Deucher 	    (amdgpu_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) {
1886d38ceaf9SAlex Deucher 		if (connected) {
1887d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("DFP2 connected\n");
1888d38ceaf9SAlex Deucher 			bios_0_scratch |= ATOM_S0_DFP2;
1889d38ceaf9SAlex Deucher 			bios_3_scratch |= ATOM_S3_DFP2_ACTIVE;
1890d38ceaf9SAlex Deucher 			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP2;
1891d38ceaf9SAlex Deucher 		} else {
1892d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("DFP2 disconnected\n");
1893d38ceaf9SAlex Deucher 			bios_0_scratch &= ~ATOM_S0_DFP2;
1894d38ceaf9SAlex Deucher 			bios_3_scratch &= ~ATOM_S3_DFP2_ACTIVE;
1895d38ceaf9SAlex Deucher 			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP2;
1896d38ceaf9SAlex Deucher 		}
1897d38ceaf9SAlex Deucher 	}
1898d38ceaf9SAlex Deucher 	if ((amdgpu_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) &&
1899d38ceaf9SAlex Deucher 	    (amdgpu_connector->devices & ATOM_DEVICE_DFP3_SUPPORT)) {
1900d38ceaf9SAlex Deucher 		if (connected) {
1901d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("DFP3 connected\n");
1902d38ceaf9SAlex Deucher 			bios_0_scratch |= ATOM_S0_DFP3;
1903d38ceaf9SAlex Deucher 			bios_3_scratch |= ATOM_S3_DFP3_ACTIVE;
1904d38ceaf9SAlex Deucher 			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP3;
1905d38ceaf9SAlex Deucher 		} else {
1906d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("DFP3 disconnected\n");
1907d38ceaf9SAlex Deucher 			bios_0_scratch &= ~ATOM_S0_DFP3;
1908d38ceaf9SAlex Deucher 			bios_3_scratch &= ~ATOM_S3_DFP3_ACTIVE;
1909d38ceaf9SAlex Deucher 			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP3;
1910d38ceaf9SAlex Deucher 		}
1911d38ceaf9SAlex Deucher 	}
1912d38ceaf9SAlex Deucher 	if ((amdgpu_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) &&
1913d38ceaf9SAlex Deucher 	    (amdgpu_connector->devices & ATOM_DEVICE_DFP4_SUPPORT)) {
1914d38ceaf9SAlex Deucher 		if (connected) {
1915d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("DFP4 connected\n");
1916d38ceaf9SAlex Deucher 			bios_0_scratch |= ATOM_S0_DFP4;
1917d38ceaf9SAlex Deucher 			bios_3_scratch |= ATOM_S3_DFP4_ACTIVE;
1918d38ceaf9SAlex Deucher 			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP4;
1919d38ceaf9SAlex Deucher 		} else {
1920d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("DFP4 disconnected\n");
1921d38ceaf9SAlex Deucher 			bios_0_scratch &= ~ATOM_S0_DFP4;
1922d38ceaf9SAlex Deucher 			bios_3_scratch &= ~ATOM_S3_DFP4_ACTIVE;
1923d38ceaf9SAlex Deucher 			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP4;
1924d38ceaf9SAlex Deucher 		}
1925d38ceaf9SAlex Deucher 	}
1926d38ceaf9SAlex Deucher 	if ((amdgpu_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) &&
1927d38ceaf9SAlex Deucher 	    (amdgpu_connector->devices & ATOM_DEVICE_DFP5_SUPPORT)) {
1928d38ceaf9SAlex Deucher 		if (connected) {
1929d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("DFP5 connected\n");
1930d38ceaf9SAlex Deucher 			bios_0_scratch |= ATOM_S0_DFP5;
1931d38ceaf9SAlex Deucher 			bios_3_scratch |= ATOM_S3_DFP5_ACTIVE;
1932d38ceaf9SAlex Deucher 			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP5;
1933d38ceaf9SAlex Deucher 		} else {
1934d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("DFP5 disconnected\n");
1935d38ceaf9SAlex Deucher 			bios_0_scratch &= ~ATOM_S0_DFP5;
1936d38ceaf9SAlex Deucher 			bios_3_scratch &= ~ATOM_S3_DFP5_ACTIVE;
1937d38ceaf9SAlex Deucher 			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP5;
1938d38ceaf9SAlex Deucher 		}
1939d38ceaf9SAlex Deucher 	}
1940d38ceaf9SAlex Deucher 	if ((amdgpu_encoder->devices & ATOM_DEVICE_DFP6_SUPPORT) &&
1941d38ceaf9SAlex Deucher 	    (amdgpu_connector->devices & ATOM_DEVICE_DFP6_SUPPORT)) {
1942d38ceaf9SAlex Deucher 		if (connected) {
1943d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("DFP6 connected\n");
1944d38ceaf9SAlex Deucher 			bios_0_scratch |= ATOM_S0_DFP6;
1945d38ceaf9SAlex Deucher 			bios_3_scratch |= ATOM_S3_DFP6_ACTIVE;
1946d38ceaf9SAlex Deucher 			bios_6_scratch |= ATOM_S6_ACC_REQ_DFP6;
1947d38ceaf9SAlex Deucher 		} else {
1948d38ceaf9SAlex Deucher 			DRM_DEBUG_KMS("DFP6 disconnected\n");
1949d38ceaf9SAlex Deucher 			bios_0_scratch &= ~ATOM_S0_DFP6;
1950d38ceaf9SAlex Deucher 			bios_3_scratch &= ~ATOM_S3_DFP6_ACTIVE;
1951d38ceaf9SAlex Deucher 			bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP6;
1952d38ceaf9SAlex Deucher 		}
1953d38ceaf9SAlex Deucher 	}
1954d38ceaf9SAlex Deucher 
1955d38ceaf9SAlex Deucher 	WREG32(mmBIOS_SCRATCH_0, bios_0_scratch);
1956d38ceaf9SAlex Deucher 	WREG32(mmBIOS_SCRATCH_3, bios_3_scratch);
1957d38ceaf9SAlex Deucher 	WREG32(mmBIOS_SCRATCH_6, bios_6_scratch);
1958d38ceaf9SAlex Deucher }
1959d38ceaf9SAlex Deucher 
1960d38ceaf9SAlex Deucher union lvds_info {
1961d38ceaf9SAlex Deucher 	struct _ATOM_LVDS_INFO info;
1962d38ceaf9SAlex Deucher 	struct _ATOM_LVDS_INFO_V12 info_12;
1963d38ceaf9SAlex Deucher };
1964d38ceaf9SAlex Deucher 
1965d38ceaf9SAlex Deucher struct amdgpu_encoder_atom_dig *
amdgpu_atombios_encoder_get_lcd_info(struct amdgpu_encoder * encoder)1966d38ceaf9SAlex Deucher amdgpu_atombios_encoder_get_lcd_info(struct amdgpu_encoder *encoder)
1967d38ceaf9SAlex Deucher {
1968d38ceaf9SAlex Deucher 	struct drm_device *dev = encoder->base.dev;
19691348969aSLuben Tuikov 	struct amdgpu_device *adev = drm_to_adev(dev);
1970d38ceaf9SAlex Deucher 	struct amdgpu_mode_info *mode_info = &adev->mode_info;
1971d38ceaf9SAlex Deucher 	int index = GetIndexIntoMasterTable(DATA, LVDS_Info);
1972d38ceaf9SAlex Deucher 	uint16_t data_offset, misc;
1973d38ceaf9SAlex Deucher 	union lvds_info *lvds_info;
1974d38ceaf9SAlex Deucher 	uint8_t frev, crev;
1975d38ceaf9SAlex Deucher 	struct amdgpu_encoder_atom_dig *lvds = NULL;
1976d38ceaf9SAlex Deucher 	int encoder_enum = (encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
1977d38ceaf9SAlex Deucher 
1978d38ceaf9SAlex Deucher 	if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
1979d38ceaf9SAlex Deucher 				   &frev, &crev, &data_offset)) {
1980d38ceaf9SAlex Deucher 		lvds_info =
1981d38ceaf9SAlex Deucher 			(union lvds_info *)(mode_info->atom_context->bios + data_offset);
1982d38ceaf9SAlex Deucher 		lvds =
1983d38ceaf9SAlex Deucher 		    kzalloc(sizeof(struct amdgpu_encoder_atom_dig), GFP_KERNEL);
1984d38ceaf9SAlex Deucher 
1985d38ceaf9SAlex Deucher 		if (!lvds)
1986d38ceaf9SAlex Deucher 			return NULL;
1987d38ceaf9SAlex Deucher 
1988d38ceaf9SAlex Deucher 		lvds->native_mode.clock =
1989d38ceaf9SAlex Deucher 		    le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10;
1990d38ceaf9SAlex Deucher 		lvds->native_mode.hdisplay =
1991d38ceaf9SAlex Deucher 		    le16_to_cpu(lvds_info->info.sLCDTiming.usHActive);
1992d38ceaf9SAlex Deucher 		lvds->native_mode.vdisplay =
1993d38ceaf9SAlex Deucher 		    le16_to_cpu(lvds_info->info.sLCDTiming.usVActive);
1994d38ceaf9SAlex Deucher 		lvds->native_mode.htotal = lvds->native_mode.hdisplay +
1995d38ceaf9SAlex Deucher 			le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time);
1996d38ceaf9SAlex Deucher 		lvds->native_mode.hsync_start = lvds->native_mode.hdisplay +
1997d38ceaf9SAlex Deucher 			le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset);
1998d38ceaf9SAlex Deucher 		lvds->native_mode.hsync_end = lvds->native_mode.hsync_start +
1999d38ceaf9SAlex Deucher 			le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth);
2000d38ceaf9SAlex Deucher 		lvds->native_mode.vtotal = lvds->native_mode.vdisplay +
2001d38ceaf9SAlex Deucher 			le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time);
2002d38ceaf9SAlex Deucher 		lvds->native_mode.vsync_start = lvds->native_mode.vdisplay +
2003d38ceaf9SAlex Deucher 			le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset);
2004d38ceaf9SAlex Deucher 		lvds->native_mode.vsync_end = lvds->native_mode.vsync_start +
2005d38ceaf9SAlex Deucher 			le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth);
2006d38ceaf9SAlex Deucher 		lvds->panel_pwr_delay =
2007d38ceaf9SAlex Deucher 		    le16_to_cpu(lvds_info->info.usOffDelayInMs);
2008d38ceaf9SAlex Deucher 		lvds->lcd_misc = lvds_info->info.ucLVDS_Misc;
2009d38ceaf9SAlex Deucher 
2010d38ceaf9SAlex Deucher 		misc = le16_to_cpu(lvds_info->info.sLCDTiming.susModeMiscInfo.usAccess);
2011d38ceaf9SAlex Deucher 		if (misc & ATOM_VSYNC_POLARITY)
2012d38ceaf9SAlex Deucher 			lvds->native_mode.flags |= DRM_MODE_FLAG_NVSYNC;
2013d38ceaf9SAlex Deucher 		if (misc & ATOM_HSYNC_POLARITY)
2014d38ceaf9SAlex Deucher 			lvds->native_mode.flags |= DRM_MODE_FLAG_NHSYNC;
2015d38ceaf9SAlex Deucher 		if (misc & ATOM_COMPOSITESYNC)
2016d38ceaf9SAlex Deucher 			lvds->native_mode.flags |= DRM_MODE_FLAG_CSYNC;
2017d38ceaf9SAlex Deucher 		if (misc & ATOM_INTERLACE)
2018d38ceaf9SAlex Deucher 			lvds->native_mode.flags |= DRM_MODE_FLAG_INTERLACE;
2019d38ceaf9SAlex Deucher 		if (misc & ATOM_DOUBLE_CLOCK_MODE)
2020d38ceaf9SAlex Deucher 			lvds->native_mode.flags |= DRM_MODE_FLAG_DBLSCAN;
2021d38ceaf9SAlex Deucher 
2022d38ceaf9SAlex Deucher 		lvds->native_mode.width_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageHSize);
2023d38ceaf9SAlex Deucher 		lvds->native_mode.height_mm = le16_to_cpu(lvds_info->info.sLCDTiming.usImageVSize);
2024d38ceaf9SAlex Deucher 
2025d38ceaf9SAlex Deucher 		/* set crtc values */
2026d38ceaf9SAlex Deucher 		drm_mode_set_crtcinfo(&lvds->native_mode, CRTC_INTERLACE_HALVE_V);
2027d38ceaf9SAlex Deucher 
2028d38ceaf9SAlex Deucher 		lvds->lcd_ss_id = lvds_info->info.ucSS_Id;
2029d38ceaf9SAlex Deucher 
2030d38ceaf9SAlex Deucher 		encoder->native_mode = lvds->native_mode;
2031d38ceaf9SAlex Deucher 
2032d38ceaf9SAlex Deucher 		if (encoder_enum == 2)
2033d38ceaf9SAlex Deucher 			lvds->linkb = true;
2034d38ceaf9SAlex Deucher 		else
2035d38ceaf9SAlex Deucher 			lvds->linkb = false;
2036d38ceaf9SAlex Deucher 
2037d38ceaf9SAlex Deucher 		/* parse the lcd record table */
2038d38ceaf9SAlex Deucher 		if (le16_to_cpu(lvds_info->info.usModePatchTableOffset)) {
2039d38ceaf9SAlex Deucher 			ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record;
2040d38ceaf9SAlex Deucher 			ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record;
2041d38ceaf9SAlex Deucher 			bool bad_record = false;
2042d38ceaf9SAlex Deucher 			u8 *record;
2043d38ceaf9SAlex Deucher 
2044d38ceaf9SAlex Deucher 			if ((frev == 1) && (crev < 2))
2045d38ceaf9SAlex Deucher 				/* absolute */
2046d38ceaf9SAlex Deucher 				record = (u8 *)(mode_info->atom_context->bios +
2047d38ceaf9SAlex Deucher 						le16_to_cpu(lvds_info->info.usModePatchTableOffset));
2048d38ceaf9SAlex Deucher 			else
2049d38ceaf9SAlex Deucher 				/* relative */
2050d38ceaf9SAlex Deucher 				record = (u8 *)(mode_info->atom_context->bios +
2051d38ceaf9SAlex Deucher 						data_offset +
2052d38ceaf9SAlex Deucher 						le16_to_cpu(lvds_info->info.usModePatchTableOffset));
2053d38ceaf9SAlex Deucher 			while (*record != ATOM_RECORD_END_TYPE) {
2054d38ceaf9SAlex Deucher 				switch (*record) {
2055d38ceaf9SAlex Deucher 				case LCD_MODE_PATCH_RECORD_MODE_TYPE:
2056d38ceaf9SAlex Deucher 					record += sizeof(ATOM_PATCH_RECORD_MODE);
2057d38ceaf9SAlex Deucher 					break;
2058d38ceaf9SAlex Deucher 				case LCD_RTS_RECORD_TYPE:
2059d38ceaf9SAlex Deucher 					record += sizeof(ATOM_LCD_RTS_RECORD);
2060d38ceaf9SAlex Deucher 					break;
2061d38ceaf9SAlex Deucher 				case LCD_CAP_RECORD_TYPE:
2062d38ceaf9SAlex Deucher 					record += sizeof(ATOM_LCD_MODE_CONTROL_CAP);
2063d38ceaf9SAlex Deucher 					break;
2064d38ceaf9SAlex Deucher 				case LCD_FAKE_EDID_PATCH_RECORD_TYPE:
2065d38ceaf9SAlex Deucher 					fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record;
2066d38ceaf9SAlex Deucher 					if (fake_edid_record->ucFakeEDIDLength) {
2067d38ceaf9SAlex Deucher 						struct edid *edid;
2068*78b9e10bSAlex Deucher 						int edid_size;
2069d38ceaf9SAlex Deucher 
2070*78b9e10bSAlex Deucher 						if (fake_edid_record->ucFakeEDIDLength == 128)
2071*78b9e10bSAlex Deucher 							edid_size = fake_edid_record->ucFakeEDIDLength;
2072*78b9e10bSAlex Deucher 						else
2073*78b9e10bSAlex Deucher 							edid_size = fake_edid_record->ucFakeEDIDLength * 128;
2074*78b9e10bSAlex Deucher 						edid = kmemdup(&fake_edid_record->ucFakeEDIDString[0],
2075*78b9e10bSAlex Deucher 							       edid_size, GFP_KERNEL);
2076*78b9e10bSAlex Deucher 						if (edid) {
2077d38ceaf9SAlex Deucher 							if (drm_edid_is_valid(edid)) {
2078d38ceaf9SAlex Deucher 								adev->mode_info.bios_hardcoded_edid = edid;
2079d38ceaf9SAlex Deucher 								adev->mode_info.bios_hardcoded_edid_size = edid_size;
2080*78b9e10bSAlex Deucher 							} else {
2081d38ceaf9SAlex Deucher 								kfree(edid);
2082d38ceaf9SAlex Deucher 							}
2083d38ceaf9SAlex Deucher 						}
2084*78b9e10bSAlex Deucher 						record += struct_size(fake_edid_record,
2085320e2590SPaulo Miguel Almeida 								      ucFakeEDIDString,
2086*78b9e10bSAlex Deucher 								      edid_size);
2087*78b9e10bSAlex Deucher 					} else {
2088320e2590SPaulo Miguel Almeida 						/* empty fake edid record must be 3 bytes long */
2089*78b9e10bSAlex Deucher 						record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1;
2090*78b9e10bSAlex Deucher 					}
2091d38ceaf9SAlex Deucher 					break;
2092d38ceaf9SAlex Deucher 				case LCD_PANEL_RESOLUTION_RECORD_TYPE:
2093d38ceaf9SAlex Deucher 					panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record;
2094d38ceaf9SAlex Deucher 					lvds->native_mode.width_mm = panel_res_record->usHSize;
2095d38ceaf9SAlex Deucher 					lvds->native_mode.height_mm = panel_res_record->usVSize;
2096d38ceaf9SAlex Deucher 					record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
2097d38ceaf9SAlex Deucher 					break;
2098d38ceaf9SAlex Deucher 				default:
2099d38ceaf9SAlex Deucher 					DRM_ERROR("Bad LCD record %d\n", *record);
2100d38ceaf9SAlex Deucher 					bad_record = true;
2101d38ceaf9SAlex Deucher 					break;
2102d38ceaf9SAlex Deucher 				}
2103d38ceaf9SAlex Deucher 				if (bad_record)
2104d38ceaf9SAlex Deucher 					break;
2105d38ceaf9SAlex Deucher 			}
2106d38ceaf9SAlex Deucher 		}
2107d38ceaf9SAlex Deucher 	}
2108d38ceaf9SAlex Deucher 	return lvds;
2109d38ceaf9SAlex Deucher }
2110d38ceaf9SAlex Deucher 
2111d38ceaf9SAlex Deucher struct amdgpu_encoder_atom_dig *
amdgpu_atombios_encoder_get_dig_info(struct amdgpu_encoder * amdgpu_encoder)2112d38ceaf9SAlex Deucher amdgpu_atombios_encoder_get_dig_info(struct amdgpu_encoder *amdgpu_encoder)
2113d38ceaf9SAlex Deucher {
2114d38ceaf9SAlex Deucher 	int encoder_enum = (amdgpu_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
2115d38ceaf9SAlex Deucher 	struct amdgpu_encoder_atom_dig *dig = kzalloc(sizeof(struct amdgpu_encoder_atom_dig), GFP_KERNEL);
2116d38ceaf9SAlex Deucher 
2117d38ceaf9SAlex Deucher 	if (!dig)
2118d38ceaf9SAlex Deucher 		return NULL;
2119d38ceaf9SAlex Deucher 
2120d38ceaf9SAlex Deucher 	/* coherent mode by default */
2121d38ceaf9SAlex Deucher 	dig->coherent_mode = true;
2122d38ceaf9SAlex Deucher 	dig->dig_encoder = -1;
2123d38ceaf9SAlex Deucher 
2124d38ceaf9SAlex Deucher 	if (encoder_enum == 2)
2125d38ceaf9SAlex Deucher 		dig->linkb = true;
2126d38ceaf9SAlex Deucher 	else
2127d38ceaf9SAlex Deucher 		dig->linkb = false;
2128d38ceaf9SAlex Deucher 
2129d38ceaf9SAlex Deucher 	return dig;
2130d38ceaf9SAlex Deucher }
2131d38ceaf9SAlex Deucher 
2132