xref: /haiku/src/add-ons/accelerants/radeon_hd/encoder.cpp (revision 4466b89c65970de4c7236ac87faa2bee4589f413)
1 /*
2  * Copyright 2006-2011, 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 "accelerant_protos.h"
11 #include "accelerant.h"
12 #include "bios.h"
13 #include "display.h"
14 #include "utility.h"
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <math.h>
20 
21 
22 #define TRACE_ENCODER
23 #ifdef TRACE_ENCODER
24 extern "C" void _sPrintf(const char *format, ...);
25 #   define TRACE(x...) _sPrintf("radeon_hd: " x)
26 #else
27 #   define TRACE(x...) ;
28 #endif
29 
30 #define ERROR(x...) _sPrintf("radeon_hd: " x)
31 
32 
33 union crtc_source_param {
34 	SELECT_CRTC_SOURCE_PS_ALLOCATION v1;
35 	SELECT_CRTC_SOURCE_PARAMETERS_V2 v2;
36 };
37 
38 
39 void
40 encoder_assign_crtc(uint8 crtcID)
41 {
42 	int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
43 	union crtc_source_param args;
44 
45 	// Table version
46 	uint8 tableMajor;
47 	uint8 tableMinor;
48 
49 	memset(&args, 0, sizeof(args));
50 
51 	if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor)
52 		!= B_OK)
53 		return;
54 
55 	uint16 connectorIndex = gDisplay[crtcID]->connectorIndex;
56 	uint16 encoderID = gConnector[connectorIndex]->encoder.objectID;
57 	uint16 encoderFlags = gConnector[connectorIndex]->encoder.flags;
58 
59 	switch (tableMajor) {
60 		case 1:
61 			switch (tableMinor) {
62 				case 1:
63 				default:
64 					args.v1.ucCRTC = crtcID;
65 					switch (encoderID) {
66 						case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
67 						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
68 							args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX;
69 							break;
70 						case ENCODER_OBJECT_ID_INTERNAL_LVDS:
71 						case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
72 							if ((gConnector[connectorIndex]->flags
73 								& ATOM_DEVICE_LCD1_SUPPORT) != 0)
74 								args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX;
75 							else
76 								args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX;
77 							break;
78 						case ENCODER_OBJECT_ID_INTERNAL_DVO1:
79 						case ENCODER_OBJECT_ID_INTERNAL_DDI:
80 						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
81 							args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX;
82 							break;
83 						case ENCODER_OBJECT_ID_INTERNAL_DAC1:
84 						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
85 							if ((encoderFlags & ATOM_DEVICE_TV_SUPPORT) != 0) {
86 								args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
87 							} else if ((encoderFlags
88 								& ATOM_DEVICE_CV_SUPPORT) != 0) {
89 								args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
90 							} else
91 								args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX;
92 							break;
93 						case ENCODER_OBJECT_ID_INTERNAL_DAC2:
94 						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
95 							if ((encoderFlags & ATOM_DEVICE_TV_SUPPORT) != 0) {
96 								args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
97 							} else if ((encoderFlags
98 								& ATOM_DEVICE_CV_SUPPORT) != 0) {
99 								args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
100 							} else
101 								args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX;
102 							break;
103 					}
104 					break;
105 				case 2:
106 					args.v2.ucCRTC = crtcID;
107 					args.v2.ucEncodeMode
108 						= display_get_encoder_mode(connectorIndex);
109 					switch (encoderID) {
110 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
111 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
112 						case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
113 						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
114 							ERROR("%s: DIG encoder not yet supported!\n",
115 								__func__);
116 							//dig = radeon_encoder->enc_priv;
117 							//switch (dig->dig_encoder) {
118 							//	case 0:
119 							//		args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
120 							//		break;
121 							//	case 1:
122 							//		args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
123 							//		break;
124 							//	case 2:
125 							//		args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID;
126 							//		break;
127 							//	case 3:
128 							//		args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID;
129 							//		break;
130 							//	case 4:
131 							//		args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID;
132 							//		break;
133 							//	case 5:
134 							//		args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID;
135 							//		break;
136 							//}
137 							break;
138 						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
139 							args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID;
140 							break;
141 						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
142 							if ((encoderFlags & ATOM_DEVICE_TV_SUPPORT) != 0) {
143 								args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
144 							} else if ((encoderFlags
145 								& ATOM_DEVICE_CV_SUPPORT) != 0) {
146 								args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
147 							} else
148 								args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
149 							break;
150 						case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
151 							if ((encoderFlags & ATOM_DEVICE_TV_SUPPORT) != 0) {
152 								args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
153 							} else if ((encoderFlags
154 								& ATOM_DEVICE_CV_SUPPORT) != 0) {
155 								args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
156 							} else
157 								args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
158 							break;
159 					}
160 					break;
161 			}
162 			break;
163 		default:
164 			ERROR("%s: Unknown table version: %" B_PRIu8 ".%" B_PRIu8 "\n",
165 				__func__, tableMajor, tableMinor);
166 			return;
167 	}
168 
169 	atom_execute_table(gAtomContext, index, (uint32*)&args);
170 
171 	// update crtc encoder scratch register @ scratch 3
172 	encoder_crtc_scratch(crtcID);
173 }
174 
175 
176 void
177 encoder_apply_quirks(uint8 crtcID)
178 {
179 	radeon_shared_info &info = *gInfo->shared_info;
180 	register_info* regs = gDisplay[crtcID]->regs;
181 	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
182 	uint16 encoderFlags = gConnector[connectorIndex]->encoder.flags;
183 
184 	// Setting the scaler clears this on some chips...
185 	if (info.dceMajor >= 3
186 		&& (encoderFlags & ATOM_DEVICE_TV_SUPPORT) == 0) {
187 		// TODO: assume non interleave mode for now
188 		// en: EVERGREEN_INTERLEAVE_EN : AVIVO_D1MODE_INTERLEAVE_EN
189 		Write32(OUT, regs->modeDataFormat, 0);
190 	}
191 }
192 
193 
194 void
195 encoder_mode_set(uint8 id, uint32 pixelClock)
196 {
197 	radeon_shared_info &info = *gInfo->shared_info;
198 	uint32 connectorIndex = gDisplay[id]->connectorIndex;
199 	uint16 encoderFlags = gConnector[connectorIndex]->encoder.flags;
200 
201 	switch (gConnector[connectorIndex]->encoder.objectID) {
202 		case ENCODER_OBJECT_ID_INTERNAL_DAC1:
203 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
204 		case ENCODER_OBJECT_ID_INTERNAL_DAC2:
205 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
206 			encoder_analog_setup(id, pixelClock, ATOM_ENABLE);
207 			if ((encoderFlags
208 				& (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) != 0) {
209 				encoder_tv_setup(id, pixelClock, ATOM_ENABLE);
210 			} else {
211 				encoder_tv_setup(id, pixelClock, ATOM_DISABLE);
212 			}
213 			break;
214 		case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
215 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
216 		case ENCODER_OBJECT_ID_INTERNAL_LVDS:
217 		case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
218 			encoder_digital_setup(id, pixelClock, PANEL_ENCODER_ACTION_ENABLE);
219 			break;
220 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
221 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
222 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
223 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
224 			if (info.dceMajor >= 4) {
225 				//atombios_dig_transmitter_setup(encoder,
226 				//	ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
227 					// TODO: Disable the dig transmitter
228 				encoder_dig_setup(id, pixelClock, ATOM_ENCODER_CMD_SETUP);
229 					// Setup and enable the dig encoder
230 
231 				//atombios_dig_transmitter_setup(encoder,
232 				//	ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
233 					// TODO: Enable the dig transmitter
234 			} else {
235 				//atombios_dig_transmitter_setup(encoder,
236 				//	ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
237 					// Disable the dig transmitter
238 				encoder_dig_setup(id, pixelClock, ATOM_DISABLE);
239 					// Disable the dig encoder
240 
241 				/* setup and enable the encoder and transmitter */
242 				encoder_dig_setup(id, pixelClock, ATOM_ENABLE);
243 					// Setup and enable the dig encoder
244 
245 				//atombios_dig_transmitter_setup(encoder,
246 				//	ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
247 				//atombios_dig_transmitter_setup(encoder,
248 				//	ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
249 					// TODO: Setup and Enable the dig transmitter
250 			}
251 
252 			TRACE("%s: TODO for DIG encoder setup\n", __func__);
253 			break;
254 		case ENCODER_OBJECT_ID_INTERNAL_DDI:
255 		case ENCODER_OBJECT_ID_INTERNAL_DVO1:
256 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
257 			TRACE("%s: TODO for DVO encoder setup\n", __func__);
258 			break;
259 		default:
260 			TRACE("%s: TODO for unknown encoder setup!\n", __func__);
261 	}
262 
263 	encoder_apply_quirks(id);
264 }
265 
266 
267 status_t
268 encoder_tv_setup(uint8 id, uint32 pixelClock, int command)
269 {
270 	uint32 connectorIndex = gDisplay[id]->connectorIndex;
271 	uint16 encoderFlags = gConnector[connectorIndex]->encoder.flags;
272 
273 	TV_ENCODER_CONTROL_PS_ALLOCATION args;
274 	memset(&args, 0, sizeof(args));
275 
276 	int index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl);
277 
278 	args.sTVEncoder.ucAction = command;
279 
280 	if ((encoderFlags & ATOM_DEVICE_CV_SUPPORT) != 0)
281 		args.sTVEncoder.ucTvStandard = ATOM_TV_CV;
282 	else {
283 		// TODO: we assume NTSC for now
284 		args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
285 	}
286 
287 	args.sTVEncoder.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
288 
289 	return atom_execute_table(gAtomContext, index, (uint32*)&args);
290 }
291 
292 
293 union lvds_encoder_control {
294 	LVDS_ENCODER_CONTROL_PS_ALLOCATION    v1;
295 	LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2;
296 };
297 
298 
299 status_t
300 encoder_digital_setup(uint8 id, uint32 pixelClock, int command)
301 {
302 	TRACE("%s\n", __func__);
303 
304 	uint32 connectorIndex = gDisplay[id]->connectorIndex;
305 
306 	union lvds_encoder_control args;
307 	memset(&args, 0, sizeof(args));
308 
309 	int index = 0;
310 	uint16 encoderFlags = gConnector[connectorIndex]->encoder.flags;
311 
312 	switch (gConnector[connectorIndex]->encoder.objectID) {
313 		case ENCODER_OBJECT_ID_INTERNAL_LVDS:
314 			index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
315 			break;
316 		case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
317 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
318 			index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl);
319 			break;
320 		case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
321 			if ((encoderFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
322 				index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
323 			else
324 				index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl);
325 			break;
326 	}
327 
328 	// Table verson
329 	uint8 tableMajor;
330 	uint8 tableMinor;
331 
332 	if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor)
333 		!= B_OK)
334 		return B_ERROR;
335 
336 	switch (tableMajor) {
337 	case 1:
338 	case 2:
339 		switch (tableMinor) {
340 			case 1:
341 				args.v1.ucMisc = 0;
342 				args.v1.ucAction = command;
343 				if (0)	// TODO: HDMI?
344 					args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
345 				args.v1.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
346 
347 				if ((encoderFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
348 					// TODO: laptop display support
349 					//if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL)
350 					//	args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
351 					//if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
352 					//	args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
353 				} else {
354 					//if (dig->linkb)
355 					//	args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
356 					if (pixelClock > 165000)
357 						args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
358 					/*if (pScrn->rgbBits == 8) */
359 					args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
360 				}
361 				break;
362 			case 2:
363 			case 3:
364 				args.v2.ucMisc = 0;
365 				args.v2.ucAction = command;
366 				if (tableMinor == 3) {
367 					//if (dig->coherent_mode)
368 					//	args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT;
369 				}
370 				if (0) // TODO: HDMI?
371 					args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
372 				args.v2.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
373 				args.v2.ucTruncate = 0;
374 				args.v2.ucSpatial = 0;
375 				args.v2.ucTemporal = 0;
376 				args.v2.ucFRC = 0;
377 				if ((encoderFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
378 					// TODO: laptop display support
379 					//if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL)
380 					//	args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
381 					//if (dig->lcd_misc & ATOM_PANEL_MISC_SPATIAL) {
382 					args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN;
383 					//if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB)
384 					//	args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH;
385 					//}
386 					//if (dig->lcd_misc & ATOM_PANEL_MISC_TEMPORAL) {
387 					//	args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN;
388 					//	if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) {
389 					//		args.v2.ucTemporal
390 					//			|= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH;
391 					//	}
392 					//	if (((dig->lcd_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT)
393 					//		& 0x3) == 2) {
394 					//		args.v2.ucTemporal
395 					//			|= PANEL_ENCODER_TEMPORAL_LEVEL_4;
396 					//	}
397 					//}
398 				} else {
399 					//if (dig->linkb)
400 					//	args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
401 					if (pixelClock > 165000)
402 						args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
403 				}
404 				break;
405 			default:
406 				ERROR("%s: Unknown minor table version: %"
407 					B_PRIu8 ".%" B_PRIu8 "\n", __func__,
408 					tableMajor, tableMinor);
409 				return B_ERROR;
410 		}
411 		break;
412 	default:
413 		ERROR("%s: Unknown major table version: %" B_PRIu8 ".%" B_PRIu8 "\n",
414 			__func__, tableMajor, tableMinor);
415 		return B_ERROR;
416 	}
417 	return atom_execute_table(gAtomContext, index, (uint32*)&args);
418 }
419 
420 
421 union dig_encoder_control {
422 	DIG_ENCODER_CONTROL_PS_ALLOCATION v1;
423 	DIG_ENCODER_CONTROL_PARAMETERS_V2 v2;
424 	DIG_ENCODER_CONTROL_PARAMETERS_V3 v3;
425 	DIG_ENCODER_CONTROL_PARAMETERS_V4 v4;
426 };
427 
428 
429 status_t
430 encoder_dig_setup(uint8 id, uint32 pixelClock, int command)
431 {
432 	radeon_shared_info &info = *gInfo->shared_info;
433 
434 	uint32 connectorIndex = gDisplay[id]->connectorIndex;
435 	uint32 encoderID = gConnector[connectorIndex]->encoder.objectID;
436 
437 	union dig_encoder_control args;
438 	int index = 0;
439 
440 	uint8 tableMajor;
441 	uint8 tableMinor;
442 
443 	memset(&args, 0, sizeof(args));
444 
445 	if (info.dceMajor > 4)
446 		index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl);
447 	else {
448 		if (1) // TODO: pick dig encoder
449 			index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
450 		else
451 			index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
452 	}
453 
454 	if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor)
455 		!= B_OK) {
456 		ERROR("%s: cannot parse command table\n", __func__);
457 		return B_ERROR;
458 	}
459 
460 	args.v1.ucAction = command;
461 	args.v1.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
462 
463 	#if 0
464 	if (command == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) {
465 		if (info.dceMajor >= 4 && 0) // TODO: 0 == if DP bridge
466 			args.v3.ucPanelMode = DP_PANEL_MODE_INTERNAL_DP1_MODE;
467 		else
468 			args.v3.ucPanelMode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
469 	} else {
470 		args.v1.ucEncoderMode = display_get_encoder_mode(connectorIndex);
471 
472 	if (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP
473 		|| args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST) {
474 		args.v1.ucLaneNum = dp_lane_count;
475 	} else if (pixelClock > 165000)
476 		args.v1.ucLaneNum = 8;
477 	else
478 		args.v1.ucLaneNum = 4;
479 
480 	if (info.dceMajor >= 5) {
481 		if (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP
482 			|| args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST) {
483 				if (dpClock == 270000) {
484 					args.v1.ucConfig
485 						|= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ;
486 				} else if (dpClock == 540000) {
487 					args.v1.ucConfig
488 						|= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ;
489 				}
490 		}
491 		args.v4.acConfig.ucDigSel = dig->dig_encoder;
492 		switch (bpc) {
493 			case 0:
494 				args.v4.ucBitPerColor = PANEL_BPC_UNDEFINE;
495 				break;
496 			case 6:
497 				args.v4.ucBitPerColor = PANEL_6BIT_PER_COLOR;
498 				break;
499 			case 8:
500 			default:
501 				args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR;
502 				break;
503 			case 10:
504 				args.v4.ucBitPerColor = PANEL_10BIT_PER_COLOR;
505 				break;
506 			case 12:
507 				args.v4.ucBitPerColor = PANEL_12BIT_PER_COLOR;
508 				break;
509 			case 16:
510 				args.v4.ucBitPerColor = PANEL_16BIT_PER_COLOR;
511 				break;
512 		}
513 
514 		//if (hpdID == RADEON_HPD_NONE)
515 		if (1)
516 			args.v4.ucHPD_ID = 0;
517 		else
518 			args.v4.ucHPD_ID = hpd_id + 1;
519 
520 	} else if (info.dceMajor >= 4) {
521 		if (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP
522 			&& dp_clock == 270000) {
523 			args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
524 		}
525 
526 		args.v3.acConfig.ucDigSel = dig->dig_encoder;
527 		switch (bpc) {
528 			case 0:
529 				args.v3.ucBitPerColor = PANEL_BPC_UNDEFINE;
530 				break;
531 			case 6:
532 				args.v3.ucBitPerColor = PANEL_6BIT_PER_COLOR;
533 				break;
534 			case 8:
535 			default:
536 				args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR;
537 				break;
538 			case 10:
539 				args.v3.ucBitPerColor = PANEL_10BIT_PER_COLOR;
540 				break;
541 			case 12:
542 				args.v3.ucBitPerColor = PANEL_12BIT_PER_COLOR;
543 				break;
544 			case 16:
545 				args.v3.ucBitPerColor = PANEL_16BIT_PER_COLOR;
546 				break;
547 		}
548 
549 	} else {
550 		if (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP
551 			&& dp_clock == 270000) {
552 			args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
553 		}
554 	#endif
555 		switch (encoderID) {
556 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
557 				args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
558 				break;
559 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
560 			case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
561 				args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2;
562 				break;
563 			case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
564 				args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3;
565 				break;
566 		}
567 	#if 0
568 		if (dig->linkb)
569 			args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
570 		else
571 			args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
572 	}
573 	#endif
574 
575 	return atom_execute_table(gAtomContext, index, (uint32*)&args);
576 }
577 
578 
579 status_t
580 encoder_analog_setup(uint8 id, uint32 pixelClock, int command)
581 {
582 	TRACE("%s\n", __func__);
583 
584 	uint32 connectorIndex = gDisplay[id]->connectorIndex;
585 
586 	int index = 0;
587 	DAC_ENCODER_CONTROL_PS_ALLOCATION args;
588 	memset(&args, 0, sizeof(args));
589 
590 	switch (gConnector[connectorIndex]->encoder.objectID) {
591 		case ENCODER_OBJECT_ID_INTERNAL_DAC1:
592 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
593 			index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl);
594 			break;
595 		case ENCODER_OBJECT_ID_INTERNAL_DAC2:
596 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
597 			index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl);
598 			break;
599 	}
600 
601 	args.ucAction = command;
602 	args.ucDacStandard = ATOM_DAC1_PS2;
603 		// TODO: or ATOM_DAC1_CV if ATOM_DEVICE_CV_SUPPORT
604 		// TODO: or ATOM_DAC1_PAL or ATOM_DAC1_NTSC if else
605 
606 	args.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
607 
608 	return atom_execute_table(gAtomContext, index, (uint32*)&args);
609 }
610 
611 
612 bool
613 encoder_analog_load_detect(uint8 connectorIndex)
614 {
615 	uint32 encoderFlags = gConnector[connectorIndex]->encoder.flags;
616 	uint32 encoderID = gConnector[connectorIndex]->encoder.objectID;
617 
618 	if ((encoderFlags & ATOM_DEVICE_TV_SUPPORT) == 0
619 		&& (encoderFlags & ATOM_DEVICE_CV_SUPPORT) == 0
620 		&& (encoderFlags & ATOM_DEVICE_CRT_SUPPORT) == 0) {
621 		ERROR("%s: executed on non-dac device connector #%" B_PRIu8 "\n",
622 			__func__, connectorIndex);
623 		return false;
624 	}
625 
626 	// *** tell the card we want to do a DAC detection
627 
628 	DAC_LOAD_DETECTION_PS_ALLOCATION args;
629 	int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection);
630 	uint8 tableMajor;
631 	uint8 tableMinor;
632 
633 	memset(&args, 0, sizeof(args));
634 
635 	if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor)
636 		!= B_OK) {
637 		ERROR("%s: failed getting AtomBIOS header for DAC_LoadDetection\n",
638 			__func__);
639 		return false;
640 	}
641 
642 	args.sDacload.ucMisc = 0;
643 
644 	if (encoderID == ENCODER_OBJECT_ID_INTERNAL_DAC1
645 		|| encoderID == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1) {
646 		args.sDacload.ucDacType = ATOM_DAC_A;
647 	} else {
648 		args.sDacload.ucDacType = ATOM_DAC_B;
649 	}
650 
651 	if ((encoderFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) {
652 		args.sDacload.usDeviceID
653 			= B_HOST_TO_LENDIAN_INT16(ATOM_DEVICE_CRT1_SUPPORT);
654 		atom_execute_table(gAtomContext, index, (uint32*)&args);
655 
656 		uint32 biosScratch0 = Read32(OUT, R600_BIOS_0_SCRATCH);
657 
658 		if ((biosScratch0 & ATOM_S0_CRT1_MASK) != 0)
659 			return true;
660 
661 	} else if ((encoderFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) {
662 		args.sDacload.usDeviceID
663 			= B_HOST_TO_LENDIAN_INT16(ATOM_DEVICE_CRT2_SUPPORT);
664 		atom_execute_table(gAtomContext, index, (uint32*)&args);
665 
666 		uint32 biosScratch0 = Read32(OUT, R600_BIOS_0_SCRATCH);
667 
668 		if ((biosScratch0 & ATOM_S0_CRT2_MASK) != 0)
669 			return true;
670 
671 	} else if ((encoderFlags & ATOM_DEVICE_CV_SUPPORT) != 0) {
672 		args.sDacload.usDeviceID
673 			= B_HOST_TO_LENDIAN_INT16(ATOM_DEVICE_CV_SUPPORT);
674 		if (tableMinor >= 3)
675 			args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
676 		atom_execute_table(gAtomContext, index, (uint32*)&args);
677 
678 		uint32 biosScratch0 = Read32(OUT, R600_BIOS_0_SCRATCH);
679 
680 		if ((biosScratch0 & (ATOM_S0_CV_MASK | ATOM_S0_CV_MASK_A)) != 0)
681 			return true;
682 
683 	} else if ((encoderFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
684 		args.sDacload.usDeviceID
685 			= B_HOST_TO_LENDIAN_INT16(ATOM_DEVICE_TV1_SUPPORT);
686 		if (tableMinor >= 3)
687 			args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
688 		atom_execute_table(gAtomContext, index, (uint32*)&args);
689 
690 		uint32 biosScratch0 = Read32(OUT, R600_BIOS_0_SCRATCH);
691 
692 		if ((biosScratch0
693 			& (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) != 0) {
694 			return true; /* Composite connected */
695 		} else if ((biosScratch0
696 			& (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) != 0) {
697 			return true; /* S-Video connected */
698 		}
699 
700 	}
701 	return false;
702 }
703 
704 
705 void
706 encoder_crtc_scratch(uint8 crtcID)
707 {
708 	TRACE("%s\n", __func__);
709 
710 	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
711 	uint32 encoderFlags = gConnector[connectorIndex]->encoder.flags;
712 
713 	// TODO: r500
714 	uint32 biosScratch3 = Read32(OUT, R600_BIOS_3_SCRATCH);
715 
716 	if ((encoderFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
717 		biosScratch3 &= ~ATOM_S3_TV1_CRTC_ACTIVE;
718 		biosScratch3 |= (crtcID << 18);
719 	}
720 	if ((encoderFlags & ATOM_DEVICE_CV_SUPPORT) != 0) {
721 		biosScratch3 &= ~ATOM_S3_CV_CRTC_ACTIVE;
722 		biosScratch3 |= (crtcID << 24);
723 	}
724 	if ((encoderFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) {
725 		biosScratch3 &= ~ATOM_S3_CRT1_CRTC_ACTIVE;
726 		biosScratch3 |= (crtcID << 16);
727 	}
728 	if ((encoderFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) {
729 		biosScratch3 &= ~ATOM_S3_CRT2_CRTC_ACTIVE;
730 		biosScratch3 |= (crtcID << 20);
731 	}
732 	if ((encoderFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) {
733 		biosScratch3 &= ~ATOM_S3_LCD1_CRTC_ACTIVE;
734 		biosScratch3 |= (crtcID << 17);
735 	}
736 	if ((encoderFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) {
737 		biosScratch3 &= ~ATOM_S3_DFP1_CRTC_ACTIVE;
738 		biosScratch3 |= (crtcID << 19);
739 	}
740 	if ((encoderFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) {
741 		biosScratch3 &= ~ATOM_S3_DFP2_CRTC_ACTIVE;
742 		biosScratch3 |= (crtcID << 23);
743 	}
744 	if ((encoderFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) {
745 		biosScratch3 &= ~ATOM_S3_DFP3_CRTC_ACTIVE;
746 		biosScratch3 |= (crtcID << 25);
747 	}
748 
749 	// TODO: r500
750 	Write32(OUT, R600_BIOS_3_SCRATCH, biosScratch3);
751 }
752 
753 
754 void
755 encoder_dpms_scratch(uint8 crtcID, bool power)
756 {
757 	TRACE("%s: power: %s\n", __func__, power ? "true" : "false");
758 
759 	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
760 	uint32 encoderFlags = gConnector[connectorIndex]->encoder.flags;
761 
762 	// TODO: r500
763 	uint32 biosScratch2 = Read32(OUT, R600_BIOS_2_SCRATCH);
764 
765 	if ((encoderFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
766 		if (power == true)
767 			biosScratch2 &= ~ATOM_S2_TV1_DPMS_STATE;
768 		else
769 			biosScratch2 |= ATOM_S2_TV1_DPMS_STATE;
770 	}
771 	if ((encoderFlags & ATOM_DEVICE_CV_SUPPORT) != 0) {
772 		if (power == true)
773 			biosScratch2 &= ~ATOM_S2_CV_DPMS_STATE;
774 		else
775 			biosScratch2 |= ATOM_S2_CV_DPMS_STATE;
776 	}
777 	if ((encoderFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) {
778 		if (power == true)
779 			biosScratch2 &= ~ATOM_S2_CRT1_DPMS_STATE;
780 		else
781 			biosScratch2 |= ATOM_S2_CRT1_DPMS_STATE;
782 	}
783 	if ((encoderFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) {
784 		if (power == true)
785 			biosScratch2 &= ~ATOM_S2_CRT2_DPMS_STATE;
786 		else
787 			biosScratch2 |= ATOM_S2_CRT2_DPMS_STATE;
788 	}
789 	if ((encoderFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) {
790 		if (power == true)
791 			biosScratch2 &= ~ATOM_S2_LCD1_DPMS_STATE;
792 		else
793 			biosScratch2 |= ATOM_S2_LCD1_DPMS_STATE;
794 	}
795 	if ((encoderFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) {
796 		if (power == true)
797 			biosScratch2 &= ~ATOM_S2_DFP1_DPMS_STATE;
798 		else
799 			biosScratch2 |= ATOM_S2_DFP1_DPMS_STATE;
800 	}
801 	if ((encoderFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) {
802 		if (power == true)
803 			biosScratch2 &= ~ATOM_S2_DFP2_DPMS_STATE;
804 		else
805 			biosScratch2 |= ATOM_S2_DFP2_DPMS_STATE;
806 	}
807 	if ((encoderFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) {
808 		if (power == true)
809 			biosScratch2 &= ~ATOM_S2_DFP3_DPMS_STATE;
810 		else
811 			biosScratch2 |= ATOM_S2_DFP3_DPMS_STATE;
812 	}
813 	if ((encoderFlags & ATOM_DEVICE_DFP4_SUPPORT) != 0) {
814 		if (power == true)
815 			biosScratch2 &= ~ATOM_S2_DFP4_DPMS_STATE;
816 		else
817 			biosScratch2 |= ATOM_S2_DFP4_DPMS_STATE;
818 	}
819 	if ((encoderFlags & ATOM_DEVICE_DFP5_SUPPORT) != 0) {
820 		if (power == true)
821 			biosScratch2 &= ~ATOM_S2_DFP5_DPMS_STATE;
822 		else
823 			biosScratch2 |= ATOM_S2_DFP5_DPMS_STATE;
824 	}
825 	Write32(OUT, R600_BIOS_2_SCRATCH, biosScratch2);
826 }
827 
828 
829 void
830 encoder_dpms_set(uint8 crtcID, uint8 encoderID, int mode)
831 {
832 	int index = 0;
833 	DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
834 
835 	memset(&args, 0, sizeof(args));
836 
837 	uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
838 	uint32 encoderFlags = gConnector[connectorIndex]->encoder.flags;
839 
840 	switch (encoderID) {
841 		case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
842 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
843 			index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl);
844 			break;
845 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
846 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
847 		case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
848 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
849 			ERROR("%s: TODO DIG DPMS set\n", __func__);
850 			return;
851 		case ENCODER_OBJECT_ID_INTERNAL_DVO1:
852 		case ENCODER_OBJECT_ID_INTERNAL_DDI:
853 			index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
854 			break;
855 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
856 			// TODO: encoder dpms set newer cards
857 			// If DCE5, dvo true
858 			// If DCE3, dig true
859 			// else...
860 			index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
861 			break;
862 		case ENCODER_OBJECT_ID_INTERNAL_LVDS:
863 			index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
864 			break;
865 		case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
866 			if ((encoderFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
867 				index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
868 			else
869 				index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl);
870 			break;
871 		case ENCODER_OBJECT_ID_INTERNAL_DAC1:
872 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
873 			// TODO: encoder dpms dce5 dac
874 			// else...
875 			/*
876 			if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
877 				index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
878 			else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
879 				index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
880 			else
881 			*/
882 			index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
883 			break;
884 		case ENCODER_OBJECT_ID_INTERNAL_DAC2:
885 		case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
886 			// TODO: tv or CV encoder on DAC2
887 			index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
888 			break;
889 	}
890 
891 	switch (mode) {
892 		case B_DPMS_ON:
893 			args.ucAction = ATOM_ENABLE;
894 			atom_execute_table(gAtomContext, index, (uint32*)&args);
895 			if ((encoderFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
896 				args.ucAction = ATOM_LCD_BLON;
897 				atom_execute_table(gAtomContext, index, (uint32*)&args);
898 			}
899 			encoder_dpms_scratch(crtcID, true);
900 			break;
901 		case B_DPMS_STAND_BY:
902 		case B_DPMS_SUSPEND:
903 		case B_DPMS_OFF:
904 			args.ucAction = ATOM_DISABLE;
905 			atom_execute_table(gAtomContext, index, (uint32*)&args);
906 			if ((encoderFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
907 				args.ucAction = ATOM_LCD_BLOFF;
908 				atom_execute_table(gAtomContext, index, (uint32*)&args);
909 			}
910 			encoder_dpms_scratch(crtcID, false);
911 			break;
912 	}
913 }
914 
915 
916 void
917 encoder_output_lock(bool lock)
918 {
919 	TRACE("%s: %s\n", __func__, lock ? "true" : "false");
920 	uint32 biosScratch6 = Read32(OUT, R600_BIOS_6_SCRATCH);
921 
922 	if (lock) {
923 		biosScratch6 |= ATOM_S6_CRITICAL_STATE;
924 		biosScratch6 &= ~ATOM_S6_ACC_MODE;
925 	} else {
926 		biosScratch6 &= ~ATOM_S6_CRITICAL_STATE;
927 		biosScratch6 |= ATOM_S6_ACC_MODE;
928 	}
929 
930 	Write32(OUT, R600_BIOS_6_SCRATCH, biosScratch6);
931 }
932