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