xref: /haiku/src/add-ons/accelerants/radeon_hd/encoder.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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 	// Careful! The mapping of ucHPD_ID differs between atombios calls
1265 	uint16 hpdID = connector_pick_atom_hpdid(connectorIndex);
1266 
1267 	bool isDP = connector_is_dp(connectorIndex);
1268 	bool linkB = gConnector[connectorIndex]->encoder.linkEnumeration
1269 		== GRAPH_OBJECT_ENUM_ID2 ? true : false;
1270 
1271 	dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo;
1272 
1273 	uint32 dpClock = 0;
1274 	int dpLaneCount = 0;
1275 	if (dpInfo->valid == true) {
1276 		dpClock = dpInfo->linkRate;
1277 		dpLaneCount = dpInfo->laneCount;
1278 	}
1279 
1280 	switch (tableMajor) {
1281 		case 1:
1282 			switch (tableMinor) {
1283 				case 1:
1284 					args.v1.ucAction = command;
1285 					if (command == ATOM_TRANSMITTER_ACTION_INIT) {
1286 						args.v1.usInitInfo
1287 							= B_HOST_TO_LENDIAN_INT16(connectorObjectID);
1288 					} else if (command
1289 						== ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1290 						args.v1.asMode.ucLaneSel = laneNumber;
1291 						args.v1.asMode.ucLaneSet = laneSet;
1292 					} else {
1293 						if (isDP) {
1294 							args.v1.usPixelClock
1295 								= B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1296 						} else if (pixelClock > 165000) {
1297 							args.v1.usPixelClock = B_HOST_TO_LENDIAN_INT16(
1298 								(pixelClock / 2) / 10);
1299 						} else {
1300 							args.v1.usPixelClock
1301 								= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1302 						}
1303 					}
1304 
1305 					args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
1306 
1307 					if (digEncoderID > 0) {
1308 						args.v1.ucConfig
1309 							|= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
1310 					} else {
1311 						args.v1.ucConfig
1312 							|= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
1313 					}
1314 
1315 					// TODO: IGP DIG Transmitter setup
1316 					#if 0
1317 					if ((rdev->flags & RADEON_IS_IGP) && (encoderObjectID
1318 						== ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) {
1319 						if (is_dp || (radeon_encoder->pixel_clock <= 165000)) {
1320 							if (igp_lane_info & 0x1)
1321 								args.v1.ucConfig
1322 									|= ATOM_TRANSMITTER_CONFIG_LANE_0_3;
1323 							else if (igp_lane_info & 0x2)
1324 								args.v1.ucConfig
1325 									|= ATOM_TRANSMITTER_CONFIG_LANE_4_7;
1326 							else if (igp_lane_info & 0x4)
1327 								args.v1.ucConfig
1328 									|= ATOM_TRANSMITTER_CONFIG_LANE_8_11;
1329 							else if (igp_lane_info & 0x8)
1330 								args.v1.ucConfig
1331 									|= ATOM_TRANSMITTER_CONFIG_LANE_12_15;
1332 						} else {
1333 							if (igp_lane_info & 0x3)
1334 								args.v1.ucConfig
1335 									|= ATOM_TRANSMITTER_CONFIG_LANE_0_7;
1336 							else if (igp_lane_info & 0xc)
1337 								args.v1.ucConfig
1338 									|= ATOM_TRANSMITTER_CONFIG_LANE_8_15;
1339 						}
1340 					}
1341 					#endif
1342 
1343 					if (linkB == true)
1344 						args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB;
1345 					else
1346 						args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
1347 
1348 					if (isDP)
1349 						args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
1350 					else if ((gConnector[connectorIndex]->flags
1351 						& ATOM_DEVICE_DFP_SUPPORT) != 0) {
1352 						if (1) {
1353 							// if coherentMode, i've only ever seen it true
1354 							args.v1.ucConfig
1355 								|= ATOM_TRANSMITTER_CONFIG_COHERENT;
1356 						}
1357 						if (pixelClock > 165000) {
1358 							args.v1.ucConfig
1359 								|= ATOM_TRANSMITTER_CONFIG_8LANE_LINK;
1360 						}
1361 					}
1362 					break;
1363 				case 2:
1364 					args.v2.ucAction = command;
1365 					if (command == ATOM_TRANSMITTER_ACTION_INIT) {
1366 						args.v2.usInitInfo
1367 							= B_HOST_TO_LENDIAN_INT16(connectorObjectID);
1368 					} else if (command
1369 						== ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1370 						args.v2.asMode.ucLaneSel = laneNumber;
1371 						args.v2.asMode.ucLaneSet = laneSet;
1372 					} else {
1373 						if (isDP) {
1374 							args.v2.usPixelClock
1375 								= B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1376 						} else if (pixelClock > 165000) {
1377 							args.v2.usPixelClock = B_HOST_TO_LENDIAN_INT16(
1378 								(pixelClock / 2) / 10);
1379 						} else {
1380 							args.v2.usPixelClock
1381 								= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1382 						}
1383 					}
1384 					args.v2.acConfig.ucEncoderSel = digEncoderID;
1385 					if (linkB)
1386 						args.v2.acConfig.ucLinkSel = 1;
1387 
1388 					switch (encoderObjectID) {
1389 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1390 							args.v2.acConfig.ucTransmitterSel = 0;
1391 							break;
1392 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1393 							args.v2.acConfig.ucTransmitterSel = 1;
1394 							break;
1395 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1396 							args.v2.acConfig.ucTransmitterSel = 2;
1397 							break;
1398 					}
1399 
1400 					if (isDP) {
1401 						args.v2.acConfig.fCoherentMode = 1;
1402 						args.v2.acConfig.fDPConnector = 1;
1403 					} else if ((gConnector[connectorIndex]->flags
1404 						& ATOM_DEVICE_DFP_SUPPORT) != 0) {
1405 						if (1) {
1406 							// if coherentMode, i've only ever seen it true
1407 							args.v2.acConfig.fCoherentMode = 1;
1408 						}
1409 
1410 						if (pixelClock > 165000)
1411 							args.v2.acConfig.fDualLinkConnector = 1;
1412 					}
1413 					break;
1414 				case 3:
1415 					args.v3.ucAction = command;
1416 					if (command == ATOM_TRANSMITTER_ACTION_INIT) {
1417 						args.v3.usInitInfo
1418 							= B_HOST_TO_LENDIAN_INT16(connectorObjectID);
1419 					} else if (command
1420 						== ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1421 						args.v3.asMode.ucLaneSel = laneNumber;
1422 						args.v3.asMode.ucLaneSet = laneSet;
1423 					} else {
1424 						if (isDP) {
1425 							args.v3.usPixelClock
1426 								= B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1427 						} else if (pixelClock > 165000) {
1428 							args.v3.usPixelClock = B_HOST_TO_LENDIAN_INT16(
1429 								(pixelClock / 2) / 10);
1430 						} else {
1431 							args.v3.usPixelClock
1432 								= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1433 						}
1434 					}
1435 
1436 					if (isDP)
1437 						args.v3.ucLaneNum = dpLaneCount;
1438 					else if (pixelClock > 165000)
1439 						args.v3.ucLaneNum = 8;
1440 					else
1441 						args.v3.ucLaneNum = 4;
1442 
1443 					if (linkB == true)
1444 						args.v3.acConfig.ucLinkSel = 1;
1445 					if (digEncoderID & 1)
1446 						args.v3.acConfig.ucEncoderSel = 1;
1447 
1448 					// Select the PLL for the PHY
1449 					// DP PHY to be clocked from external src if possible
1450 
1451 					// DCE4 has external DCPLL clock for DP
1452 					if (isDP && gInfo->dpExternalClock) {
1453 						// use external clock source (id'ed to 2 on DCE4)
1454 						args.v3.acConfig.ucRefClkSource = 2; // EXT clock
1455 					} else
1456 						args.v3.acConfig.ucRefClkSource = pll->id;
1457 
1458 					switch (encoderObjectID) {
1459 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1460 							args.v3.acConfig.ucTransmitterSel = 0;
1461 							break;
1462 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1463 							args.v3.acConfig.ucTransmitterSel = 1;
1464 							break;
1465 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1466 							args.v3.acConfig.ucTransmitterSel = 2;
1467 							break;
1468 					}
1469 
1470 					if (isDP)
1471 						args.v3.acConfig.fCoherentMode = 1;
1472 					else if ((gConnector[connectorIndex]->flags
1473 						& ATOM_DEVICE_DFP_SUPPORT) != 0) {
1474 						if (1) {
1475 							// if coherentMode, i've only ever seen it true
1476 							args.v3.acConfig.fCoherentMode = 1;
1477 						}
1478 						if (pixelClock > 165000)
1479 							args.v3.acConfig.fDualLinkConnector = 1;
1480 					}
1481 					break;
1482 				case 4:
1483 					args.v4.ucAction = command;
1484 					if (command == ATOM_TRANSMITTER_ACTION_INIT) {
1485 						args.v4.usInitInfo
1486 							= B_HOST_TO_LENDIAN_INT16(connectorObjectID);
1487 					} else if (command
1488 						== ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1489 						args.v4.asMode.ucLaneSel = laneNumber;
1490 						args.v4.asMode.ucLaneSet = laneSet;
1491 					} else {
1492 						if (isDP) {
1493 							args.v4.usPixelClock
1494 								= B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1495 						} else if (pixelClock > 165000) {
1496 							args.v4.usPixelClock = B_HOST_TO_LENDIAN_INT16(
1497 								(pixelClock / 2) / 10);
1498 						} else {
1499 							args.v4.usPixelClock
1500 								= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1501 						}
1502 					}
1503 
1504 					if (isDP)
1505 						args.v4.ucLaneNum = dpLaneCount;
1506 					else if (pixelClock > 165000)
1507 						args.v4.ucLaneNum = 8;
1508 					else
1509 						args.v4.ucLaneNum = 4;
1510 
1511 					if (linkB == true)
1512 						args.v4.acConfig.ucLinkSel = 1;
1513 					if (digEncoderID & 1)
1514 						args.v4.acConfig.ucEncoderSel = 1;
1515 
1516 					// Select the PLL for the PHY
1517 					// DP PHY to be clocked from external src if possible
1518 					// DCE5, DCPLL usually generates the DP ref clock
1519 					if (isDP) {
1520 						if (gInfo->dpExternalClock > 0) {
1521 							args.v4.acConfig.ucRefClkSource
1522 								= ENCODER_REFCLK_SRC_EXTCLK;
1523 						} else {
1524 							args.v4.acConfig.ucRefClkSource
1525 								= ENCODER_REFCLK_SRC_DCPLL;
1526 						}
1527 					} else
1528 						args.v4.acConfig.ucRefClkSource = pll->id;
1529 
1530 					switch (encoderObjectID) {
1531 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1532 							args.v4.acConfig.ucTransmitterSel = 0;
1533 							break;
1534 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1535 							args.v4.acConfig.ucTransmitterSel = 1;
1536 							break;
1537 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1538 							args.v4.acConfig.ucTransmitterSel = 2;
1539 							break;
1540 					}
1541 
1542 					if (isDP)
1543 						args.v4.acConfig.fCoherentMode = 1;
1544 					else if ((gConnector[connectorIndex]->flags
1545 						& ATOM_DEVICE_DFP_SUPPORT) != 0) {
1546 						if (1) {
1547 							// if coherentMode, i've only ever seen it true
1548 							args.v4.acConfig.fCoherentMode = 1;
1549 						}
1550 						if (pixelClock > 165000)
1551 							args.v4.acConfig.fDualLinkConnector = 1;
1552 					}
1553 					break;
1554 				case 5:
1555 					args.v5.ucAction = command;
1556 
1557 					if (isDP) {
1558 						args.v5.usSymClock
1559 							= B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1560 					} else {
1561 						args.v5.usSymClock
1562 							= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1563 					}
1564 					switch (encoderObjectID) {
1565 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1566 							if (linkB)
1567 								args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYB;
1568 							else
1569 								args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYA;
1570 							break;
1571 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1572 							if (linkB)
1573 								args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYD;
1574 							else
1575 								args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYC;
1576 							break;
1577 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1578 							if (linkB)
1579 								args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYF;
1580 							else
1581 								args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYE;
1582 							break;
1583 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
1584 							args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYG;
1585 					}
1586 					if (isDP) {
1587 						args.v5.ucLaneNum = dpLaneCount;
1588 					} else if (pixelClock >= 165000) {
1589 						args.v5.ucLaneNum = 8;
1590 					} else {
1591 						args.v5.ucLaneNum = 4;
1592 					}
1593 
1594 					args.v5.ucConnObjId = connectorObjectID;
1595 
1596 					if (command != ATOM_TRANSMITTER_ACTION_INIT) {
1597 						// not used on INIT and display_get_encoder_mode
1598 						// unavailable until displays are probed.
1599 						args.v5.ucDigMode
1600 							= display_get_encoder_mode(connectorIndex);
1601 					}
1602 
1603 					if (isDP && gInfo->dpExternalClock) {
1604 						args.v5.asConfig.ucPhyClkSrcId
1605 							= ENCODER_REFCLK_SRC_EXTCLK;
1606 					} else {
1607 						args.v5.asConfig.ucPhyClkSrcId = pll->id;
1608 					}
1609 
1610 					if (isDP) {
1611 						args.v5.asConfig.ucCoherentMode = 1;
1612 							// DP always coherent
1613 					} else if ((gConnector[connectorIndex]->flags
1614 						& ATOM_DEVICE_DFP_SUPPORT) != 0) {
1615 						// TODO: dig coherent mode? VVV
1616 						args.v5.asConfig.ucCoherentMode = 1;
1617 					}
1618 
1619 					if (hpdID == 0xff)
1620 						args.v5.asConfig.ucHPDSel = 0;
1621 					else
1622 						args.v5.asConfig.ucHPDSel = hpdID + 1;
1623 
1624 					args.v5.ucDigEncoderSel = 1 << digEncoderID;
1625 					args.v5.ucDPLaneSet = laneSet;
1626 					break;
1627 				case 6:
1628 					args.v6.ucAction = command;
1629 					if (isDP) {
1630 						args.v6.ulSymClock
1631 							= B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1632 					} else {
1633 						args.v6.ulSymClock
1634 							= B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1635 					}
1636 					switch (encoderObjectID) {
1637 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1638 							if (linkB)
1639 								args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYB;
1640 							else
1641 								args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYA;
1642 							break;
1643 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1644 							if (linkB)
1645 								args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYD;
1646 							else
1647 								args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYC;
1648 							break;
1649 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1650 							if (linkB)
1651 								args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYF;
1652 							else
1653 								args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYE;
1654 							break;
1655 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
1656 							args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYG;
1657 							break;
1658 					}
1659 					if (isDP)
1660 						args.v6.ucLaneNum = dpLaneCount;
1661 					else if (pixelClock > 165000)
1662 						args.v6.ucLaneNum = 8;
1663 					else
1664 						args.v6.ucLaneNum = 4;
1665 
1666 					args.v6.ucConnObjId = connectorObjectID;
1667 
1668 					if (command == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH)
1669 						args.v6.ucDPLaneSet = laneSet;
1670 					else if (command != ATOM_TRANSMITTER_ACTION_INIT) {
1671 						// not used on INIT and display_get_encoder_mode
1672 						// unavailable until displays are probed.
1673 						args.v6.ucDigMode
1674 							= display_get_encoder_mode(connectorIndex);
1675 					}
1676 
1677 					if (hpdID == 0xff)
1678 						args.v6.ucHPDSel = 0;
1679 					else
1680 						args.v6.ucHPDSel = hpdID + 1;
1681 
1682 					args.v6.ucDigEncoderSel = 1 << digEncoderID;
1683 					break;
1684 				default:
1685 					ERROR("%s: unknown table version\n", __func__);
1686 			}
1687 			break;
1688 		default:
1689 			ERROR("%s: unknown table version\n", __func__);
1690 	}
1691 
1692 	return atom_execute_table(gAtomContext, index, (uint32*)&args);
1693 }
1694 
1695 
1696 void
1697 encoder_crtc_scratch(uint8 crtcID)
1698 {
1699 	TRACE("%s: display %" B_PRIu8 "\n", __func__, crtcID);
1700 
1701 	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
1702 	uint32 connectorFlags = gConnector[connectorIndex]->flags;
1703 
1704 	// TODO: r500
1705 	uint32 biosScratch3 = Read32(OUT, R600_SCRATCH_REG3);
1706 
1707 	if ((connectorFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
1708 		biosScratch3 &= ~ATOM_S3_TV1_CRTC_ACTIVE;
1709 		biosScratch3 |= (crtcID << 18);
1710 	}
1711 	if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0) {
1712 		biosScratch3 &= ~ATOM_S3_CV_CRTC_ACTIVE;
1713 		biosScratch3 |= (crtcID << 24);
1714 	}
1715 	if ((connectorFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) {
1716 		biosScratch3 &= ~ATOM_S3_CRT1_CRTC_ACTIVE;
1717 		biosScratch3 |= (crtcID << 16);
1718 	}
1719 	if ((connectorFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) {
1720 		biosScratch3 &= ~ATOM_S3_CRT2_CRTC_ACTIVE;
1721 		biosScratch3 |= (crtcID << 20);
1722 	}
1723 	if ((connectorFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) {
1724 		biosScratch3 &= ~ATOM_S3_LCD1_CRTC_ACTIVE;
1725 		biosScratch3 |= (crtcID << 17);
1726 	}
1727 	if ((connectorFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) {
1728 		biosScratch3 &= ~ATOM_S3_DFP1_CRTC_ACTIVE;
1729 		biosScratch3 |= (crtcID << 19);
1730 	}
1731 	if ((connectorFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) {
1732 		biosScratch3 &= ~ATOM_S3_DFP2_CRTC_ACTIVE;
1733 		biosScratch3 |= (crtcID << 23);
1734 	}
1735 	if ((connectorFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) {
1736 		biosScratch3 &= ~ATOM_S3_DFP3_CRTC_ACTIVE;
1737 		biosScratch3 |= (crtcID << 25);
1738 	}
1739 
1740 	// TODO: r500
1741 	Write32(OUT, R600_SCRATCH_REG3, biosScratch3);
1742 }
1743 
1744 
1745 void
1746 encoder_dpms_scratch(uint8 crtcID, bool power)
1747 {
1748 	TRACE("%s: display %" B_PRIu8 "\n", __func__, crtcID);
1749 
1750 	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
1751 	uint32 connectorFlags = gConnector[connectorIndex]->flags;
1752 
1753 	// TODO: r500
1754 	uint32 biosScratch2 = Read32(OUT, R600_SCRATCH_REG2);
1755 
1756 	if ((connectorFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
1757 		if (power == true)
1758 			biosScratch2 &= ~ATOM_S2_TV1_DPMS_STATE;
1759 		else
1760 			biosScratch2 |= ATOM_S2_TV1_DPMS_STATE;
1761 	}
1762 	if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0) {
1763 		if (power == true)
1764 			biosScratch2 &= ~ATOM_S2_CV_DPMS_STATE;
1765 		else
1766 			biosScratch2 |= ATOM_S2_CV_DPMS_STATE;
1767 	}
1768 	if ((connectorFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) {
1769 		if (power == true)
1770 			biosScratch2 &= ~ATOM_S2_CRT1_DPMS_STATE;
1771 		else
1772 			biosScratch2 |= ATOM_S2_CRT1_DPMS_STATE;
1773 	}
1774 	if ((connectorFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) {
1775 		if (power == true)
1776 			biosScratch2 &= ~ATOM_S2_CRT2_DPMS_STATE;
1777 		else
1778 			biosScratch2 |= ATOM_S2_CRT2_DPMS_STATE;
1779 	}
1780 	if ((connectorFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) {
1781 		if (power == true)
1782 			biosScratch2 &= ~ATOM_S2_LCD1_DPMS_STATE;
1783 		else
1784 			biosScratch2 |= ATOM_S2_LCD1_DPMS_STATE;
1785 	}
1786 	if ((connectorFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) {
1787 		if (power == true)
1788 			biosScratch2 &= ~ATOM_S2_DFP1_DPMS_STATE;
1789 		else
1790 			biosScratch2 |= ATOM_S2_DFP1_DPMS_STATE;
1791 	}
1792 	if ((connectorFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) {
1793 		if (power == true)
1794 			biosScratch2 &= ~ATOM_S2_DFP2_DPMS_STATE;
1795 		else
1796 			biosScratch2 |= ATOM_S2_DFP2_DPMS_STATE;
1797 	}
1798 	if ((connectorFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) {
1799 		if (power == true)
1800 			biosScratch2 &= ~ATOM_S2_DFP3_DPMS_STATE;
1801 		else
1802 			biosScratch2 |= ATOM_S2_DFP3_DPMS_STATE;
1803 	}
1804 	if ((connectorFlags & ATOM_DEVICE_DFP4_SUPPORT) != 0) {
1805 		if (power == true)
1806 			biosScratch2 &= ~ATOM_S2_DFP4_DPMS_STATE;
1807 		else
1808 			biosScratch2 |= ATOM_S2_DFP4_DPMS_STATE;
1809 	}
1810 	if ((connectorFlags & ATOM_DEVICE_DFP5_SUPPORT) != 0) {
1811 		if (power == true)
1812 			biosScratch2 &= ~ATOM_S2_DFP5_DPMS_STATE;
1813 		else
1814 			biosScratch2 |= ATOM_S2_DFP5_DPMS_STATE;
1815 	}
1816 	Write32(OUT, R600_SCRATCH_REG2, biosScratch2);
1817 }
1818 
1819 
1820 void
1821 encoder_dpms_set(uint8 crtcID, int mode)
1822 {
1823 	TRACE("%s: display %" B_PRIu8 ", power: %s\n", __func__, crtcID,
1824 		mode == B_DPMS_ON ? "true" : "false");
1825 
1826 	int index = -1;
1827 	radeon_shared_info &info = *gInfo->shared_info;
1828 
1829 	DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
1830 	memset(&args, 0, sizeof(args));
1831 
1832 	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
1833 	uint32 connectorFlags = gConnector[connectorIndex]->flags;
1834 	uint16 encoderID = gConnector[connectorIndex]->encoder.objectID;
1835 
1836 	switch (encoderID) {
1837 		case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1838 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1839 			index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl);
1840 			break;
1841 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1842 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1843 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1844 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1845 			encoder_dpms_set_dig(crtcID, mode);
1846 			break;
1847 		case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1848 		case ENCODER_OBJECT_ID_INTERNAL_DDI:
1849 			index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
1850 			break;
1851 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1852 			if (info.dceMajor >= 5)
1853 				encoder_dpms_set_dvo(crtcID, mode);
1854 			else if (info.dceMajor >= 3)
1855 				encoder_dpms_set_dig(crtcID, mode);
1856 			else
1857 				index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
1858 			break;
1859 		case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1860 			index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
1861 			break;
1862 		case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1863 			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
1864 				index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
1865 			else
1866 				index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl);
1867 			break;
1868 		case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1869 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1870 			if ((connectorFlags & ATOM_DEVICE_TV_SUPPORT) != 0)
1871 				index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
1872 			else if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0)
1873 				index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
1874 			else
1875 				index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
1876 			break;
1877 		case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1878 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1879 			if ((connectorFlags & ATOM_DEVICE_TV_SUPPORT) != 0)
1880 				index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
1881 			else if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0)
1882 				index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
1883 			else
1884 				index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
1885 			break;
1886 		// default, none on purpose
1887 	}
1888 
1889 	// If we have an index, we need to execute a table.
1890 	if (index >= 0) {
1891 		switch (mode) {
1892 			case B_DPMS_ON:
1893 				args.ucAction = ATOM_ENABLE;
1894 				break;
1895 			case B_DPMS_STAND_BY:
1896 			case B_DPMS_SUSPEND:
1897 			case B_DPMS_OFF:
1898 				args.ucAction = ATOM_DISABLE;
1899 				break;
1900 		}
1901 
1902 		atom_execute_table(gAtomContext, index, (uint32*)&args);
1903 		if (info.dceMajor < 5) {
1904 			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
1905 				args.ucAction = args.ucAction == ATOM_DISABLE
1906 					? ATOM_LCD_BLOFF : ATOM_LCD_BLON;
1907 				atom_execute_table(gAtomContext, index, (uint32*)&args);
1908 			}
1909 		}
1910 		if (info.dceMajor < 4)
1911 			encoder_dpms_scratch(crtcID, true);
1912 	}
1913 }
1914 
1915 
1916 void
1917 encoder_dpms_set_dig(uint8 crtcID, int mode)
1918 {
1919 	TRACE("%s: display %" B_PRIu8 ", power: %s\n", __func__, crtcID,
1920 		mode == B_DPMS_ON ? "true" : "false");
1921 
1922 	radeon_shared_info &info = *gInfo->shared_info;
1923 	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
1924 	connector_info* connector = gConnector[connectorIndex];
1925 	uint32 connectorFlags = connector->flags;
1926 	pll_info* pll = &connector->encoder.pll;
1927 	bool hasExternal = connector->encoderExternal.valid;
1928 	bool travisQuirk = info.dceMajor < 5
1929 		&& (connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0
1930 		&& connector->encoderExternal.objectID == ENCODER_OBJECT_ID_TRAVIS;
1931 
1932 	switch (mode) {
1933 		case B_DPMS_ON:
1934 			if ((info.dceMajor == 4 && info.dceMinor == 1)
1935 				|| info.dceMajor >= 5) {
1936 				// Setup encoder
1937 				encoder_dig_setup(connectorIndex, pll->pixelClock,
1938 					ATOM_ENCODER_CMD_SETUP);
1939 				encoder_dig_setup(connectorIndex, pll->pixelClock,
1940 					ATOM_ENCODER_CMD_SETUP_PANEL_MODE);
1941 			} else if (info.dceMajor >= 4) {
1942 				// Setup encoder
1943 				encoder_dig_setup(connectorIndex, pll->pixelClock,
1944 					ATOM_ENCODER_CMD_SETUP);
1945 			} else {
1946 				// Setup encoder and transmitter
1947 				encoder_dig_setup(connectorIndex, pll->pixelClock, ATOM_ENABLE);
1948 				transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
1949 					ATOM_TRANSMITTER_ACTION_SETUP);
1950 			}
1951 
1952 			if (connector->type == VIDEO_CONNECTOR_EDP) {
1953 				// TODO: If VIDEO_CONNECTOR_EDP, ATOM_TRANSMITTER_ACTION_POWER_ON
1954 				ERROR("%s: TODO, edp_panel_power!\n",
1955 					__func__);
1956 			}
1957 
1958 			// Enable transmitter
1959 			transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
1960 				ATOM_TRANSMITTER_ACTION_ENABLE);
1961 
1962 			if (connector_is_dp(connectorIndex)) {
1963 				if (info.dceMajor >= 4) {
1964 					encoder_dig_setup(connectorIndex, pll->pixelClock,
1965 						ATOM_ENCODER_CMD_DP_VIDEO_OFF);
1966 				}
1967 				// dp link train
1968 				dp_link_train(crtcID);
1969 				if (info.dceMajor >= 4) {
1970 					encoder_dig_setup(connectorIndex, pll->pixelClock,
1971 						ATOM_ENCODER_CMD_DP_VIDEO_ON);
1972 				}
1973 				// not sure what AtomBIOS table/command sets this
1974 				// register, but it's required to get the video output
1975 				Write32(OUT, AVIVO_DP_VID_STREAM_CNTL, 0x201);
1976 			}
1977 			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
1978 				transmitter_dig_setup(connectorIndex, pll->pixelClock,
1979 					0, 0, ATOM_TRANSMITTER_ACTION_LCD_BLON);
1980 			}
1981 			if (hasExternal)
1982 				encoder_external_setup(connectorIndex, ATOM_ENABLE);
1983 			break;
1984 		case B_DPMS_STAND_BY:
1985 		case B_DPMS_SUSPEND:
1986 		case B_DPMS_OFF:
1987 			if (connector_is_dp(connectorIndex)) {
1988 				if (info.dceMajor >= 4) {
1989 					encoder_dig_setup(connectorIndex, pll->pixelClock,
1990 						ATOM_ENCODER_CMD_DP_VIDEO_OFF);
1991 				}
1992 			}
1993 			if (hasExternal)
1994 				encoder_external_setup(connectorIndex, ATOM_DISABLE);
1995 			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
1996 				transmitter_dig_setup(connectorIndex, pll->pixelClock,
1997 					0, 0, ATOM_TRANSMITTER_ACTION_LCD_BLOFF);
1998 			}
1999 			if (connector_is_dp(connectorIndex) && !travisQuirk) {
2000 				// If not TRAVIS on < DCE 5, set_rx_power_state D3
2001 				ERROR("%s: TODO: dpms off set_rx_power_state D3\n", __func__);
2002 			}
2003 			if (info.dceMajor >= 4) {
2004 				// Disable transmitter
2005 				transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
2006 					ATOM_TRANSMITTER_ACTION_DISABLE);
2007 			} else {
2008 				// Disable transmitter and encoder
2009 				transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
2010 					ATOM_TRANSMITTER_ACTION_DISABLE);
2011 				encoder_dig_setup(connectorIndex, pll->pixelClock, ATOM_DISABLE);
2012 			}
2013 
2014 			if (connector_is_dp(connectorIndex)) {
2015 				if (travisQuirk) {
2016 					ERROR("%s: TODO: dpms off set_rx_power_state D3\n",
2017 						__func__);
2018 				}
2019 				if (connector->type == VIDEO_CONNECTOR_EDP) {
2020 					// TODO: ATOM_TRANSMITTER_ACTION_POWER_OFF
2021 					ERROR("%s: TODO, edp_panel_power!\n", __func__);
2022 				}
2023 			}
2024 			break;
2025 	}
2026 }
2027 
2028 
2029 void
2030 encoder_dpms_set_dvo(uint8 crtcID, int mode)
2031 {
2032 	ERROR("%s: TODO, dvo encoder dpms stub\n", __func__);
2033 }
2034 
2035 
2036 void
2037 encoder_output_lock(bool lock)
2038 {
2039 	TRACE("%s: %s\n", __func__, lock ? "true" : "false");
2040 	uint32 biosScratch6 = Read32(OUT, R600_SCRATCH_REG6);
2041 
2042 	if (lock) {
2043 		biosScratch6 |= ATOM_S6_CRITICAL_STATE;
2044 		biosScratch6 &= ~ATOM_S6_ACC_MODE;
2045 	} else {
2046 		biosScratch6 &= ~ATOM_S6_CRITICAL_STATE;
2047 		biosScratch6 |= ATOM_S6_ACC_MODE;
2048 	}
2049 
2050 	Write32(OUT, R600_SCRATCH_REG6, biosScratch6);
2051 }
2052 
2053 static const char* encoder_name_matrix[] = {
2054 	"NONE",
2055 	"Internal Radeon LVDS",
2056 	"Internal Radeon TMDS1",
2057 	"Internal Radeon TMDS2",
2058 	"Internal Radeon DAC1",
2059 	"Internal Radeon DAC2 (TV)",
2060 	"Internal Radeon SDVOA",
2061 	"Internal Radeon SDVOB",
2062 	"External 3rd party SI170B",
2063 	"External 3rd party CH7303",
2064 	"External 3rd party CH7301",
2065 	"Internal Radeon DVO1",
2066 	"External 3rd party SDVOA",
2067 	"External 3rd party SDVOB",
2068 	"External 3rd party TITFP513",
2069 	"Internal LVTM1",
2070 	"External 3rd party VT1623",
2071 	"External HDMI SI1930",
2072 	"Internal HDMI",
2073 	"Internal Kaleidoscope TMDS1",
2074 	"Internal Kaleidoscope DVO1",
2075 	"Internal Kaleidoscope DAC1",
2076 	"Internal Kaleidoscope DAC2",
2077 	"External Kaleidoscope SI178",
2078 	"MVPU FPGA",
2079 	"Internal Kaleidoscope DDI",
2080 	"External Kaleidoscope VT1625",
2081 	"External Kaleidoscope HDMI SI1932",
2082 	"External Kaleidoscope DP AN9801",
2083 	"External Kaleidoscope DP DP501",
2084 	"Internal Kaleidoscope UNIPHY",
2085 	"Internal Kaleidoscope LVTMA",
2086 	"Internal Kaleidoscope UNIPHY1",
2087 	"Internal Kaleidoscope UNIPHY2",
2088 	"External Nutmeg Bridge",
2089 	"External Travis Bridge",
2090 	"Internal Kaleidoscope VCE"
2091 };
2092 
2093 
2094 const char*
2095 encoder_name_lookup(uint32 encoderID) {
2096 	if (encoderID < B_COUNT_OF(encoder_name_matrix))
2097 		return encoder_name_matrix[encoderID];
2098 	else
2099 		return "Unknown";
2100 }
2101 
2102 
2103 uint32
2104 encoder_object_lookup(uint32 connectorFlags, uint8 dacID)
2105 {
2106 	// used on older cards to take a guess at the encoder
2107 	// object
2108 
2109 	radeon_shared_info &info = *gInfo->shared_info;
2110 
2111 	uint32 ret = 0;
2112 
2113 	switch (connectorFlags) {
2114 		case ATOM_DEVICE_CRT1_SUPPORT:
2115 		case ATOM_DEVICE_TV1_SUPPORT:
2116 		case ATOM_DEVICE_TV2_SUPPORT:
2117 		case ATOM_DEVICE_CRT2_SUPPORT:
2118 		case ATOM_DEVICE_CV_SUPPORT:
2119 			switch (dacID) {
2120 				case 1:
2121 					if ((info.chipsetID == RADEON_RS400)
2122 						|| (info.chipsetID == RADEON_RS480))
2123 						ret = ENCODER_INTERNAL_DAC2_ENUM_ID1;
2124 					else if (info.chipsetID >= RADEON_RS600)
2125 						ret = ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1;
2126 					else
2127 						ret = ENCODER_INTERNAL_DAC1_ENUM_ID1;
2128 					break;
2129 				case 2:
2130 					if (info.chipsetID >= RADEON_RS600)
2131 						ret = ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1;
2132 					else {
2133 						ret = ENCODER_INTERNAL_DAC2_ENUM_ID1;
2134 					}
2135 					break;
2136 				case 3: // external dac
2137 					if (info.chipsetID >= RADEON_RS600)
2138 						ret = ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1;
2139 					else
2140 						ret = ENCODER_INTERNAL_DVO1_ENUM_ID1;
2141 					break;
2142 			}
2143 			break;
2144 		case ATOM_DEVICE_LCD1_SUPPORT:
2145 			if (info.chipsetID >= RADEON_RS600)
2146 				ret = ENCODER_INTERNAL_LVTM1_ENUM_ID1;
2147 			else
2148 				ret = ENCODER_INTERNAL_LVDS_ENUM_ID1;
2149 			break;
2150 		case ATOM_DEVICE_DFP1_SUPPORT:
2151 			if ((info.chipsetID == RADEON_RS400)
2152 				|| (info.chipsetID == RADEON_RS480))
2153 				ret = ENCODER_INTERNAL_DVO1_ENUM_ID1;
2154 			else if (info.chipsetID >= RADEON_RS600)
2155 				ret = ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1;
2156 			else
2157 				ret = ENCODER_INTERNAL_TMDS1_ENUM_ID1;
2158 			break;
2159 		case ATOM_DEVICE_LCD2_SUPPORT:
2160 		case ATOM_DEVICE_DFP2_SUPPORT:
2161 			if ((info.chipsetID == RADEON_RS600)
2162 				|| (info.chipsetID == RADEON_RS690)
2163 				|| (info.chipsetID == RADEON_RS740))
2164 				ret = ENCODER_INTERNAL_DDI_ENUM_ID1;
2165 			else if (info.chipsetID >= RADEON_RS600)
2166 				ret = ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1;
2167 			else
2168 				ret = ENCODER_INTERNAL_DVO1_ENUM_ID1;
2169 			break;
2170 		case ATOM_DEVICE_DFP3_SUPPORT:
2171 			ret = ENCODER_INTERNAL_LVTM1_ENUM_ID1;
2172 			break;
2173 	}
2174 
2175 	return ret;
2176 }
2177 
2178 
2179 uint32
2180 encoder_type_lookup(uint32 encoderID, uint32 connectorFlags)
2181 {
2182 	switch (encoderID) {
2183 		case ENCODER_OBJECT_ID_INTERNAL_LVDS:
2184 		case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
2185 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
2186 		case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
2187 			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
2188 				return VIDEO_ENCODER_LVDS;
2189 			else
2190 				return VIDEO_ENCODER_TMDS;
2191 			break;
2192 		case ENCODER_OBJECT_ID_INTERNAL_DAC1:
2193 			return VIDEO_ENCODER_DAC;
2194 		case ENCODER_OBJECT_ID_INTERNAL_DAC2:
2195 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
2196 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
2197 			return VIDEO_ENCODER_TVDAC;
2198 		case ENCODER_OBJECT_ID_INTERNAL_DVO1:
2199 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
2200 		case ENCODER_OBJECT_ID_INTERNAL_DDI:
2201 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
2202 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
2203 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
2204 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
2205 			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
2206 				return VIDEO_ENCODER_LVDS;
2207 			else if ((connectorFlags & ATOM_DEVICE_CRT_SUPPORT) != 0)
2208 				return VIDEO_ENCODER_DAC;
2209 			else
2210 				return VIDEO_ENCODER_TMDS;
2211 			break;
2212 		case ENCODER_OBJECT_ID_SI170B:
2213 		case ENCODER_OBJECT_ID_CH7303:
2214 		case ENCODER_OBJECT_ID_EXTERNAL_SDVOA:
2215 		case ENCODER_OBJECT_ID_EXTERNAL_SDVOB:
2216 		case ENCODER_OBJECT_ID_TITFP513:
2217 		case ENCODER_OBJECT_ID_VT1623:
2218 		case ENCODER_OBJECT_ID_HDMI_SI1930:
2219 		case ENCODER_OBJECT_ID_TRAVIS:
2220 		case ENCODER_OBJECT_ID_NUTMEG:
2221 			if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
2222 				return VIDEO_ENCODER_LVDS;
2223 			else if ((connectorFlags & ATOM_DEVICE_CRT_SUPPORT) != 0)
2224 				return VIDEO_ENCODER_DAC;
2225 			else
2226 				return VIDEO_ENCODER_TMDS;
2227 			break;
2228 	}
2229 
2230 	return VIDEO_ENCODER_NONE;
2231 }
2232 
2233 
2234 bool
2235 encoder_is_external(uint32 encoderID)
2236 {
2237 	switch (encoderID) {
2238 		case ENCODER_OBJECT_ID_SI170B:
2239 		case ENCODER_OBJECT_ID_CH7303:
2240 		case ENCODER_OBJECT_ID_EXTERNAL_SDVOA:
2241 		case ENCODER_OBJECT_ID_EXTERNAL_SDVOB:
2242 		case ENCODER_OBJECT_ID_TITFP513:
2243 		case ENCODER_OBJECT_ID_VT1623:
2244 		case ENCODER_OBJECT_ID_HDMI_SI1930:
2245 		case ENCODER_OBJECT_ID_TRAVIS:
2246 		case ENCODER_OBJECT_ID_NUTMEG:
2247 			return true;
2248 	}
2249 
2250 	return false;
2251 }
2252 
2253 
2254 bool
2255 encoder_is_dp_bridge(uint32 encoderID)
2256 {
2257 	switch (encoderID) {
2258 		case ENCODER_OBJECT_ID_TRAVIS:
2259 		case ENCODER_OBJECT_ID_NUTMEG:
2260 			return true;
2261 	}
2262 	return false;
2263 }
2264