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