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