1/*
2 * Copyright 2006-2012, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *	  Alexander von Gluck, kallisti5@unixzen.com
7 */
8
9
10#include "encoder.h"
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <math.h>
16
17#include "accelerant.h"
18#include "accelerant_protos.h"
19#include "atombios-obsolete.h"
20#include "bios.h"
21#include "connector.h"
22#include "display.h"
23#include "displayport.h"
24#include "utility.h"
25
26
27#define TRACE_ENCODER
28#ifdef TRACE_ENCODER
29extern "C" void _sPrintf(const char* format, ...);
30#   define TRACE(x...) _sPrintf("radeon_hd: " x)
31#else
32#   define TRACE(x...) ;
33#endif
34
35#define ERROR(x...) _sPrintf("radeon_hd: " x)
36
37
38static uint32
39encoder_get_bpc()
40{
41	/*
42	switch (8) {
43		case 0:
44			return PANEL_BPC_UNDEFINE;
45		case 6:
46			return PANEL_6BIT_PER_COLOR;
47		case 8:
48			return PANEL_8BIT_PER_COLOR;
49		case 10:
50			return PANEL_10BIT_PER_COLOR;
51		case 12:
52			return PANEL_12BIT_PER_COLOR;
53		case 16:
54			return PANEL_16BIT_PER_COLOR;
55	}
56	*/
57	return PANEL_8BIT_PER_COLOR;
58}
59
60
61void
62encoder_init()
63{
64	TRACE("%s: called\n", __func__);
65	radeon_shared_info &info = *gInfo->shared_info;
66
67	for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
68		if (gConnector[id]->valid == false)
69			continue;
70
71		switch (gConnector[id]->encoder.objectID) {
72			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
73			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
74			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
75			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
76				transmitter_dig_setup(id, 0, 0, 0,
77					ATOM_TRANSMITTER_ACTION_INIT);
78				break;
79			default:
80				break;
81		}
82
83		if ((info.chipsetFlags & CHIP_APU) != 0) {
84			if (gConnector[id]->encoderExternal.valid == true) {
85				encoder_external_setup(id,
86					EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
87			}
88		}
89	}
90}
91
92
93void
94encoder_assign_crtc(uint8 crtcID)
95{
96	TRACE("%s\n", __func__);
97
98	int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
99
100	// Table version
101	uint8 tableMajor;
102	uint8 tableMinor;
103	if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor)
104		!= B_OK)
105		return;
106
107	TRACE("%s: table %" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
108		tableMajor, tableMinor);
109
110	uint16 connectorIndex = gDisplay[crtcID]->connectorIndex;
111	uint16 connectorFlags = gConnector[connectorIndex]->flags;
112	uint16 encoderID = gConnector[connectorIndex]->encoder.objectID;
113
114	// Prepare AtomBIOS command arguments
115	union crtcSourceParam {
116		SELECT_CRTC_SOURCE_PS_ALLOCATION v1;
117		SELECT_CRTC_SOURCE_PARAMETERS_V2 v2;
118		SELECT_CRTC_SOURCE_PARAMETERS_V3 v3;
119	};
120	union crtcSourceParam args;
121	memset(&args, 0, sizeof(args));
122
123	switch (tableMajor) {
124		case 1:
125			switch (tableMinor) {
126				case 1:
127				default:
128					args.v1.ucCRTC = crtcID;
129					switch (encoderID) {
130						case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
131						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
132							args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX;
133							break;
134						case ENCODER_OBJECT_ID_INTERNAL_LVDS:
135						case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
136							if ((gConnector[connectorIndex]->flags
137								& ATOM_DEVICE_LCD1_SUPPORT) != 0)
138								args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX;
139							else
140								args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX;
141							break;
142						case ENCODER_OBJECT_ID_INTERNAL_DVO1:
143						case ENCODER_OBJECT_ID_INTERNAL_DDI:
144						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
145							args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX;
146							break;
147						case ENCODER_OBJECT_ID_INTERNAL_DAC1:
148						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
149							if ((connectorFlags
150								& ATOM_DEVICE_TV_SUPPORT) != 0) {
151								args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
152							} else if ((connectorFlags
153								& ATOM_DEVICE_CV_SUPPORT) != 0) {
154								args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
155							} else
156								args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX;
157							break;
158						case ENCODER_OBJECT_ID_INTERNAL_DAC2:
159						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
160							if ((connectorFlags
161								& ATOM_DEVICE_TV_SUPPORT) != 0) {
162								args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
163							} else if ((connectorFlags
164								& ATOM_DEVICE_CV_SUPPORT) != 0) {
165								args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
166							} else
167								args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX;
168							break;
169					}
170					break;
171				case 2:
172					args.v2.ucCRTC = crtcID;
173					args.v2.ucEncodeMode
174						= display_get_encoder_mode(connectorIndex);
175					switch (encoderID) {
176						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
177						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
178						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
179						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
180							switch (encoder_pick_dig(connectorIndex)) {
181								case 0:
182									args.v2.ucEncoderID
183										= ASIC_INT_DIG1_ENCODER_ID;
184									break;
185								case 1:
186									args.v2.ucEncoderID
187										= ASIC_INT_DIG2_ENCODER_ID;
188									break;
189								case 2:
190									args.v2.ucEncoderID
191										= ASIC_INT_DIG3_ENCODER_ID;
192									break;
193								case 3:
194									args.v2.ucEncoderID
195										= ASIC_INT_DIG4_ENCODER_ID;
196									break;
197								case 4:
198									args.v2.ucEncoderID
199										= ASIC_INT_DIG5_ENCODER_ID;
200									break;
201								case 5:
202									args.v2.ucEncoderID
203										= ASIC_INT_DIG6_ENCODER_ID;
204									break;
205							}
206							break;
207						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
208							args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID;
209							break;
210						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
211							if ((connectorFlags
212								& ATOM_DEVICE_TV_SUPPORT) != 0) {
213								args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
214							} else if ((connectorFlags
215								& ATOM_DEVICE_CV_SUPPORT) != 0) {
216								args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
217							} else
218								args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
219							break;
220						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
221							if ((connectorFlags
222								& ATOM_DEVICE_TV_SUPPORT) != 0) {
223								args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
224							} else if ((connectorFlags
225								& ATOM_DEVICE_CV_SUPPORT) != 0) {
226								args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
227							} else
228								args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
229							break;
230					}
231					break;
232				case 3:
233					args.v3.ucCRTC = crtcID;
234					// TODO: Better bridge logic
235					args.v2.ucEncodeMode
236						= display_get_encoder_mode(connectorIndex);
237					args.v3.ucDstBpc = encoder_get_bpc();
238					switch (encoderID) {
239						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
240						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
241						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
242						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
243						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
244							switch (encoder_pick_dig(connectorIndex)) {
245								case 0:
246									args.v3.ucEncoderID
247										= ASIC_INT_DIG1_ENCODER_ID;
248									break;
249								case 1:
250									args.v3.ucEncoderID
251										= ASIC_INT_DIG2_ENCODER_ID;
252									break;
253								case 2:
254									args.v3.ucEncoderID
255										= ASIC_INT_DIG3_ENCODER_ID;
256									break;
257								case 3:
258									args.v3.ucEncoderID
259										= ASIC_INT_DIG4_ENCODER_ID;
260									break;
261								case 4:
262									args.v3.ucEncoderID
263										= ASIC_INT_DIG5_ENCODER_ID;
264									break;
265								case 5:
266									args.v3.ucEncoderID
267										= ASIC_INT_DIG6_ENCODER_ID;
268									break;
269								case 6:
270									args.v3.ucEncoderID
271										= ASIC_INT_DIG7_ENCODER_ID;
272									break;
273							}
274							break;
275						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
276							args.v3.ucEncoderID = ASIC_INT_DVO_ENCODER_ID;
277							break;
278						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
279							if ((connectorFlags
280								& ATOM_DEVICE_TV_SUPPORT) != 0) {
281								args.v3.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
282							} else if ((connectorFlags
283								& ATOM_DEVICE_CV_SUPPORT) != 0) {
284								args.v3.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
285							} else
286								args.v3.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
287							break;
288						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
289							if ((connectorFlags
290								& ATOM_DEVICE_TV_SUPPORT) != 0) {
291								args.v3.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
292							} else if ((connectorFlags
293								& ATOM_DEVICE_CV_SUPPORT) != 0) {
294								args.v3.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
295							} else
296								args.v3.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
297							break;
298					}
299					break;
300			}
301			break;
302		default:
303			ERROR("%s: Unknown table version: %" B_PRIu8 ".%" B_PRIu8 "\n",
304				__func__, tableMajor, tableMinor);
305			return;
306	}
307
308	atom_execute_table(gAtomContext, index, (uint32*)&args);
309
310	// update crtc encoder scratch register @ scratch 3
311	encoder_crtc_scratch(crtcID);
312}
313
314
315uint32
316encoder_pick_dig(uint32 connectorIndex)
317{
318	TRACE("%s: connector %" B_PRIu32 "\n", __func__, connectorIndex);
319	radeon_shared_info &info = *gInfo->shared_info;
320	uint32 encoderID = gConnector[connectorIndex]->encoder.objectID;
321
322	// obtain assigned CRT
323	uint32 crtcID;
324	for (crtcID = 0; crtcID < MAX_DISPLAY; crtcID++) {
325		if (gDisplay[crtcID]->attached != true)
326			continue;
327		if (gDisplay[crtcID]->connectorIndex == connectorIndex)
328			break;
329	}
330
331	bool linkB = gConnector[connectorIndex]->encoder.linkEnumeration
332		== GRAPH_OBJECT_ENUM_ID2 ? true : false;
333
334	uint32 dceVersion = (info.dceMajor * 100) + info.dceMinor;
335
336	if (dceVersion >= 400) {
337		// APU
338		switch (info.chipsetID) {
339			case RADEON_PALM:
340				return linkB ? 1 : 0;
341			case RADEON_SUMO:
342			case RADEON_SUMO2:
343				return crtcID;
344		}
345
346		switch (encoderID) {
347			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
348				return linkB ? 1 : 0;
349			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
350				return linkB ? 3 : 2;
351			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
352				return linkB ? 5 : 4;
353			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
354				return 6;
355		}
356	}
357
358	if (dceVersion >= 302)
359		return crtcID;
360
361	if (encoderID == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA)
362		return 1;
363
364	return 0;
365}
366
367
368void
369encoder_apply_quirks(uint8 crtcID)
370{
371	TRACE("%s: display %" B_PRIu8 "\n", __func__, crtcID);
372	radeon_shared_info &info = *gInfo->shared_info;
373	register_info* regs = gDisplay[crtcID]->regs;
374	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
375	uint16 connectorFlags = gConnector[connectorIndex]->flags;
376
377	// Setting the scaler clears this on some chips...
378	if (info.dceMajor >= 3
379		&& (connectorFlags & ATOM_DEVICE_TV_SUPPORT) == 0) {
380		// TODO: assume non interleave mode for now
381		// en: EVERGREEN_INTERLEAVE_EN : AVIVO_D1MODE_INTERLEAVE_EN
382		Write32(OUT, regs->modeDataFormat, 0);
383	}
384}
385
386
387void
388encoder_mode_set(uint8 crtcID)
389{
390	TRACE("%s: display %" B_PRIu8 "\n", __func__, crtcID);
391	radeon_shared_info &info = *gInfo->shared_info;
392	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
393	uint16 connectorFlags = gConnector[connectorIndex]->flags;
394	pll_info* pll = &gConnector[connectorIndex]->encoder.pll;
395
396	// TODO: Should this be the adjusted pll or the original?
397	uint32 pixelClock = pll->pixelClock;
398
399	switch (gConnector[connectorIndex]->encoder.objectID) {
400		case ENCODER_OBJECT_ID_INTERNAL_DAC1:
401		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
402		case ENCODER_OBJECT_ID_INTERNAL_DAC2:
403		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
404			encoder_analog_setup(connectorIndex, pixelClock, ATOM_ENABLE);
405			if (info.dceMajor < 5) {
406				// TV encoder was dropped in DCE 5
407				if ((connectorFlags & ATOM_DEVICE_TV_SUPPORT) != 0
408					|| (connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0) {
409					encoder_tv_setup(connectorIndex, pixelClock, ATOM_ENABLE);
410				} else {
411					encoder_tv_setup(connectorIndex, pixelClock, ATOM_DISABLE);
412				}
413			}
414			break;
415		case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
416		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
417		case ENCODER_OBJECT_ID_INTERNAL_LVDS:
418		case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
419			encoder_digital_setup(connectorIndex, pixelClock,
420				PANEL_ENCODER_ACTION_ENABLE);
421			break;
422		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
423		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
424		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
425		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
426			if ((info.chipsetFlags & CHIP_APU) != 0
427				|| info.dceMajor >= 5) {
428				// Setup DIG encoder
429				encoder_dig_setup(connectorIndex, pixelClock,
430					ATOM_ENCODER_CMD_SETUP);
431				encoder_dig_setup(connectorIndex, pixelClock,
432					ATOM_ENCODER_CMD_SETUP_PANEL_MODE);
433			} else if (info.dceMajor >= 4) {
434				// Disable DIG transmitter
435				transmitter_dig_setup(connectorIndex, pixelClock, 0, 0,
436					ATOM_TRANSMITTER_ACTION_DISABLE);
437				// Setup DIG encoder
438				encoder_dig_setup(connectorIndex, pixelClock,
439					ATOM_ENCODER_CMD_SETUP);
440				// Enable DIG transmitter
441				transmitter_dig_setup(connectorIndex, pixelClock, 0, 0,
442					ATOM_TRANSMITTER_ACTION_ENABLE);
443			} else {
444				// Disable DIG transmitter
445				transmitter_dig_setup(connectorIndex, pixelClock, 0, 0,
446					ATOM_TRANSMITTER_ACTION_DISABLE);
447				// Disable DIG encoder
448				encoder_dig_setup(connectorIndex, pixelClock, ATOM_DISABLE);
449				// Enable the DIG encoder
450				encoder_dig_setup(connectorIndex, pixelClock, ATOM_ENABLE);
451
452				// Setup and enable DIG transmitter
453				transmitter_dig_setup(connectorIndex, pixelClock, 0, 0,
454					ATOM_TRANSMITTER_ACTION_SETUP);
455				transmitter_dig_setup(connectorIndex, pixelClock, 0, 0,
456					ATOM_TRANSMITTER_ACTION_ENABLE);
457			}
458			break;
459		case ENCODER_OBJECT_ID_INTERNAL_DDI:
460		case ENCODER_OBJECT_ID_INTERNAL_DVO1:
461		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
462			TRACE("%s: TODO for DVO encoder setup\n", __func__);
463			break;
464	}
465
466	if (gConnector[connectorIndex]->encoderExternal.valid == true) {
467		if ((info.chipsetFlags & CHIP_APU) != 0) {
468			// aka DCE 4.1
469			encoder_external_setup(connectorIndex,
470				EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP);
471		} else
472			encoder_external_setup(connectorIndex, ATOM_ENABLE);
473
474	}
475
476	encoder_apply_quirks(crtcID);
477}
478
479
480status_t
481encoder_tv_setup(uint32 connectorIndex, uint32 pixelClock, int command)
482{
483	TRACE("%s: connector %" B_PRIu32 ", pixelClock: %" B_PRIu32 "\n", __func__,
484		connectorIndex, pixelClock);
485
486	uint16 connectorFlags = gConnector[connectorIndex]->flags;
487
488	TV_ENCODER_CONTROL_PS_ALLOCATION args;
489	memset(&args, 0, sizeof(args));
490
491	int index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl);
492
493	args.sTVEncoder.ucAction = command;
494
495	if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0)
496		args.sTVEncoder.ucTvStandard = ATOM_TV_CV;
497	else {
498		// TODO: we assume NTSC for now
499		args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
500	}
501
502	args.sTVEncoder.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
503
504	return atom_execute_table(gAtomContext, index, (uint32*)&args);
505}
506
507
508status_t
509encoder_digital_setup(uint32 connectorIndex, uint32 pixelClock, int command)
510{
511	TRACE("%s: connector %" B_PRIu32 ", pixelClock: %" B_PRIu32 "\n", __func__,
512		connectorIndex, pixelClock);
513
514	int index = 0;
515	uint16 connectorFlags = gConnector[connectorIndex]->flags;
516
517	switch (gConnector[connectorIndex]->encoder.objectID) {
518		case ENCODER_OBJECT_ID_INTERNAL_LVDS:
519			index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
520			break;
521		case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
522		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
523			index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl);
524			break;
525		case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
526			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
527				index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
528			else
529				index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl);
530			break;
531	}
532
533	// Table verson
534	uint8 tableMajor;
535	uint8 tableMinor;
536
537	if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor)
538		!= B_OK) {
539		ERROR("%s: cannot parse command table\n", __func__);
540		return B_ERROR;
541	}
542
543	uint32 lvdsFlags = gConnector[connectorIndex]->lvdsFlags;
544
545	bool isHdmi = false;
546	if (gConnector[connectorIndex]->type == VIDEO_CONNECTOR_HDMIA
547		|| gConnector[connectorIndex]->type == VIDEO_CONNECTOR_HDMIB) {
548		isHdmi = true;
549	}
550
551	// Prepare AtomBIOS command arguments
552	union lvdsEncoderControl {
553		LVDS_ENCODER_CONTROL_PS_ALLOCATION    v1;
554		LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2;
555	};
556	union lvdsEncoderControl args;
557	memset(&args, 0, sizeof(args));
558
559	TRACE("%s: table %" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
560		tableMajor, tableMinor);
561
562	switch (tableMajor) {
563	case 1:
564	case 2:
565		switch (tableMinor) {
566			case 1:
567				args.v1.ucMisc = 0;
568				args.v1.ucAction = command;
569				if (isHdmi)
570					args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
571				args.v1.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
572
573				if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
574					if ((lvdsFlags & ATOM_PANEL_MISC_DUAL) != 0)
575						args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
576					if ((lvdsFlags & ATOM_PANEL_MISC_888RGB) != 0)
577						args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
578				} else {
579					//if (dig->linkb)
580					//	args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
581					if (pixelClock > 165000)
582						args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
583					/*if (pScrn->rgbBits == 8) */
584					args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
585				}
586				break;
587			case 2:
588			case 3:
589				args.v2.ucMisc = 0;
590				args.v2.ucAction = command;
591				if (tableMinor == 3) {
592					//if (dig->coherent_mode)
593					//	args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT;
594				}
595				if (isHdmi)
596					args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
597				args.v2.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
598				args.v2.ucTruncate = 0;
599				args.v2.ucSpatial = 0;
600				args.v2.ucTemporal = 0;
601				args.v2.ucFRC = 0;
602				if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
603					if ((lvdsFlags & ATOM_PANEL_MISC_DUAL) != 0)
604						args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
605					if ((lvdsFlags & ATOM_PANEL_MISC_SPATIAL) != 0) {
606						args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN;
607						if ((lvdsFlags & ATOM_PANEL_MISC_888RGB) != 0) {
608							args.v2.ucSpatial
609								|= PANEL_ENCODER_SPATIAL_DITHER_DEPTH;
610						}
611					}
612
613					if ((lvdsFlags & ATOM_PANEL_MISC_TEMPORAL) != 0) {
614						args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN;
615						if ((lvdsFlags & ATOM_PANEL_MISC_888RGB) != 0) {
616							args.v2.ucTemporal
617								|= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH;
618						}
619						if (((lvdsFlags >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT)
620							& 0x3) == 2) {
621							args.v2.ucTemporal
622							|= PANEL_ENCODER_TEMPORAL_LEVEL_4;
623						}
624					}
625				} else {
626					//if (dig->linkb)
627					//	args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
628					if (pixelClock > 165000)
629						args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
630				}
631				break;
632			default:
633				ERROR("%s: Unknown minor table version: %"
634					B_PRIu8 ".%" B_PRIu8 "\n", __func__,
635					tableMajor, tableMinor);
636				return B_ERROR;
637		}
638		break;
639	default:
640		ERROR("%s: Unknown major table version: %" B_PRIu8 ".%" B_PRIu8 "\n",
641			__func__, tableMajor, tableMinor);
642		return B_ERROR;
643	}
644	return atom_execute_table(gAtomContext, index, (uint32*)&args);
645}
646
647
648status_t
649encoder_dig_setup(uint32 connectorIndex, uint32 pixelClock, int command)
650{
651	TRACE("%s\n", __func__);
652
653	radeon_shared_info &info = *gInfo->shared_info;
654	connector_info* connector = gConnector[connectorIndex];
655
656	int index = 0;
657	if (info.dceMajor >= 4)
658		index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl);
659	else {
660		if (encoder_pick_dig(connectorIndex))
661			index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
662		else
663			index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
664	}
665
666	// Table verson
667	uint8 tableMajor;
668	uint8 tableMinor;
669
670	if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor)
671		!= B_OK) {
672		ERROR("%s: cannot parse command table\n", __func__);
673		return B_ERROR;
674	}
675
676	// Prepare AtomBIOS command arguments
677	union digEncoderControl {
678		DIG_ENCODER_CONTROL_PS_ALLOCATION v1;
679		DIG_ENCODER_CONTROL_PARAMETERS_V2 v2;
680		DIG_ENCODER_CONTROL_PARAMETERS_V3 v3;
681		DIG_ENCODER_CONTROL_PARAMETERS_V4 v4;
682		DIG_ENCODER_CONTROL_PARAMETERS_V5 v5;
683	};
684	union digEncoderControl args;
685	memset(&args, 0, sizeof(args));
686
687	bool isDPBridge = connector->encoderExternal.isDPBridge;
688	bool linkB = connector->encoder.linkEnumeration
689		== GRAPH_OBJECT_ENUM_ID2 ? true : false;
690	uint32 digEncoderID = encoder_pick_dig(connectorIndex);
691
692	uint32 panelMode = 0;
693	// determine DP panel mode if doing panel mode setup
694	if (command == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) {
695		if (info.dceMajor >= 4 && isDPBridge) {
696			if (connector->encoderExternal.objectID == ENCODER_OBJECT_ID_NUTMEG)
697				panelMode = DP_PANEL_MODE_INTERNAL_DP1_MODE;
698			else if (connector->encoderExternal.objectID
699				== ENCODER_OBJECT_ID_TRAVIS) {
700				dp_info* dp = &gConnector[connectorIndex]->dpInfo;
701				uint8 id[6];
702				int bit;
703				for (bit = 0; bit < 6; bit++)
704					id[bit] = dpcd_reg_read(dp->auxPin, 0x503 + bit);
705				if (id[0] == 0x73 && id[1] == 0x69 && id[2] == 0x76
706					&& id[3] == 0x61 && id[4] == 0x72 && id[5] == 0x54) {
707					panelMode = DP_PANEL_MODE_INTERNAL_DP1_MODE;
708				} else {
709					panelMode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
710				}
711			} else {
712				panelMode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
713			}
714		} else
715			panelMode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
716	}
717
718	#if 0
719	uint32 encoderID = gConnector[connectorIndex]->encoder.objectID;
720	if (gConnector[connectorIndex]->type == VIDEO_CONNECTOR_EDP) {
721		uint8 temp = dpcd_read_reg(hwPin, DP_EDP_CONFIGURATION_CAP);
722		if ((temp & 1) != 0)
723			panelMode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
724	}
725	#endif
726
727	TRACE("%s: table %" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
728		tableMajor, tableMinor);
729
730	dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo;
731	uint32 dpClock = 0;
732	if (dpInfo->valid == true)
733		dpClock = dpInfo->linkRate;
734
735	bool dualLink = false;
736	if (connector->type == VIDEO_CONNECTOR_DVID
737		&& pixelClock > 165000) {
738		// TODO: Expand on this duallink code
739		dualLink = true;
740	}
741
742	uint32 encoderMode = display_get_encoder_mode(connectorIndex);
743
744	// Careful! The mapping of ucHPD_ID differs between atombios calls
745	uint16 hpdID = connector_pick_atom_hpdid(connectorIndex);
746
747	if (tableMajor != 1) {
748		ERROR("%s: Unknown table major!\n", __func__);
749	}
750
751	switch (tableMinor) {
752		case 1:
753			args.v1.ucAction = command;
754			args.v1.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
755
756			if (command == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
757				args.v3.ucPanelMode = panelMode;
758			else {
759				args.v1.ucEncoderMode = encoderMode;
760			}
761
762			if (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP
763				|| args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST) {
764				args.v1.ucLaneNum = dpInfo->laneCount;
765			} else if (dualLink)
766				args.v1.ucLaneNum = 8;
767			else
768				args.v1.ucLaneNum = 4;
769
770			if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP
771				|| args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST)
772				&& dpClock == 270000) {
773				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
774			}
775
776			switch (connector->encoder.objectID) {
777				case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
778					args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
779					break;
780				case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
781				case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
782					args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2;
783					break;
784				case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
785					args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3;
786					break;
787			}
788
789			if (linkB)
790				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
791			else
792				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
793			break;
794		case 2:
795		case 3:
796			args.v3.ucAction = command;
797			args.v3.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
798
799			if (command == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
800				args.v3.ucPanelMode = panelMode;
801			else
802				args.v3.ucEncoderMode = encoderMode;
803
804			if (args.v3.ucEncoderMode == ATOM_ENCODER_MODE_DP
805				|| args.v3.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST) {
806				args.v3.ucLaneNum = dpInfo->laneCount;
807			} else if (dualLink)
808				args.v3.ucLaneNum = 8;
809			else
810				args.v3.ucLaneNum = 4;
811
812			if ((args.v3.ucEncoderMode == ATOM_ENCODER_MODE_DP
813				|| args.v3.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST)
814				&& dpClock == 270000) {
815				args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
816			}
817
818			args.v3.acConfig.ucDigSel = encoder_pick_dig(connectorIndex);
819			args.v3.ucBitPerColor = encoder_get_bpc();
820			break;
821		case 4:
822			args.v4.ucAction = command;
823			args.v4.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
824
825			if (command == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
826				args.v4.ucPanelMode = panelMode;
827			else
828				args.v4.ucEncoderMode = encoderMode;
829
830			if (args.v4.ucEncoderMode == ATOM_ENCODER_MODE_DP
831				|| args.v4.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST) {
832				// Is DP?
833				args.v4.ucLaneNum = dpInfo->laneCount;
834				if (dpClock == 270000) {
835					args.v4.ucConfig
836						|= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ;
837				} else if (dpClock == 540000) {
838					args.v4.ucConfig
839						|= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ;
840				}
841			} else if (dualLink) {
842				// DualLink, double the lane numbers
843				args.v4.ucLaneNum = 8;
844			} else {
845				args.v4.ucLaneNum = 4;
846			}
847			args.v4.acConfig.ucDigSel = digEncoderID;
848			args.v4.ucBitPerColor = encoder_get_bpc();
849
850			if (hpdID == 0xff)
851				args.v4.ucHPD_ID = 0;
852			else
853				args.v4.ucHPD_ID = hpdID + 1;
854			break;
855		case 5:
856			switch(command) {
857				case ATOM_ENCODER_CMD_SETUP_PANEL_MODE:
858					args.v5.asDPPanelModeParam.ucAction = command;
859					args.v5.asDPPanelModeParam.ucPanelMode = panelMode;
860					args.v5.asDPPanelModeParam.ucDigId = digEncoderID;
861					break;
862				case ATOM_ENCODER_CMD_STREAM_SETUP:
863					args.v5.asStreamParam.ucAction = command;
864					args.v5.asStreamParam.ucDigId = digEncoderID;
865					args.v5.asStreamParam.ucDigMode = encoderMode;
866					if (encoderMode == ATOM_ENCODER_MODE_DP
867						|| encoderMode == ATOM_ENCODER_MODE_DP_MST) {
868						args.v5.asStreamParam.ucLaneNum = dpInfo->laneCount;
869					} else if (dualLink)
870						args.v5.asStreamParam.ucLaneNum = 8;
871					else
872						args.v5.asStreamParam.ucLaneNum = 4;
873					args.v5.asStreamParam.ulPixelClock
874						= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
875					args.v5.asStreamParam.ucBitPerColor = encoder_get_bpc();
876					args.v5.asStreamParam.ucLinkRateIn270Mhz = dpClock / 27000;
877					break;
878				case ATOM_ENCODER_CMD_DP_LINK_TRAINING_START:
879				case ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1:
880				case ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2:
881				case ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3:
882				case ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN4:
883				case ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE:
884				case ATOM_ENCODER_CMD_DP_VIDEO_OFF:
885				case ATOM_ENCODER_CMD_DP_VIDEO_ON:
886					args.v5.asCmdParam.ucAction = command;
887					args.v5.asCmdParam.ucDigId = digEncoderID;
888					break;
889				default:
890					ERROR("%s: Unknown command: 0x%X\n", __func__, command);
891			}
892			break;
893		default:
894			ERROR("%s: unknown tableMinor!\n", __func__);
895			return B_ERROR;
896	}
897
898	status_t result = atom_execute_table(gAtomContext, index, (uint32*)&args);
899
900	#if 0
901	if (gConnector[connectorIndex]->type == VIDEO_CONNECTOR_EDP
902		&& panelMode == DP_PANEL_MODE_INTERNAL_DP2_MODE) {
903		dpcd_write_reg(hwPin, DP_EDP_CONFIGURATION_SET, 1);
904	}
905	#endif
906
907	return result;
908}
909
910
911status_t
912encoder_external_setup(uint32 connectorIndex, int command)
913{
914	TRACE("%s: connector %" B_PRIu32 "\n", __func__, connectorIndex);
915
916	encoder_info* encoder
917		= &gConnector[connectorIndex]->encoder;
918	encoder_info* extEncoder
919		= &gConnector[connectorIndex]->encoderExternal;
920	uint32 connectorFlags = gConnector[connectorIndex]->flags;
921
922	dp_info* dpInfo
923		= &gConnector[connectorIndex]->dpInfo;
924
925	if (extEncoder->valid != true) {
926		ERROR("%s: connector %" B_PRIu32 " doesn't have a valid "
927			"external encoder!", __func__, connectorIndex);
928		return B_ERROR;
929	}
930
931	uint8 tableMajor;
932	uint8 tableMinor;
933
934	int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl);
935	if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor)
936		!= B_OK) {
937		ERROR("%s: Error parsing ExternalEncoderControl table\n", __func__);
938		return B_ERROR;
939	}
940
941	// Prepare AtomBIOS command arguments
942	union externalEncoderControl {
943		EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1;
944		EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3;
945	};
946	union externalEncoderControl args;
947	memset(&args, 0, sizeof(args));
948
949	int connectorObjectID
950		= (gConnector[connectorIndex]->objectID & OBJECT_ID_MASK)
951			>> OBJECT_ID_SHIFT;
952
953	uint32 pixelClock = encoder->pll.pixelClock;
954
955	TRACE("%s: table %" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
956		tableMajor, tableMinor);
957	switch (tableMajor) {
958		case 1:
959			// no options needed on table 1.x
960			break;
961		case 2:
962			switch (tableMinor) {
963				case 1:
964				case 2:
965					args.v1.sDigEncoder.ucAction = command;
966					args.v1.sDigEncoder.usPixelClock
967						= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
968					args.v1.sDigEncoder.ucEncoderMode
969						= display_get_encoder_mode(connectorIndex);
970
971					if (connector_is_dp(connectorIndex)) {
972						if (dpInfo->linkRate == 270000) {
973							args.v1.sDigEncoder.ucConfig
974								|= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
975						}
976						args.v1.sDigEncoder.ucLaneNum
977							= dpInfo->laneCount;
978					} else if (pixelClock > 165000) {
979						args.v1.sDigEncoder.ucLaneNum = 8;
980					} else {
981						args.v1.sDigEncoder.ucLaneNum = 4;
982					}
983					break;
984				case 3:
985				{
986					args.v3.sExtEncoder.ucAction = command;
987					if (command == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) {
988						args.v3.sExtEncoder.usConnectorId
989							= B_HOST_TO_LENDIAN_INT16(connectorObjectID);
990					} else {
991						args.v3.sExtEncoder.usPixelClock
992							= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
993					}
994
995					args.v3.sExtEncoder.ucEncoderMode
996						= display_get_encoder_mode(connectorIndex);
997
998					if (connector_is_dp(connectorIndex)) {
999						if (dpInfo->linkRate == 270000) {
1000							args.v3.sExtEncoder.ucConfig
1001								|=EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
1002						} else if (dpInfo->linkRate == 540000) {
1003							args.v3.sExtEncoder.ucConfig
1004								|=EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ;
1005						}
1006						args.v1.sDigEncoder.ucLaneNum
1007							= dpInfo->laneCount;
1008					} else if (pixelClock > 165000) {
1009						args.v3.sExtEncoder.ucLaneNum = 8;
1010					} else {
1011						args.v3.sExtEncoder.ucLaneNum = 4;
1012					}
1013
1014					switch ((connectorFlags & ENUM_ID_MASK) >> ENUM_ID_SHIFT) {
1015						case GRAPH_OBJECT_ENUM_ID1:
1016							TRACE("%s: external encoder 1\n", __func__);
1017							args.v3.sExtEncoder.ucConfig
1018								|= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1;
1019							break;
1020						case GRAPH_OBJECT_ENUM_ID2:
1021							TRACE("%s: external encoder 2\n", __func__);
1022							args.v3.sExtEncoder.ucConfig
1023								|= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2;
1024							break;
1025						case GRAPH_OBJECT_ENUM_ID3:
1026							TRACE("%s: external encoder 3\n", __func__);
1027							args.v3.sExtEncoder.ucConfig
1028								|= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3;
1029							break;
1030					}
1031
1032					// TODO: don't set statically
1033					uint32 bitsPerColor = 8;
1034					switch (bitsPerColor) {
1035						case 0:
1036							args.v3.sExtEncoder.ucBitPerColor
1037								= PANEL_BPC_UNDEFINE;
1038							break;
1039						case 6:
1040							args.v3.sExtEncoder.ucBitPerColor
1041								= PANEL_6BIT_PER_COLOR;
1042							break;
1043						case 8:
1044						default:
1045							args.v3.sExtEncoder.ucBitPerColor
1046								= PANEL_8BIT_PER_COLOR;
1047							break;
1048						case 10:
1049							args.v3.sExtEncoder.ucBitPerColor
1050								= PANEL_10BIT_PER_COLOR;
1051							break;
1052						case 12:
1053							args.v3.sExtEncoder.ucBitPerColor
1054								= PANEL_12BIT_PER_COLOR;
1055							break;
1056						case 16:
1057							args.v3.sExtEncoder.ucBitPerColor
1058								= PANEL_16BIT_PER_COLOR;
1059							break;
1060					}
1061					break;
1062				}
1063				default:
1064					ERROR("%s: Unknown table minor version: "
1065						"%" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
1066						tableMajor, tableMinor);
1067					return B_ERROR;
1068			}
1069			break;
1070		default:
1071			ERROR("%s: Unknown table major version: "
1072				"%" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
1073				tableMajor, tableMinor);
1074			return B_ERROR;
1075	}
1076
1077	return atom_execute_table(gAtomContext, index, (uint32*)&args);
1078}
1079
1080
1081status_t
1082encoder_analog_setup(uint32 connectorIndex, uint32 pixelClock, int command)
1083{
1084	TRACE("%s: connector %" B_PRIu32 ", pixelClock: %" B_PRIu32 "\n", __func__,
1085		connectorIndex, pixelClock);
1086
1087	uint32 connectorFlags = gConnector[connectorIndex]->flags;
1088
1089	int index = 0;
1090	DAC_ENCODER_CONTROL_PS_ALLOCATION args;
1091	memset(&args, 0, sizeof(args));
1092
1093	switch (gConnector[connectorIndex]->encoder.objectID) {
1094		case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1095		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1096			index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl);
1097			break;
1098		case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1099		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1100			index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl);
1101			break;
1102	}
1103
1104	args.ucAction = command;
1105
1106	if ((connectorFlags & ATOM_DEVICE_CRT_SUPPORT) != 0)
1107		args.ucDacStandard = ATOM_DAC1_PS2;
1108	else if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0)
1109		args.ucDacStandard = ATOM_DAC1_CV;
1110	else {
1111		TRACE("%s: TODO, hardcoded NTSC TV support\n", __func__);
1112		if (1) {
1113			// NTSC, NTSC_J, PAL 60
1114			args.ucDacStandard = ATOM_DAC1_NTSC;
1115		} else {
1116			// PAL, SCART. SECAM, PAL_CN
1117			args.ucDacStandard = ATOM_DAC1_PAL;
1118		}
1119	}
1120
1121	args.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1122
1123	return atom_execute_table(gAtomContext, index, (uint32*)&args);
1124}
1125
1126
1127bool
1128encoder_analog_load_detect(uint32 connectorIndex)
1129{
1130	TRACE("%s: connector %" B_PRIu32 "\n", __func__, connectorIndex);
1131
1132	if (gConnector[connectorIndex]->encoderExternal.valid == true)
1133		return encoder_dig_load_detect(connectorIndex);
1134
1135	return encoder_dac_load_detect(connectorIndex);
1136}
1137
1138
1139bool
1140encoder_dac_load_detect(uint32 connectorIndex)
1141{
1142	TRACE("%s: connector %" B_PRIu32 "\n", __func__, connectorIndex);
1143
1144	uint32 connectorFlags = gConnector[connectorIndex]->flags;
1145	uint32 encoderID = gConnector[connectorIndex]->encoder.objectID;
1146
1147	if ((connectorFlags & ATOM_DEVICE_TV_SUPPORT) == 0
1148		&& (connectorFlags & ATOM_DEVICE_CV_SUPPORT) == 0
1149		&& (connectorFlags & ATOM_DEVICE_CRT_SUPPORT) == 0) {
1150		ERROR("%s: executed on non-dac device connector #%" B_PRIu8 "\n",
1151			__func__, connectorIndex);
1152		return false;
1153	}
1154
1155	// *** tell the card we want to do a DAC detection
1156
1157	DAC_LOAD_DETECTION_PS_ALLOCATION args;
1158	int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection);
1159	uint8 tableMajor;
1160	uint8 tableMinor;
1161
1162	memset(&args, 0, sizeof(args));
1163
1164	if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor)
1165		!= B_OK) {
1166		ERROR("%s: failed getting AtomBIOS header for DAC_LoadDetection\n",
1167			__func__);
1168		return false;
1169	}
1170
1171	args.sDacload.ucMisc = 0;
1172
1173	if (encoderID == ENCODER_OBJECT_ID_INTERNAL_DAC1
1174		|| encoderID == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1) {
1175		args.sDacload.ucDacType = ATOM_DAC_A;
1176	} else {
1177		args.sDacload.ucDacType = ATOM_DAC_B;
1178	}
1179
1180	if ((connectorFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) {
1181		args.sDacload.usDeviceID
1182			= B_HOST_TO_LENDIAN_INT16(ATOM_DEVICE_CRT1_SUPPORT);
1183		atom_execute_table(gAtomContext, index, (uint32*)&args);
1184
1185		uint32 biosScratch0 = Read32(OUT, R600_SCRATCH_REG0);
1186
1187		if ((biosScratch0 & ATOM_S0_CRT1_MASK) != 0)
1188			return true;
1189
1190	} else if ((connectorFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) {
1191		args.sDacload.usDeviceID
1192			= B_HOST_TO_LENDIAN_INT16(ATOM_DEVICE_CRT2_SUPPORT);
1193		atom_execute_table(gAtomContext, index, (uint32*)&args);
1194
1195		uint32 biosScratch0 = Read32(OUT, R600_SCRATCH_REG0);
1196
1197		if ((biosScratch0 & ATOM_S0_CRT2_MASK) != 0)
1198			return true;
1199
1200	} else if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0) {
1201		args.sDacload.usDeviceID
1202			= B_HOST_TO_LENDIAN_INT16(ATOM_DEVICE_CV_SUPPORT);
1203		if (tableMinor >= 3)
1204			args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
1205		atom_execute_table(gAtomContext, index, (uint32*)&args);
1206
1207		uint32 biosScratch0 = Read32(OUT, R600_SCRATCH_REG0);
1208
1209		if ((biosScratch0 & (ATOM_S0_CV_MASK | ATOM_S0_CV_MASK_A)) != 0)
1210			return true;
1211
1212	} else if ((connectorFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
1213		args.sDacload.usDeviceID
1214			= B_HOST_TO_LENDIAN_INT16(ATOM_DEVICE_TV1_SUPPORT);
1215		if (tableMinor >= 3)
1216			args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
1217		atom_execute_table(gAtomContext, index, (uint32*)&args);
1218
1219		uint32 biosScratch0 = Read32(OUT, R600_SCRATCH_REG0);
1220
1221		if ((biosScratch0
1222			& (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) != 0) {
1223			return true; /* Composite connected */
1224		} else if ((biosScratch0
1225			& (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) != 0) {
1226			return true; /* S-Video connected */
1227		}
1228
1229	}
1230	return false;
1231}
1232
1233
1234bool
1235encoder_dig_load_detect(uint32 connectorIndex)
1236{
1237	TRACE("%s: connector %" B_PRIu32 "\n", __func__, connectorIndex);
1238	radeon_shared_info &info = *gInfo->shared_info;
1239
1240	if (info.dceMajor < 4) {
1241		ERROR("%s: Strange: External DIG encoder on DCE < 4?\n", __func__);
1242		return false;
1243	}
1244
1245	encoder_external_setup(connectorIndex,
1246		EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION);
1247
1248	uint32 biosScratch0 = Read32(OUT, R600_SCRATCH_REG0);
1249
1250	uint32 connectorFlags = gConnector[connectorIndex]->flags;
1251
1252	if ((connectorFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0)
1253		if ((biosScratch0 & ATOM_S0_CRT1_MASK) != 0)
1254			return true;
1255	if ((connectorFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0)
1256		if ((biosScratch0 & ATOM_S0_CRT2_MASK) != 0)
1257			return true;
1258	if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0)
1259		if ((biosScratch0 & (ATOM_S0_CV_MASK | ATOM_S0_CV_MASK_A)) != 0)
1260			return true;
1261	if ((connectorFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
1262		if ((biosScratch0
1263			& (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) != 0)
1264			return true; /* Composite connected */
1265		else if ((biosScratch0
1266			& (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) != 0)
1267			return true; /* S-Video connected */
1268	}
1269
1270	return false;
1271}
1272
1273
1274status_t
1275transmitter_dig_setup(uint32 connectorIndex, uint32 pixelClock,
1276	uint8 laneNumber, uint8 laneSet, int command)
1277{
1278	TRACE("%s: connector %" B_PRIu32 ", pixelClock: %" B_PRIu32 "\n", __func__,
1279		connectorIndex, pixelClock);
1280
1281	uint16 encoderID = gConnector[connectorIndex]->encoder.objectID;
1282	int index;
1283	switch (encoderID) {
1284		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1285			index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
1286			break;
1287		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1288		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1289		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1290			index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
1291			break;
1292		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1293			index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl);
1294			break;
1295		default:
1296			ERROR("%s: BUG: dig setup run on non-dig encoder!\n", __func__);
1297			return B_ERROR;
1298	}
1299
1300	if (index < 0) {
1301		ERROR("%s: GetIndexIntoMasterTable failed!\n", __func__);
1302		return B_ERROR;
1303	}
1304
1305	uint8 tableMajor;
1306	uint8 tableMinor;
1307
1308	if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor)
1309		!= B_OK)
1310		return B_ERROR;
1311
1312	// Prepare AtomBIOS arguments
1313	union digTransmitterControl {
1314		DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
1315		DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
1316		DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3;
1317		DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4;
1318		DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5 v5;
1319		DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_6 v6;
1320	};
1321	union digTransmitterControl args;
1322	memset(&args, 0, sizeof(args));
1323
1324	TRACE("%s: table %" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
1325		tableMajor, tableMinor);
1326
1327	int connectorObjectID
1328		= (gConnector[connectorIndex]->objectID & OBJECT_ID_MASK)
1329			>> OBJECT_ID_SHIFT;
1330	uint32 encoderObjectID = gConnector[connectorIndex]->encoder.objectID;
1331	uint32 digEncoderID = encoder_pick_dig(connectorIndex);
1332
1333	pll_info* pll = &gConnector[connectorIndex]->encoder.pll;
1334
1335	// Careful! The mapping of ucHPD_ID differs between atombios calls
1336	uint16 hpdID = connector_pick_atom_hpdid(connectorIndex);
1337
1338	bool isDP = connector_is_dp(connectorIndex);
1339	bool linkB = gConnector[connectorIndex]->encoder.linkEnumeration
1340		== GRAPH_OBJECT_ENUM_ID2 ? true : false;
1341
1342	dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo;
1343
1344	uint32 dpClock = 0;
1345	int dpLaneCount = 0;
1346	if (dpInfo->valid == true) {
1347		dpClock = dpInfo->linkRate;
1348		dpLaneCount = dpInfo->laneCount;
1349	}
1350
1351	switch (tableMajor) {
1352		case 1:
1353			switch (tableMinor) {
1354				case 1:
1355					args.v1.ucAction = command;
1356					if (command == ATOM_TRANSMITTER_ACTION_INIT) {
1357						args.v1.usInitInfo
1358							= B_HOST_TO_LENDIAN_INT16(connectorObjectID);
1359					} else if (command
1360						== ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1361						args.v1.asMode.ucLaneSel = laneNumber;
1362						args.v1.asMode.ucLaneSet = laneSet;
1363					} else {
1364						if (isDP) {
1365							args.v1.usPixelClock
1366								= B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1367						} else if (pixelClock > 165000) {
1368							args.v1.usPixelClock = B_HOST_TO_LENDIAN_INT16(
1369								(pixelClock / 2) / 10);
1370						} else {
1371							args.v1.usPixelClock
1372								= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1373						}
1374					}
1375
1376					args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
1377
1378					if (digEncoderID > 0) {
1379						args.v1.ucConfig
1380							|= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
1381					} else {
1382						args.v1.ucConfig
1383							|= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
1384					}
1385
1386					// TODO: IGP DIG Transmitter setup
1387					#if 0
1388					if ((rdev->flags & RADEON_IS_IGP) && (encoderObjectID
1389						== ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) {
1390						if (is_dp || (radeon_encoder->pixel_clock <= 165000)) {
1391							if (igp_lane_info & 0x1)
1392								args.v1.ucConfig
1393									|= ATOM_TRANSMITTER_CONFIG_LANE_0_3;
1394							else if (igp_lane_info & 0x2)
1395								args.v1.ucConfig
1396									|= ATOM_TRANSMITTER_CONFIG_LANE_4_7;
1397							else if (igp_lane_info & 0x4)
1398								args.v1.ucConfig
1399									|= ATOM_TRANSMITTER_CONFIG_LANE_8_11;
1400							else if (igp_lane_info & 0x8)
1401								args.v1.ucConfig
1402									|= ATOM_TRANSMITTER_CONFIG_LANE_12_15;
1403						} else {
1404							if (igp_lane_info & 0x3)
1405								args.v1.ucConfig
1406									|= ATOM_TRANSMITTER_CONFIG_LANE_0_7;
1407							else if (igp_lane_info & 0xc)
1408								args.v1.ucConfig
1409									|= ATOM_TRANSMITTER_CONFIG_LANE_8_15;
1410						}
1411					}
1412					#endif
1413
1414					if (linkB == true)
1415						args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB;
1416					else
1417						args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
1418
1419					if (isDP)
1420						args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
1421					else if ((gConnector[connectorIndex]->flags
1422						& ATOM_DEVICE_DFP_SUPPORT) != 0) {
1423						if (1) {
1424							// if coherentMode, i've only ever seen it true
1425							args.v1.ucConfig
1426								|= ATOM_TRANSMITTER_CONFIG_COHERENT;
1427						}
1428						if (pixelClock > 165000) {
1429							args.v1.ucConfig
1430								|= ATOM_TRANSMITTER_CONFIG_8LANE_LINK;
1431						}
1432					}
1433					break;
1434				case 2:
1435					args.v2.ucAction = command;
1436					if (command == ATOM_TRANSMITTER_ACTION_INIT) {
1437						args.v2.usInitInfo
1438							= B_HOST_TO_LENDIAN_INT16(connectorObjectID);
1439					} else if (command
1440						== ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1441						args.v2.asMode.ucLaneSel = laneNumber;
1442						args.v2.asMode.ucLaneSet = laneSet;
1443					} else {
1444						if (isDP) {
1445							args.v2.usPixelClock
1446								= B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1447						} else if (pixelClock > 165000) {
1448							args.v2.usPixelClock = B_HOST_TO_LENDIAN_INT16(
1449								(pixelClock / 2) / 10);
1450						} else {
1451							args.v2.usPixelClock
1452								= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1453						}
1454					}
1455					args.v2.acConfig.ucEncoderSel = digEncoderID;
1456					if (linkB)
1457						args.v2.acConfig.ucLinkSel = 1;
1458
1459					switch (encoderObjectID) {
1460						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1461							args.v2.acConfig.ucTransmitterSel = 0;
1462							break;
1463						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1464							args.v2.acConfig.ucTransmitterSel = 1;
1465							break;
1466						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1467							args.v2.acConfig.ucTransmitterSel = 2;
1468							break;
1469					}
1470
1471					if (isDP) {
1472						args.v2.acConfig.fCoherentMode = 1;
1473						args.v2.acConfig.fDPConnector = 1;
1474					} else if ((gConnector[connectorIndex]->flags
1475						& ATOM_DEVICE_DFP_SUPPORT) != 0) {
1476						if (1) {
1477							// if coherentMode, i've only ever seen it true
1478							args.v2.acConfig.fCoherentMode = 1;
1479						}
1480
1481						if (pixelClock > 165000)
1482							args.v2.acConfig.fDualLinkConnector = 1;
1483					}
1484					break;
1485				case 3:
1486					args.v3.ucAction = command;
1487					if (command == ATOM_TRANSMITTER_ACTION_INIT) {
1488						args.v3.usInitInfo
1489							= B_HOST_TO_LENDIAN_INT16(connectorObjectID);
1490					} else if (command
1491						== ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1492						args.v3.asMode.ucLaneSel = laneNumber;
1493						args.v3.asMode.ucLaneSet = laneSet;
1494					} else {
1495						if (isDP) {
1496							args.v3.usPixelClock
1497								= B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1498						} else if (pixelClock > 165000) {
1499							args.v3.usPixelClock = B_HOST_TO_LENDIAN_INT16(
1500								(pixelClock / 2) / 10);
1501						} else {
1502							args.v3.usPixelClock
1503								= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1504						}
1505					}
1506
1507					if (isDP)
1508						args.v3.ucLaneNum = dpLaneCount;
1509					else if (pixelClock > 165000)
1510						args.v3.ucLaneNum = 8;
1511					else
1512						args.v3.ucLaneNum = 4;
1513
1514					if (linkB == true)
1515						args.v3.acConfig.ucLinkSel = 1;
1516					if (digEncoderID & 1)
1517						args.v3.acConfig.ucEncoderSel = 1;
1518
1519					// Select the PLL for the PHY
1520					// DP PHY to be clocked from external src if possible
1521
1522					// DCE4 has external DCPLL clock for DP
1523					if (isDP && gInfo->dpExternalClock) {
1524						// use external clock source (id'ed to 2 on DCE4)
1525						args.v3.acConfig.ucRefClkSource = 2; // EXT clock
1526					} else
1527						args.v3.acConfig.ucRefClkSource = pll->id;
1528
1529					switch (encoderObjectID) {
1530						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1531							args.v3.acConfig.ucTransmitterSel = 0;
1532							break;
1533						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1534							args.v3.acConfig.ucTransmitterSel = 1;
1535							break;
1536						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1537							args.v3.acConfig.ucTransmitterSel = 2;
1538							break;
1539					}
1540
1541					if (isDP)
1542						args.v3.acConfig.fCoherentMode = 1;
1543					else if ((gConnector[connectorIndex]->flags
1544						& ATOM_DEVICE_DFP_SUPPORT) != 0) {
1545						if (1) {
1546							// if coherentMode, i've only ever seen it true
1547							args.v3.acConfig.fCoherentMode = 1;
1548						}
1549						if (pixelClock > 165000)
1550							args.v3.acConfig.fDualLinkConnector = 1;
1551					}
1552					break;
1553				case 4:
1554					args.v4.ucAction = command;
1555					if (command == ATOM_TRANSMITTER_ACTION_INIT) {
1556						args.v4.usInitInfo
1557							= B_HOST_TO_LENDIAN_INT16(connectorObjectID);
1558					} else if (command
1559						== ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1560						args.v4.asMode.ucLaneSel = laneNumber;
1561						args.v4.asMode.ucLaneSet = laneSet;
1562					} else {
1563						if (isDP) {
1564							args.v4.usPixelClock
1565								= B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1566						} else if (pixelClock > 165000) {
1567							args.v4.usPixelClock = B_HOST_TO_LENDIAN_INT16(
1568								(pixelClock / 2) / 10);
1569						} else {
1570							args.v4.usPixelClock
1571								= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1572						}
1573					}
1574
1575					if (isDP)
1576						args.v4.ucLaneNum = dpLaneCount;
1577					else if (pixelClock > 165000)
1578						args.v4.ucLaneNum = 8;
1579					else
1580						args.v4.ucLaneNum = 4;
1581
1582					if (linkB == true)
1583						args.v4.acConfig.ucLinkSel = 1;
1584					if (digEncoderID & 1)
1585						args.v4.acConfig.ucEncoderSel = 1;
1586
1587					// Select the PLL for the PHY
1588					// DP PHY to be clocked from external src if possible
1589					// DCE5, DCPLL usually generates the DP ref clock
1590					if (isDP) {
1591						if (gInfo->dpExternalClock > 0) {
1592							args.v4.acConfig.ucRefClkSource
1593								= ENCODER_REFCLK_SRC_EXTCLK;
1594						} else {
1595							args.v4.acConfig.ucRefClkSource
1596								= ENCODER_REFCLK_SRC_DCPLL;
1597						}
1598					} else
1599						args.v4.acConfig.ucRefClkSource = pll->id;
1600
1601					switch (encoderObjectID) {
1602						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1603							args.v4.acConfig.ucTransmitterSel = 0;
1604							break;
1605						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1606							args.v4.acConfig.ucTransmitterSel = 1;
1607							break;
1608						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1609							args.v4.acConfig.ucTransmitterSel = 2;
1610							break;
1611					}
1612
1613					if (isDP)
1614						args.v4.acConfig.fCoherentMode = 1;
1615					else if ((gConnector[connectorIndex]->flags
1616						& ATOM_DEVICE_DFP_SUPPORT) != 0) {
1617						if (1) {
1618							// if coherentMode, i've only ever seen it true
1619							args.v4.acConfig.fCoherentMode = 1;
1620						}
1621						if (pixelClock > 165000)
1622							args.v4.acConfig.fDualLinkConnector = 1;
1623					}
1624					break;
1625				case 5:
1626					args.v5.ucAction = command;
1627
1628					if (isDP) {
1629						args.v5.usSymClock
1630							= B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1631					} else {
1632						args.v5.usSymClock
1633							= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1634					}
1635					switch (encoderObjectID) {
1636						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1637							if (linkB)
1638								args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYB;
1639							else
1640								args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYA;
1641							break;
1642						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1643							if (linkB)
1644								args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYD;
1645							else
1646								args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYC;
1647							break;
1648						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1649							if (linkB)
1650								args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYF;
1651							else
1652								args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYE;
1653							break;
1654						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
1655							args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYG;
1656					}
1657					if (isDP) {
1658						args.v5.ucLaneNum = dpLaneCount;
1659					} else if (pixelClock >= 165000) {
1660						args.v5.ucLaneNum = 8;
1661					} else {
1662						args.v5.ucLaneNum = 4;
1663					}
1664
1665					args.v5.ucConnObjId = connectorObjectID;
1666
1667					if (command != ATOM_TRANSMITTER_ACTION_INIT) {
1668						// not used on INIT and display_get_encoder_mode
1669						// unavailable until displays are probed.
1670						args.v5.ucDigMode
1671							= display_get_encoder_mode(connectorIndex);
1672					}
1673
1674					if (isDP && gInfo->dpExternalClock) {
1675						args.v5.asConfig.ucPhyClkSrcId
1676							= ENCODER_REFCLK_SRC_EXTCLK;
1677					} else {
1678						args.v5.asConfig.ucPhyClkSrcId = pll->id;
1679					}
1680
1681					if (isDP) {
1682						args.v5.asConfig.ucCoherentMode = 1;
1683							// DP always coherent
1684					} else if ((gConnector[connectorIndex]->flags
1685						& ATOM_DEVICE_DFP_SUPPORT) != 0) {
1686						// TODO: dig coherent mode? VVV
1687						args.v5.asConfig.ucCoherentMode = 1;
1688					}
1689
1690					if (hpdID == 0xff)
1691						args.v5.asConfig.ucHPDSel = 0;
1692					else
1693						args.v5.asConfig.ucHPDSel = hpdID + 1;
1694
1695					args.v5.ucDigEncoderSel = 1 << digEncoderID;
1696					args.v5.ucDPLaneSet = laneSet;
1697					break;
1698				case 6:
1699					args.v6.ucAction = command;
1700					if (isDP) {
1701						args.v6.ulSymClock
1702							= B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1703					} else {
1704						args.v6.ulSymClock
1705							= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1706					}
1707					switch (encoderObjectID) {
1708						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1709							if (linkB)
1710								args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYB;
1711							else
1712								args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYA;
1713							break;
1714						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1715							if (linkB)
1716								args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYD;
1717							else
1718								args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYC;
1719							break;
1720						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1721							if (linkB)
1722								args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYF;
1723							else
1724								args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYE;
1725							break;
1726						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
1727							args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYG;
1728							break;
1729					}
1730					if (isDP)
1731						args.v6.ucLaneNum = dpLaneCount;
1732					else if (pixelClock > 165000)
1733						args.v6.ucLaneNum = 8;
1734					else
1735						args.v6.ucLaneNum = 4;
1736
1737					args.v6.ucConnObjId = connectorObjectID;
1738
1739					if (command == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH)
1740						args.v6.ucDPLaneSet = laneSet;
1741					else if (command != ATOM_TRANSMITTER_ACTION_INIT) {
1742						// not used on INIT and display_get_encoder_mode
1743						// unavailable until displays are probed.
1744						args.v6.ucDigMode
1745							= display_get_encoder_mode(connectorIndex);
1746					}
1747
1748					if (hpdID == 0xff)
1749						args.v6.ucHPDSel = 0;
1750					else
1751						args.v6.ucHPDSel = hpdID + 1;
1752
1753					args.v6.ucDigEncoderSel = 1 << digEncoderID;
1754					break;
1755				default:
1756					ERROR("%s: unknown table version\n", __func__);
1757			}
1758			break;
1759		default:
1760			ERROR("%s: unknown table version\n", __func__);
1761	}
1762
1763	return atom_execute_table(gAtomContext, index, (uint32*)&args);
1764}
1765
1766
1767void
1768encoder_crtc_scratch(uint8 crtcID)
1769{
1770	TRACE("%s: display %" B_PRIu8 "\n", __func__, crtcID);
1771
1772	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
1773	uint32 connectorFlags = gConnector[connectorIndex]->flags;
1774
1775	// TODO: r500
1776	uint32 biosScratch3 = Read32(OUT, R600_SCRATCH_REG3);
1777
1778	if ((connectorFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
1779		biosScratch3 &= ~ATOM_S3_TV1_CRTC_ACTIVE;
1780		biosScratch3 |= (crtcID << 18);
1781	}
1782	if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0) {
1783		biosScratch3 &= ~ATOM_S3_CV_CRTC_ACTIVE;
1784		biosScratch3 |= (crtcID << 24);
1785	}
1786	if ((connectorFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) {
1787		biosScratch3 &= ~ATOM_S3_CRT1_CRTC_ACTIVE;
1788		biosScratch3 |= (crtcID << 16);
1789	}
1790	if ((connectorFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) {
1791		biosScratch3 &= ~ATOM_S3_CRT2_CRTC_ACTIVE;
1792		biosScratch3 |= (crtcID << 20);
1793	}
1794	if ((connectorFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) {
1795		biosScratch3 &= ~ATOM_S3_LCD1_CRTC_ACTIVE;
1796		biosScratch3 |= (crtcID << 17);
1797	}
1798	if ((connectorFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) {
1799		biosScratch3 &= ~ATOM_S3_DFP1_CRTC_ACTIVE;
1800		biosScratch3 |= (crtcID << 19);
1801	}
1802	if ((connectorFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) {
1803		biosScratch3 &= ~ATOM_S3_DFP2_CRTC_ACTIVE;
1804		biosScratch3 |= (crtcID << 23);
1805	}
1806	if ((connectorFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) {
1807		biosScratch3 &= ~ATOM_S3_DFP3_CRTC_ACTIVE;
1808		biosScratch3 |= (crtcID << 25);
1809	}
1810
1811	// TODO: r500
1812	Write32(OUT, R600_SCRATCH_REG3, biosScratch3);
1813}
1814
1815
1816void
1817encoder_dpms_scratch(uint8 crtcID, bool power)
1818{
1819	TRACE("%s: display %" B_PRIu8 "\n", __func__, crtcID);
1820
1821	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
1822	uint32 connectorFlags = gConnector[connectorIndex]->flags;
1823
1824	// TODO: r500
1825	uint32 biosScratch2 = Read32(OUT, R600_SCRATCH_REG2);
1826
1827	if ((connectorFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
1828		if (power == true)
1829			biosScratch2 &= ~ATOM_S2_TV1_DPMS_STATE;
1830		else
1831			biosScratch2 |= ATOM_S2_TV1_DPMS_STATE;
1832	}
1833	if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0) {
1834		if (power == true)
1835			biosScratch2 &= ~ATOM_S2_CV_DPMS_STATE;
1836		else
1837			biosScratch2 |= ATOM_S2_CV_DPMS_STATE;
1838	}
1839	if ((connectorFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) {
1840		if (power == true)
1841			biosScratch2 &= ~ATOM_S2_CRT1_DPMS_STATE;
1842		else
1843			biosScratch2 |= ATOM_S2_CRT1_DPMS_STATE;
1844	}
1845	if ((connectorFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) {
1846		if (power == true)
1847			biosScratch2 &= ~ATOM_S2_CRT2_DPMS_STATE;
1848		else
1849			biosScratch2 |= ATOM_S2_CRT2_DPMS_STATE;
1850	}
1851	if ((connectorFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) {
1852		if (power == true)
1853			biosScratch2 &= ~ATOM_S2_LCD1_DPMS_STATE;
1854		else
1855			biosScratch2 |= ATOM_S2_LCD1_DPMS_STATE;
1856	}
1857	if ((connectorFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) {
1858		if (power == true)
1859			biosScratch2 &= ~ATOM_S2_DFP1_DPMS_STATE;
1860		else
1861			biosScratch2 |= ATOM_S2_DFP1_DPMS_STATE;
1862	}
1863	if ((connectorFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) {
1864		if (power == true)
1865			biosScratch2 &= ~ATOM_S2_DFP2_DPMS_STATE;
1866		else
1867			biosScratch2 |= ATOM_S2_DFP2_DPMS_STATE;
1868	}
1869	if ((connectorFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) {
1870		if (power == true)
1871			biosScratch2 &= ~ATOM_S2_DFP3_DPMS_STATE;
1872		else
1873			biosScratch2 |= ATOM_S2_DFP3_DPMS_STATE;
1874	}
1875	if ((connectorFlags & ATOM_DEVICE_DFP4_SUPPORT) != 0) {
1876		if (power == true)
1877			biosScratch2 &= ~ATOM_S2_DFP4_DPMS_STATE;
1878		else
1879			biosScratch2 |= ATOM_S2_DFP4_DPMS_STATE;
1880	}
1881	if ((connectorFlags & ATOM_DEVICE_DFP5_SUPPORT) != 0) {
1882		if (power == true)
1883			biosScratch2 &= ~ATOM_S2_DFP5_DPMS_STATE;
1884		else
1885			biosScratch2 |= ATOM_S2_DFP5_DPMS_STATE;
1886	}
1887	Write32(OUT, R600_SCRATCH_REG2, biosScratch2);
1888}
1889
1890
1891void
1892encoder_dpms_set(uint8 crtcID, int mode)
1893{
1894	TRACE("%s: display %" B_PRIu8 ", power: %s\n", __func__, crtcID,
1895		mode == B_DPMS_ON ? "true" : "false");
1896
1897	int index = -1;
1898	radeon_shared_info &info = *gInfo->shared_info;
1899
1900	DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
1901	memset(&args, 0, sizeof(args));
1902
1903	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
1904	uint32 connectorFlags = gConnector[connectorIndex]->flags;
1905	uint16 encoderID = gConnector[connectorIndex]->encoder.objectID;
1906
1907	switch (encoderID) {
1908		case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1909		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1910			index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl);
1911			break;
1912		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1913		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1914		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1915		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1916			encoder_dpms_set_dig(crtcID, mode);
1917			break;
1918		case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1919		case ENCODER_OBJECT_ID_INTERNAL_DDI:
1920			index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
1921			break;
1922		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1923			if (info.dceMajor >= 5)
1924				encoder_dpms_set_dvo(crtcID, mode);
1925			else if (info.dceMajor >= 3)
1926				encoder_dpms_set_dig(crtcID, mode);
1927			else
1928				index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
1929			break;
1930		case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1931			index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
1932			break;
1933		case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1934			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
1935				index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
1936			else
1937				index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl);
1938			break;
1939		case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1940		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1941			if ((connectorFlags & ATOM_DEVICE_TV_SUPPORT) != 0)
1942				index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
1943			else if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0)
1944				index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
1945			else
1946				index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
1947			break;
1948		case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1949		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1950			if ((connectorFlags & ATOM_DEVICE_TV_SUPPORT) != 0)
1951				index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
1952			else if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0)
1953				index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
1954			else
1955				index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
1956			break;
1957		// default, none on purpose
1958	}
1959
1960	// If we have an index, we need to execute a table.
1961	if (index >= 0) {
1962		switch (mode) {
1963			case B_DPMS_ON:
1964				args.ucAction = ATOM_ENABLE;
1965				break;
1966			case B_DPMS_STAND_BY:
1967			case B_DPMS_SUSPEND:
1968			case B_DPMS_OFF:
1969				args.ucAction = ATOM_DISABLE;
1970				break;
1971		}
1972
1973		atom_execute_table(gAtomContext, index, (uint32*)&args);
1974		if (info.dceMajor < 5) {
1975			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
1976				args.ucAction = args.ucAction == ATOM_DISABLE
1977					? ATOM_LCD_BLOFF : ATOM_LCD_BLON;
1978				atom_execute_table(gAtomContext, index, (uint32*)&args);
1979			}
1980		}
1981		if (info.dceMajor < 4)
1982			encoder_dpms_scratch(crtcID, true);
1983	}
1984}
1985
1986
1987void
1988encoder_dpms_set_dig(uint8 crtcID, int mode)
1989{
1990	TRACE("%s: display %" B_PRIu8 ", power: %s\n", __func__, crtcID,
1991		mode == B_DPMS_ON ? "true" : "false");
1992
1993	radeon_shared_info &info = *gInfo->shared_info;
1994	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
1995	connector_info* connector = gConnector[connectorIndex];
1996	uint32 connectorFlags = connector->flags;
1997	pll_info* pll = &connector->encoder.pll;
1998	bool hasExternal = connector->encoderExternal.valid;
1999	bool travisQuirk = info.dceMajor < 5
2000		&& (connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0
2001		&& connector->encoderExternal.objectID == ENCODER_OBJECT_ID_TRAVIS;
2002
2003	switch (mode) {
2004		case B_DPMS_ON:
2005			if ((info.dceMajor == 4 && info.dceMinor == 1)
2006				|| info.dceMajor >= 5) {
2007				// Setup encoder
2008				encoder_dig_setup(connectorIndex, pll->pixelClock,
2009					ATOM_ENCODER_CMD_SETUP);
2010				encoder_dig_setup(connectorIndex, pll->pixelClock,
2011					ATOM_ENCODER_CMD_SETUP_PANEL_MODE);
2012			} else if (info.dceMajor >= 4) {
2013				// Setup encoder
2014				encoder_dig_setup(connectorIndex, pll->pixelClock,
2015					ATOM_ENCODER_CMD_SETUP);
2016			} else {
2017				// Setup encoder and transmitter
2018				encoder_dig_setup(connectorIndex, pll->pixelClock, ATOM_ENABLE);
2019				transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
2020					ATOM_TRANSMITTER_ACTION_SETUP);
2021			}
2022
2023			if (connector->type == VIDEO_CONNECTOR_EDP) {
2024				// TODO: If VIDEO_CONNECTOR_EDP, ATOM_TRANSMITTER_ACTION_POWER_ON
2025				ERROR("%s: TODO, edp_panel_power!\n",
2026					__func__);
2027			}
2028
2029			// Enable transmitter
2030			transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
2031				ATOM_TRANSMITTER_ACTION_ENABLE);
2032
2033			if (connector_is_dp(connectorIndex)) {
2034				if (info.dceMajor >= 4) {
2035					encoder_dig_setup(connectorIndex, pll->pixelClock,
2036						ATOM_ENCODER_CMD_DP_VIDEO_OFF);
2037				}
2038				// dp link train
2039				dp_link_train(crtcID);
2040				if (info.dceMajor >= 4) {
2041					encoder_dig_setup(connectorIndex, pll->pixelClock,
2042						ATOM_ENCODER_CMD_DP_VIDEO_ON);
2043				}
2044				// not sure what AtomBIOS table/command sets this
2045				// register, but it's required to get the video output
2046				Write32(OUT, AVIVO_DP_VID_STREAM_CNTL, 0x201);
2047			}
2048			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
2049				transmitter_dig_setup(connectorIndex, pll->pixelClock,
2050					0, 0, ATOM_TRANSMITTER_ACTION_LCD_BLON);
2051			}
2052			if (hasExternal)
2053				encoder_external_setup(connectorIndex, ATOM_ENABLE);
2054			break;
2055		case B_DPMS_STAND_BY:
2056		case B_DPMS_SUSPEND:
2057		case B_DPMS_OFF:
2058			if (connector_is_dp(connectorIndex)) {
2059				if (info.dceMajor >= 4) {
2060					encoder_dig_setup(connectorIndex, pll->pixelClock,
2061						ATOM_ENCODER_CMD_DP_VIDEO_OFF);
2062				}
2063			}
2064			if (hasExternal)
2065				encoder_external_setup(connectorIndex, ATOM_DISABLE);
2066			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
2067				transmitter_dig_setup(connectorIndex, pll->pixelClock,
2068					0, 0, ATOM_TRANSMITTER_ACTION_LCD_BLOFF);
2069			}
2070			if (connector_is_dp(connectorIndex) && !travisQuirk) {
2071				// If not TRAVIS on < DCE 5, set_rx_power_state D3
2072				ERROR("%s: TODO: dpms off set_rx_power_state D3\n", __func__);
2073			}
2074			if (info.dceMajor >= 4) {
2075				// Disable transmitter
2076				transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
2077					ATOM_TRANSMITTER_ACTION_DISABLE);
2078			} else {
2079				// Disable transmitter and encoder
2080				transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
2081					ATOM_TRANSMITTER_ACTION_DISABLE);
2082				encoder_dig_setup(connectorIndex, pll->pixelClock, ATOM_DISABLE);
2083			}
2084
2085			if (connector_is_dp(connectorIndex)) {
2086				if (travisQuirk) {
2087					ERROR("%s: TODO: dpms off set_rx_power_state D3\n",
2088						__func__);
2089				}
2090				if (connector->type == VIDEO_CONNECTOR_EDP) {
2091					// TODO: ATOM_TRANSMITTER_ACTION_POWER_OFF
2092					ERROR("%s: TODO, edp_panel_power!\n", __func__);
2093				}
2094			}
2095			break;
2096	}
2097}
2098
2099
2100void
2101encoder_dpms_set_dvo(uint8 crtcID, int mode)
2102{
2103	ERROR("%s: TODO, dvo encoder dpms stub\n", __func__);
2104}
2105
2106
2107void
2108encoder_output_lock(bool lock)
2109{
2110	TRACE("%s: %s\n", __func__, lock ? "true" : "false");
2111	uint32 biosScratch6 = Read32(OUT, R600_SCRATCH_REG6);
2112
2113	if (lock) {
2114		biosScratch6 |= ATOM_S6_CRITICAL_STATE;
2115		biosScratch6 &= ~ATOM_S6_ACC_MODE;
2116	} else {
2117		biosScratch6 &= ~ATOM_S6_CRITICAL_STATE;
2118		biosScratch6 |= ATOM_S6_ACC_MODE;
2119	}
2120
2121	Write32(OUT, R600_SCRATCH_REG6, biosScratch6);
2122}
2123
2124static const char* encoder_name_matrix[] = {
2125	"NONE",
2126	"Internal Radeon LVDS",
2127	"Internal Radeon TMDS1",
2128	"Internal Radeon TMDS2",
2129	"Internal Radeon DAC1",
2130	"Internal Radeon DAC2 (TV)",
2131	"Internal Radeon SDVOA",
2132	"Internal Radeon SDVOB",
2133	"External 3rd party SI170B",
2134	"External 3rd party CH7303",
2135	"External 3rd party CH7301",
2136	"Internal Radeon DVO1",
2137	"External 3rd party SDVOA",
2138	"External 3rd party SDVOB",
2139	"External 3rd party TITFP513",
2140	"Internal LVTM1",
2141	"External 3rd party VT1623",
2142	"External HDMI SI1930",
2143	"Internal HDMI",
2144	"Internal Kaleidoscope TMDS1",
2145	"Internal Kaleidoscope DVO1",
2146	"Internal Kaleidoscope DAC1",
2147	"Internal Kaleidoscope DAC2",
2148	"External Kaleidoscope SI178",
2149	"MVPU FPGA",
2150	"Internal Kaleidoscope DDI",
2151	"External Kaleidoscope VT1625",
2152	"External Kaleidoscope HDMI SI1932",
2153	"External Kaleidoscope DP AN9801",
2154	"External Kaleidoscope DP DP501",
2155	"Internal Kaleidoscope UNIPHY",
2156	"Internal Kaleidoscope LVTMA",
2157	"Internal Kaleidoscope UNIPHY1",
2158	"Internal Kaleidoscope UNIPHY2",
2159	"External Nutmeg Bridge",
2160	"External Travis Bridge",
2161	"Internal Kaleidoscope VCE"
2162};
2163
2164
2165const char*
2166encoder_name_lookup(uint32 encoderID) {
2167	if (encoderID < B_COUNT_OF(encoder_name_matrix))
2168		return encoder_name_matrix[encoderID];
2169	else
2170		return "Unknown";
2171}
2172
2173
2174uint32
2175encoder_object_lookup(uint32 connectorFlags, uint8 dacID)
2176{
2177	// used on older cards to take a guess at the encoder
2178	// object
2179
2180	radeon_shared_info &info = *gInfo->shared_info;
2181
2182	uint32 ret = 0;
2183
2184	switch (connectorFlags) {
2185		case ATOM_DEVICE_CRT1_SUPPORT:
2186		case ATOM_DEVICE_TV1_SUPPORT:
2187		case ATOM_DEVICE_TV2_SUPPORT:
2188		case ATOM_DEVICE_CRT2_SUPPORT:
2189		case ATOM_DEVICE_CV_SUPPORT:
2190			switch (dacID) {
2191				case 1:
2192					if ((info.chipsetID == RADEON_RS400)
2193						|| (info.chipsetID == RADEON_RS480))
2194						ret = ENCODER_INTERNAL_DAC2_ENUM_ID1;
2195					else if (info.chipsetID >= RADEON_RS600)
2196						ret = ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1;
2197					else
2198						ret = ENCODER_INTERNAL_DAC1_ENUM_ID1;
2199					break;
2200				case 2:
2201					if (info.chipsetID >= RADEON_RS600)
2202						ret = ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1;
2203					else {
2204						ret = ENCODER_INTERNAL_DAC2_ENUM_ID1;
2205					}
2206					break;
2207				case 3: // external dac
2208					if (info.chipsetID >= RADEON_RS600)
2209						ret = ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1;
2210					else
2211						ret = ENCODER_INTERNAL_DVO1_ENUM_ID1;
2212					break;
2213			}
2214			break;
2215		case ATOM_DEVICE_LCD1_SUPPORT:
2216			if (info.chipsetID >= RADEON_RS600)
2217				ret = ENCODER_INTERNAL_LVTM1_ENUM_ID1;
2218			else
2219				ret = ENCODER_INTERNAL_LVDS_ENUM_ID1;
2220			break;
2221		case ATOM_DEVICE_DFP1_SUPPORT:
2222			if ((info.chipsetID == RADEON_RS400)
2223				|| (info.chipsetID == RADEON_RS480))
2224				ret = ENCODER_INTERNAL_DVO1_ENUM_ID1;
2225			else if (info.chipsetID >= RADEON_RS600)
2226				ret = ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1;
2227			else
2228				ret = ENCODER_INTERNAL_TMDS1_ENUM_ID1;
2229			break;
2230		case ATOM_DEVICE_LCD2_SUPPORT:
2231		case ATOM_DEVICE_DFP2_SUPPORT:
2232			if ((info.chipsetID == RADEON_RS600)
2233				|| (info.chipsetID == RADEON_RS690)
2234				|| (info.chipsetID == RADEON_RS740))
2235				ret = ENCODER_INTERNAL_DDI_ENUM_ID1;
2236			else if (info.chipsetID >= RADEON_RS600)
2237				ret = ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1;
2238			else
2239				ret = ENCODER_INTERNAL_DVO1_ENUM_ID1;
2240			break;
2241		case ATOM_DEVICE_DFP3_SUPPORT:
2242			ret = ENCODER_INTERNAL_LVTM1_ENUM_ID1;
2243			break;
2244	}
2245
2246	return ret;
2247}
2248
2249
2250uint32
2251encoder_type_lookup(uint32 encoderID, uint32 connectorFlags)
2252{
2253	switch (encoderID) {
2254		case ENCODER_OBJECT_ID_INTERNAL_LVDS:
2255		case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
2256		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
2257		case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
2258			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
2259				return VIDEO_ENCODER_LVDS;
2260			else
2261				return VIDEO_ENCODER_TMDS;
2262			break;
2263		case ENCODER_OBJECT_ID_INTERNAL_DAC1:
2264			return VIDEO_ENCODER_DAC;
2265		case ENCODER_OBJECT_ID_INTERNAL_DAC2:
2266		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
2267		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
2268			return VIDEO_ENCODER_TVDAC;
2269		case ENCODER_OBJECT_ID_INTERNAL_DVO1:
2270		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
2271		case ENCODER_OBJECT_ID_INTERNAL_DDI:
2272		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
2273		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
2274		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
2275		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
2276			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
2277				return VIDEO_ENCODER_LVDS;
2278			else if ((connectorFlags & ATOM_DEVICE_CRT_SUPPORT) != 0)
2279				return VIDEO_ENCODER_DAC;
2280			else
2281				return VIDEO_ENCODER_TMDS;
2282			break;
2283		case ENCODER_OBJECT_ID_SI170B:
2284		case ENCODER_OBJECT_ID_CH7303:
2285		case ENCODER_OBJECT_ID_EXTERNAL_SDVOA:
2286		case ENCODER_OBJECT_ID_EXTERNAL_SDVOB:
2287		case ENCODER_OBJECT_ID_TITFP513:
2288		case ENCODER_OBJECT_ID_VT1623:
2289		case ENCODER_OBJECT_ID_HDMI_SI1930:
2290		case ENCODER_OBJECT_ID_TRAVIS:
2291		case ENCODER_OBJECT_ID_NUTMEG:
2292			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
2293				return VIDEO_ENCODER_LVDS;
2294			else if ((connectorFlags & ATOM_DEVICE_CRT_SUPPORT) != 0)
2295				return VIDEO_ENCODER_DAC;
2296			else
2297				return VIDEO_ENCODER_TMDS;
2298			break;
2299	}
2300
2301	return VIDEO_ENCODER_NONE;
2302}
2303
2304
2305bool
2306encoder_is_external(uint32 encoderID)
2307{
2308	switch (encoderID) {
2309		case ENCODER_OBJECT_ID_SI170B:
2310		case ENCODER_OBJECT_ID_CH7303:
2311		case ENCODER_OBJECT_ID_EXTERNAL_SDVOA:
2312		case ENCODER_OBJECT_ID_EXTERNAL_SDVOB:
2313		case ENCODER_OBJECT_ID_TITFP513:
2314		case ENCODER_OBJECT_ID_VT1623:
2315		case ENCODER_OBJECT_ID_HDMI_SI1930:
2316		case ENCODER_OBJECT_ID_TRAVIS:
2317		case ENCODER_OBJECT_ID_NUTMEG:
2318			return true;
2319	}
2320
2321	return false;
2322}
2323
2324
2325bool
2326encoder_is_dp_bridge(uint32 encoderID)
2327{
2328	switch (encoderID) {
2329		case ENCODER_OBJECT_ID_TRAVIS:
2330		case ENCODER_OBJECT_ID_NUTMEG:
2331			return true;
2332	}
2333	return false;
2334}
2335