vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / radeon_hd / encoder.cpp
blob61981f88e4e2c7e3ed2f9a7e6d647fc9a0df4a89
1 /*
2 * Copyright 2006-2012, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Alexander von Gluck, kallisti5@unixzen.com
7 */
10 #include "encoder.h"
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <math.h>
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"
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
35 #define ERROR(x...) _sPrintf("radeon_hd: " x)
38 void
39 encoder_init()
41 TRACE("%s: called\n", __func__);
42 radeon_shared_info &info = *gInfo->shared_info;
44 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
45 if (gConnector[id]->valid == false)
46 continue;
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;
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);
70 void
71 encoder_assign_crtc(uint8 crtcID)
73 TRACE("%s\n", __func__);
75 int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
77 // Table version
78 uint8 tableMajor;
79 uint8 tableMinor;
80 if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor)
81 != B_OK)
82 return;
84 TRACE("%s: table %" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
85 tableMajor, tableMinor);
87 uint16 connectorIndex = gDisplay[crtcID]->connectorIndex;
88 uint16 connectorFlags = gConnector[connectorIndex]->flags;
89 uint16 encoderID = gConnector[connectorIndex]->encoder.objectID;
91 // Prepare AtomBIOS command arguments
92 union crtcSourceParam {
93 SELECT_CRTC_SOURCE_PS_ALLOCATION v1;
94 SELECT_CRTC_SOURCE_PARAMETERS_V2 v2;
96 union crtcSourceParam args;
97 memset(&args, 0, sizeof(args));
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;
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;
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;
207 break;
209 break;
210 default:
211 ERROR("%s: Unknown table version: %" B_PRIu8 ".%" B_PRIu8 "\n",
212 __func__, tableMajor, tableMinor);
213 return;
216 atom_execute_table(gAtomContext, index, (uint32*)&args);
218 // update crtc encoder scratch register @ scratch 3
219 encoder_crtc_scratch(crtcID);
223 uint32
224 encoder_pick_dig(uint32 connectorIndex)
226 TRACE("%s: connector %" B_PRIu32 "\n", __func__, connectorIndex);
227 radeon_shared_info &info = *gInfo->shared_info;
228 uint32 encoderID = gConnector[connectorIndex]->encoder.objectID;
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;
239 bool linkB = gConnector[connectorIndex]->encoder.linkEnumeration
240 == GRAPH_OBJECT_ENUM_ID2 ? true : false;
242 uint32 dceVersion = (info.dceMajor * 100) + info.dceMinor;
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;
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;
264 if (dceVersion >= 302)
265 return crtcID;
267 if (encoderID == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA)
268 return 1;
270 return 0;
274 void
275 encoder_apply_quirks(uint8 crtcID)
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;
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);
293 void
294 encoder_mode_set(uint8 crtcID)
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;
302 // TODO: Should this be the adjusted pll or the original?
303 uint32 pixelClock = pll->pixelClock;
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);
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);
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);
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;
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);
382 encoder_apply_quirks(crtcID);
386 status_t
387 encoder_tv_setup(uint32 connectorIndex, uint32 pixelClock, int command)
389 TRACE("%s: connector %" B_PRIu32 ", pixelClock: %" B_PRIu32 "\n", __func__,
390 connectorIndex, pixelClock);
392 uint16 connectorFlags = gConnector[connectorIndex]->flags;
394 TV_ENCODER_CONTROL_PS_ALLOCATION args;
395 memset(&args, 0, sizeof(args));
397 int index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl);
399 args.sTVEncoder.ucAction = command;
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;
408 args.sTVEncoder.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
410 return atom_execute_table(gAtomContext, index, (uint32*)&args);
414 status_t
415 encoder_digital_setup(uint32 connectorIndex, uint32 pixelClock, int command)
417 TRACE("%s: connector %" B_PRIu32 ", pixelClock: %" B_PRIu32 "\n", __func__,
418 connectorIndex, pixelClock);
420 int index = 0;
421 uint16 connectorFlags = gConnector[connectorIndex]->flags;
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;
439 // Table verson
440 uint8 tableMajor;
441 uint8 tableMinor;
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;
449 uint32 lvdsFlags = gConnector[connectorIndex]->lvdsFlags;
451 bool isHdmi = false;
452 if (gConnector[connectorIndex]->type == VIDEO_CONNECTOR_HDMIA
453 || gConnector[connectorIndex]->type == VIDEO_CONNECTOR_HDMIB) {
454 isHdmi = true;
457 // Prepare AtomBIOS command arguments
458 union lvdsEncoderControl {
459 LVDS_ENCODER_CONTROL_PS_ALLOCATION v1;
460 LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2;
462 union lvdsEncoderControl args;
463 memset(&args, 0, sizeof(args));
465 TRACE("%s: table %" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
466 tableMajor, tableMinor);
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);
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;
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;
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;
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;
525 if (((lvdsFlags >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT)
526 & 0x3) == 2) {
527 args.v2.ucTemporal
528 |= PANEL_ENCODER_TEMPORAL_LEVEL_4;
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;
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;
544 break;
545 default:
546 ERROR("%s: Unknown major table version: %" B_PRIu8 ".%" B_PRIu8 "\n",
547 __func__, tableMajor, tableMinor);
548 return B_ERROR;
550 return atom_execute_table(gAtomContext, index, (uint32*)&args);
554 static uint32
555 encoder_get_bpc()
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;
573 return PANEL_8BIT_PER_COLOR;
577 status_t
578 encoder_dig_setup(uint32 connectorIndex, uint32 pixelClock, int command)
580 TRACE("%s\n", __func__);
582 radeon_shared_info &info = *gInfo->shared_info;
583 connector_info* connector = gConnector[connectorIndex];
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);
595 // Table verson
596 uint8 tableMajor;
597 uint8 tableMinor;
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;
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;
613 union digEncoderControl args;
614 memset(&args, 0, sizeof(args));
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);
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;
640 } else {
641 panelMode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
643 } else
644 panelMode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
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;
654 #endif
656 TRACE("%s: table %" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
657 tableMajor, tableMinor);
659 dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo;
660 uint32 dpClock = 0;
661 if (dpInfo->valid == true)
662 dpClock = dpInfo->linkRate;
664 bool dualLink = false;
665 if (connector->type == VIDEO_CONNECTOR_DVID
666 && pixelClock > 165000) {
667 // TODO: Expand on this duallink code
668 dualLink = true;
671 uint32 encoderMode = display_get_encoder_mode(connectorIndex);
673 // Careful! The mapping of ucHPD_ID differs between atombios calls
674 uint16 hpdID = connector_pick_atom_hpdid(connectorIndex);
676 if (tableMajor != 1) {
677 ERROR("%s: Unknown table major!\n", __func__);
680 switch (tableMinor) {
681 case 1:
682 args.v1.ucAction = command;
683 args.v1.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
685 if (command == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
686 args.v3.ucPanelMode = panelMode;
687 else {
688 args.v1.ucEncoderMode = encoderMode;
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;
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;
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;
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);
728 if (command == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
729 args.v3.ucPanelMode = panelMode;
730 else
731 args.v3.ucEncoderMode = encoderMode;
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;
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;
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);
754 if (command == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
755 args.v4.ucPanelMode = panelMode;
756 else
757 args.v4.ucEncoderMode = encoderMode;
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;
770 } else if (dualLink) {
771 // DualLink, double the lane numbers
772 args.v4.ucLaneNum = 8;
773 } else {
774 args.v4.ucLaneNum = 4;
776 args.v4.acConfig.ucDigSel = digEncoderID;
777 args.v4.ucBitPerColor = encoder_get_bpc();
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);
821 break;
822 default:
823 ERROR("%s: unknown tableMinor!\n", __func__);
824 return B_ERROR;
827 status_t result = atom_execute_table(gAtomContext, index, (uint32*)&args);
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);
834 #endif
836 return result;
840 status_t
841 encoder_external_setup(uint32 connectorIndex, int command)
843 TRACE("%s: connector %" B_PRIu32 "\n", __func__, connectorIndex);
845 encoder_info* encoder
846 = &gConnector[connectorIndex]->encoder;
847 encoder_info* extEncoder
848 = &gConnector[connectorIndex]->encoderExternal;
849 uint32 connectorFlags = gConnector[connectorIndex]->flags;
851 dp_info* dpInfo
852 = &gConnector[connectorIndex]->dpInfo;
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;
860 uint8 tableMajor;
861 uint8 tableMinor;
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;
870 // Prepare AtomBIOS command arguments
871 union externalEncoderControl {
872 EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1;
873 EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3;
875 union externalEncoderControl args;
876 memset(&args, 0, sizeof(args));
878 int connectorObjectID
879 = (gConnector[connectorIndex]->objectID & OBJECT_ID_MASK)
880 >> OBJECT_ID_SHIFT;
882 uint32 pixelClock = encoder->pll.pixelClock;
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);
900 if (connector_is_dp(connectorIndex)) {
901 if (dpInfo->linkRate == 270000) {
902 args.v1.sDigEncoder.ucConfig
903 |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
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;
912 break;
913 case 3:
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);
924 args.v3.sExtEncoder.ucEncoderMode
925 = display_get_encoder_mode(connectorIndex);
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;
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;
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;
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;
990 break;
992 default:
993 ERROR("%s: Unknown table minor version: "
994 "%" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
995 tableMajor, tableMinor);
996 return B_ERROR;
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;
1006 return atom_execute_table(gAtomContext, index, (uint32*)&args);
1010 status_t
1011 encoder_analog_setup(uint32 connectorIndex, uint32 pixelClock, int command)
1013 TRACE("%s: connector %" B_PRIu32 ", pixelClock: %" B_PRIu32 "\n", __func__,
1014 connectorIndex, pixelClock);
1016 uint32 connectorFlags = gConnector[connectorIndex]->flags;
1018 int index = 0;
1019 DAC_ENCODER_CONTROL_PS_ALLOCATION args;
1020 memset(&args, 0, sizeof(args));
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;
1033 args.ucAction = command;
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;
1050 args.usPixelClock = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1052 return atom_execute_table(gAtomContext, index, (uint32*)&args);
1056 bool
1057 encoder_analog_load_detect(uint32 connectorIndex)
1059 TRACE("%s: connector %" B_PRIu32 "\n", __func__, connectorIndex);
1061 if (gConnector[connectorIndex]->encoderExternal.valid == true)
1062 return encoder_dig_load_detect(connectorIndex);
1064 return encoder_dac_load_detect(connectorIndex);
1068 bool
1069 encoder_dac_load_detect(uint32 connectorIndex)
1071 TRACE("%s: connector %" B_PRIu32 "\n", __func__, connectorIndex);
1073 uint32 connectorFlags = gConnector[connectorIndex]->flags;
1074 uint32 encoderID = gConnector[connectorIndex]->encoder.objectID;
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;
1084 // *** tell the card we want to do a DAC detection
1086 DAC_LOAD_DETECTION_PS_ALLOCATION args;
1087 int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection);
1088 uint8 tableMajor;
1089 uint8 tableMinor;
1091 memset(&args, 0, sizeof(args));
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;
1100 args.sDacload.ucMisc = 0;
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;
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);
1114 uint32 biosScratch0 = Read32(OUT, R600_SCRATCH_REG0);
1116 if ((biosScratch0 & ATOM_S0_CRT1_MASK) != 0)
1117 return true;
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);
1124 uint32 biosScratch0 = Read32(OUT, R600_SCRATCH_REG0);
1126 if ((biosScratch0 & ATOM_S0_CRT2_MASK) != 0)
1127 return true;
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);
1136 uint32 biosScratch0 = Read32(OUT, R600_SCRATCH_REG0);
1138 if ((biosScratch0 & (ATOM_S0_CV_MASK | ATOM_S0_CV_MASK_A)) != 0)
1139 return true;
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);
1148 uint32 biosScratch0 = Read32(OUT, R600_SCRATCH_REG0);
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 */
1159 return false;
1163 bool
1164 encoder_dig_load_detect(uint32 connectorIndex)
1166 TRACE("%s: connector %" B_PRIu32 "\n", __func__, connectorIndex);
1167 radeon_shared_info &info = *gInfo->shared_info;
1169 if (info.dceMajor < 4) {
1170 ERROR("%s: Strange: External DIG encoder on DCE < 4?\n", __func__);
1171 return false;
1174 encoder_external_setup(connectorIndex,
1175 EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION);
1177 uint32 biosScratch0 = Read32(OUT, R600_SCRATCH_REG0);
1179 uint32 connectorFlags = gConnector[connectorIndex]->flags;
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 */
1199 return false;
1203 status_t
1204 transmitter_dig_setup(uint32 connectorIndex, uint32 pixelClock,
1205 uint8 laneNumber, uint8 laneSet, int command)
1207 TRACE("%s: connector %" B_PRIu32 ", pixelClock: %" B_PRIu32 "\n", __func__,
1208 connectorIndex, pixelClock);
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;
1229 if (index < 0) {
1230 ERROR("%s: GetIndexIntoMasterTable failed!\n", __func__);
1231 return B_ERROR;
1234 uint8 tableMajor;
1235 uint8 tableMinor;
1237 if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor)
1238 != B_OK)
1239 return B_ERROR;
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;
1250 union digTransmitterControl args;
1251 memset(&args, 0, sizeof(args));
1253 TRACE("%s: table %" B_PRIu8 ".%" B_PRIu8 "\n", __func__,
1254 tableMajor, tableMinor);
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);
1262 pll_info* pll = &gConnector[connectorIndex]->encoder.pll;
1264 bool isDP = connector_is_dp(connectorIndex);
1265 bool linkB = gConnector[connectorIndex]->encoder.linkEnumeration
1266 == GRAPH_OBJECT_ENUM_ID2 ? true : false;
1268 dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo;
1270 uint32 dpClock = 0;
1271 int dpLaneCount = 0;
1272 if (dpInfo->valid == true) {
1273 dpClock = dpInfo->linkRate;
1274 dpLaneCount = dpInfo->laneCount;
1277 switch (tableMajor) {
1278 case 1:
1279 switch (tableMinor) {
1280 case 1:
1281 args.v1.ucAction = command;
1282 if (command == ATOM_TRANSMITTER_ACTION_INIT) {
1283 args.v1.usInitInfo
1284 = B_HOST_TO_LENDIAN_INT16(connectorObjectID);
1285 } else if (command
1286 == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1287 args.v1.asMode.ucLaneSel = laneNumber;
1288 args.v1.asMode.ucLaneSet = laneSet;
1289 } else {
1290 if (isDP) {
1291 args.v1.usPixelClock
1292 = B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1293 } else if (pixelClock > 165000) {
1294 args.v1.usPixelClock = B_HOST_TO_LENDIAN_INT16(
1295 (pixelClock / 2) / 10);
1296 } else {
1297 args.v1.usPixelClock
1298 = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1302 args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
1304 if (digEncoderID > 0) {
1305 args.v1.ucConfig
1306 |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
1307 } else {
1308 args.v1.ucConfig
1309 |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
1312 // TODO: IGP DIG Transmitter setup
1313 #if 0
1314 if ((rdev->flags & RADEON_IS_IGP) && (encoderObjectID
1315 == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) {
1316 if (is_dp || (radeon_encoder->pixel_clock <= 165000)) {
1317 if (igp_lane_info & 0x1)
1318 args.v1.ucConfig
1319 |= ATOM_TRANSMITTER_CONFIG_LANE_0_3;
1320 else if (igp_lane_info & 0x2)
1321 args.v1.ucConfig
1322 |= ATOM_TRANSMITTER_CONFIG_LANE_4_7;
1323 else if (igp_lane_info & 0x4)
1324 args.v1.ucConfig
1325 |= ATOM_TRANSMITTER_CONFIG_LANE_8_11;
1326 else if (igp_lane_info & 0x8)
1327 args.v1.ucConfig
1328 |= ATOM_TRANSMITTER_CONFIG_LANE_12_15;
1329 } else {
1330 if (igp_lane_info & 0x3)
1331 args.v1.ucConfig
1332 |= ATOM_TRANSMITTER_CONFIG_LANE_0_7;
1333 else if (igp_lane_info & 0xc)
1334 args.v1.ucConfig
1335 |= ATOM_TRANSMITTER_CONFIG_LANE_8_15;
1338 #endif
1340 if (linkB == true)
1341 args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB;
1342 else
1343 args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
1345 if (isDP)
1346 args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
1347 else if ((gConnector[connectorIndex]->flags
1348 & ATOM_DEVICE_DFP_SUPPORT) != 0) {
1349 if (1) {
1350 // if coherentMode, i've only ever seen it true
1351 args.v1.ucConfig
1352 |= ATOM_TRANSMITTER_CONFIG_COHERENT;
1354 if (pixelClock > 165000) {
1355 args.v1.ucConfig
1356 |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK;
1359 break;
1360 case 2:
1361 args.v2.ucAction = command;
1362 if (command == ATOM_TRANSMITTER_ACTION_INIT) {
1363 args.v2.usInitInfo
1364 = B_HOST_TO_LENDIAN_INT16(connectorObjectID);
1365 } else if (command
1366 == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1367 args.v2.asMode.ucLaneSel = laneNumber;
1368 args.v2.asMode.ucLaneSet = laneSet;
1369 } else {
1370 if (isDP) {
1371 args.v2.usPixelClock
1372 = B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1373 } else if (pixelClock > 165000) {
1374 args.v2.usPixelClock = B_HOST_TO_LENDIAN_INT16(
1375 (pixelClock / 2) / 10);
1376 } else {
1377 args.v2.usPixelClock
1378 = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1381 args.v2.acConfig.ucEncoderSel = digEncoderID;
1382 if (linkB)
1383 args.v2.acConfig.ucLinkSel = 1;
1385 switch (encoderObjectID) {
1386 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1387 args.v2.acConfig.ucTransmitterSel = 0;
1388 break;
1389 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1390 args.v2.acConfig.ucTransmitterSel = 1;
1391 break;
1392 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1393 args.v2.acConfig.ucTransmitterSel = 2;
1394 break;
1397 if (isDP) {
1398 args.v2.acConfig.fCoherentMode = 1;
1399 args.v2.acConfig.fDPConnector = 1;
1400 } else if ((gConnector[connectorIndex]->flags
1401 & ATOM_DEVICE_DFP_SUPPORT) != 0) {
1402 if (1) {
1403 // if coherentMode, i've only ever seen it true
1404 args.v2.acConfig.fCoherentMode = 1;
1407 if (pixelClock > 165000)
1408 args.v2.acConfig.fDualLinkConnector = 1;
1410 break;
1411 case 3:
1412 args.v3.ucAction = command;
1413 if (command == ATOM_TRANSMITTER_ACTION_INIT) {
1414 args.v3.usInitInfo
1415 = B_HOST_TO_LENDIAN_INT16(connectorObjectID);
1416 } else if (command
1417 == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1418 args.v3.asMode.ucLaneSel = laneNumber;
1419 args.v3.asMode.ucLaneSet = laneSet;
1420 } else {
1421 if (isDP) {
1422 args.v3.usPixelClock
1423 = B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1424 } else if (pixelClock > 165000) {
1425 args.v3.usPixelClock = B_HOST_TO_LENDIAN_INT16(
1426 (pixelClock / 2) / 10);
1427 } else {
1428 args.v3.usPixelClock
1429 = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1433 if (isDP)
1434 args.v3.ucLaneNum = dpLaneCount;
1435 else if (pixelClock > 165000)
1436 args.v3.ucLaneNum = 8;
1437 else
1438 args.v3.ucLaneNum = 4;
1440 if (linkB == true)
1441 args.v3.acConfig.ucLinkSel = 1;
1442 if (digEncoderID & 1)
1443 args.v3.acConfig.ucEncoderSel = 1;
1445 // Select the PLL for the PHY
1446 // DP PHY to be clocked from external src if possible
1448 // DCE4 has external DCPLL clock for DP
1449 if (isDP && gInfo->dpExternalClock) {
1450 // use external clock source (id'ed to 2 on DCE4)
1451 args.v3.acConfig.ucRefClkSource = 2; // EXT clock
1452 } else
1453 args.v3.acConfig.ucRefClkSource = pll->id;
1455 switch (encoderObjectID) {
1456 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1457 args.v3.acConfig.ucTransmitterSel = 0;
1458 break;
1459 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1460 args.v3.acConfig.ucTransmitterSel = 1;
1461 break;
1462 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1463 args.v3.acConfig.ucTransmitterSel = 2;
1464 break;
1467 if (isDP)
1468 args.v3.acConfig.fCoherentMode = 1;
1469 else if ((gConnector[connectorIndex]->flags
1470 & ATOM_DEVICE_DFP_SUPPORT) != 0) {
1471 if (1) {
1472 // if coherentMode, i've only ever seen it true
1473 args.v3.acConfig.fCoherentMode = 1;
1475 if (pixelClock > 165000)
1476 args.v3.acConfig.fDualLinkConnector = 1;
1478 break;
1479 case 4:
1480 args.v4.ucAction = command;
1481 if (command == ATOM_TRANSMITTER_ACTION_INIT) {
1482 args.v4.usInitInfo
1483 = B_HOST_TO_LENDIAN_INT16(connectorObjectID);
1484 } else if (command
1485 == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
1486 args.v4.asMode.ucLaneSel = laneNumber;
1487 args.v4.asMode.ucLaneSet = laneSet;
1488 } else {
1489 if (isDP) {
1490 args.v4.usPixelClock
1491 = B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1492 } else if (pixelClock > 165000) {
1493 args.v4.usPixelClock = B_HOST_TO_LENDIAN_INT16(
1494 (pixelClock / 2) / 10);
1495 } else {
1496 args.v4.usPixelClock
1497 = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1501 if (isDP)
1502 args.v4.ucLaneNum = dpLaneCount;
1503 else if (pixelClock > 165000)
1504 args.v4.ucLaneNum = 8;
1505 else
1506 args.v4.ucLaneNum = 4;
1508 if (linkB == true)
1509 args.v4.acConfig.ucLinkSel = 1;
1510 if (digEncoderID & 1)
1511 args.v4.acConfig.ucEncoderSel = 1;
1513 // Select the PLL for the PHY
1514 // DP PHY to be clocked from external src if possible
1515 // DCE5, DCPLL usually generates the DP ref clock
1516 if (isDP) {
1517 if (gInfo->dpExternalClock > 0) {
1518 args.v4.acConfig.ucRefClkSource
1519 = ENCODER_REFCLK_SRC_EXTCLK;
1520 } else {
1521 args.v4.acConfig.ucRefClkSource
1522 = ENCODER_REFCLK_SRC_DCPLL;
1524 } else
1525 args.v4.acConfig.ucRefClkSource = pll->id;
1527 switch (encoderObjectID) {
1528 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1529 args.v4.acConfig.ucTransmitterSel = 0;
1530 break;
1531 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1532 args.v4.acConfig.ucTransmitterSel = 1;
1533 break;
1534 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1535 args.v4.acConfig.ucTransmitterSel = 2;
1536 break;
1539 if (isDP)
1540 args.v4.acConfig.fCoherentMode = 1;
1541 else if ((gConnector[connectorIndex]->flags
1542 & ATOM_DEVICE_DFP_SUPPORT) != 0) {
1543 if (1) {
1544 // if coherentMode, i've only ever seen it true
1545 args.v4.acConfig.fCoherentMode = 1;
1547 if (pixelClock > 165000)
1548 args.v4.acConfig.fDualLinkConnector = 1;
1550 break;
1551 case 5:
1552 args.v5.ucAction = command;
1554 if (isDP) {
1555 args.v5.usSymClock
1556 = B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1557 } else {
1558 args.v5.usSymClock
1559 = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1561 switch (encoderObjectID) {
1562 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1563 if (linkB)
1564 args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYB;
1565 else
1566 args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYA;
1567 break;
1568 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1569 if (linkB)
1570 args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYD;
1571 else
1572 args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYC;
1573 break;
1574 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1575 if (linkB)
1576 args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYF;
1577 else
1578 args.v5.ucPhyId = ATOM_PHY_ID_UNIPHYE;
1579 break;
1581 if (isDP) {
1582 args.v5.ucLaneNum = dpLaneCount;
1583 } else if (pixelClock >= 165000) {
1584 args.v5.ucLaneNum = 8;
1585 } else {
1586 args.v5.ucLaneNum = 4;
1589 args.v5.ucConnObjId = connectorObjectID;
1591 if (command != ATOM_TRANSMITTER_ACTION_INIT) {
1592 // not used on INIT and display_get_encoder_mode
1593 // unavailable until displays are probed.
1594 args.v5.ucDigMode
1595 = display_get_encoder_mode(connectorIndex);
1598 if (isDP && gInfo->dpExternalClock) {
1599 args.v5.asConfig.ucPhyClkSrcId
1600 = ENCODER_REFCLK_SRC_EXTCLK;
1601 } else {
1602 args.v5.asConfig.ucPhyClkSrcId = pll->id;
1605 if (isDP) {
1606 args.v5.asConfig.ucCoherentMode = 1;
1607 // DP always coherent
1608 } else if ((gConnector[connectorIndex]->flags
1609 & ATOM_DEVICE_DFP_SUPPORT) != 0) {
1610 // TODO: dig coherent mode? VVV
1611 args.v5.asConfig.ucCoherentMode = 1;
1614 // TODO: hpd_id, for now RADEON_HPD_NONE.
1615 args.v5.asConfig.ucHPDSel = 0;
1617 args.v5.ucDigEncoderSel = 1 << digEncoderID;
1618 args.v5.ucDPLaneSet = laneSet;
1619 break;
1620 case 6:
1621 args.v6.ucAction = command;
1622 if (isDP) {
1623 args.v6.ulSymClock
1624 = B_HOST_TO_LENDIAN_INT16(dpClock / 10);
1625 } else {
1626 args.v6.ulSymClock
1627 = B_HOST_TO_LENDIAN_INT16(pixelClock / 10);
1629 switch (encoderObjectID) {
1630 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1631 if (linkB)
1632 args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYB;
1633 else
1634 args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYA;
1635 break;
1636 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1637 if (linkB)
1638 args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYD;
1639 else
1640 args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYC;
1641 break;
1642 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1643 if (linkB)
1644 args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYF;
1645 else
1646 args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYE;
1647 break;
1648 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
1649 args.v6.ucPhyId = ATOM_PHY_ID_UNIPHYG;
1650 break;
1652 if (isDP)
1653 args.v6.ucLaneNum = dpLaneCount;
1654 else if (pixelClock > 165000)
1655 args.v6.ucLaneNum = 8;
1656 else
1657 args.v6.ucLaneNum = 4;
1659 args.v6.ucConnObjId = connectorObjectID;
1661 if (command == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH)
1662 args.v6.ucDPLaneSet = laneSet;
1663 else if (command != ATOM_TRANSMITTER_ACTION_INIT) {
1664 // not used on INIT and display_get_encoder_mode
1665 // unavailable until displays are probed.
1666 args.v6.ucDigMode
1667 = display_get_encoder_mode(connectorIndex);
1669 // TODO: hpd_id, for now RADEON_HPD_NONE.
1670 args.v6.ucHPDSel = 0;
1672 args.v6.ucDigEncoderSel = 1 << digEncoderID;
1673 break;
1674 default:
1675 ERROR("%s: unknown table version\n", __func__);
1677 break;
1678 default:
1679 ERROR("%s: unknown table version\n", __func__);
1682 return atom_execute_table(gAtomContext, index, (uint32*)&args);
1686 void
1687 encoder_crtc_scratch(uint8 crtcID)
1689 TRACE("%s: display %" B_PRIu8 "\n", __func__, crtcID);
1691 uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
1692 uint32 connectorFlags = gConnector[connectorIndex]->flags;
1694 // TODO: r500
1695 uint32 biosScratch3 = Read32(OUT, R600_SCRATCH_REG3);
1697 if ((connectorFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
1698 biosScratch3 &= ~ATOM_S3_TV1_CRTC_ACTIVE;
1699 biosScratch3 |= (crtcID << 18);
1701 if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0) {
1702 biosScratch3 &= ~ATOM_S3_CV_CRTC_ACTIVE;
1703 biosScratch3 |= (crtcID << 24);
1705 if ((connectorFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) {
1706 biosScratch3 &= ~ATOM_S3_CRT1_CRTC_ACTIVE;
1707 biosScratch3 |= (crtcID << 16);
1709 if ((connectorFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) {
1710 biosScratch3 &= ~ATOM_S3_CRT2_CRTC_ACTIVE;
1711 biosScratch3 |= (crtcID << 20);
1713 if ((connectorFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) {
1714 biosScratch3 &= ~ATOM_S3_LCD1_CRTC_ACTIVE;
1715 biosScratch3 |= (crtcID << 17);
1717 if ((connectorFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) {
1718 biosScratch3 &= ~ATOM_S3_DFP1_CRTC_ACTIVE;
1719 biosScratch3 |= (crtcID << 19);
1721 if ((connectorFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) {
1722 biosScratch3 &= ~ATOM_S3_DFP2_CRTC_ACTIVE;
1723 biosScratch3 |= (crtcID << 23);
1725 if ((connectorFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) {
1726 biosScratch3 &= ~ATOM_S3_DFP3_CRTC_ACTIVE;
1727 biosScratch3 |= (crtcID << 25);
1730 // TODO: r500
1731 Write32(OUT, R600_SCRATCH_REG3, biosScratch3);
1735 void
1736 encoder_dpms_scratch(uint8 crtcID, bool power)
1738 TRACE("%s: display %" B_PRIu8 "\n", __func__, crtcID);
1740 uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
1741 uint32 connectorFlags = gConnector[connectorIndex]->flags;
1743 // TODO: r500
1744 uint32 biosScratch2 = Read32(OUT, R600_SCRATCH_REG2);
1746 if ((connectorFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
1747 if (power == true)
1748 biosScratch2 &= ~ATOM_S2_TV1_DPMS_STATE;
1749 else
1750 biosScratch2 |= ATOM_S2_TV1_DPMS_STATE;
1752 if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0) {
1753 if (power == true)
1754 biosScratch2 &= ~ATOM_S2_CV_DPMS_STATE;
1755 else
1756 biosScratch2 |= ATOM_S2_CV_DPMS_STATE;
1758 if ((connectorFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) {
1759 if (power == true)
1760 biosScratch2 &= ~ATOM_S2_CRT1_DPMS_STATE;
1761 else
1762 biosScratch2 |= ATOM_S2_CRT1_DPMS_STATE;
1764 if ((connectorFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) {
1765 if (power == true)
1766 biosScratch2 &= ~ATOM_S2_CRT2_DPMS_STATE;
1767 else
1768 biosScratch2 |= ATOM_S2_CRT2_DPMS_STATE;
1770 if ((connectorFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) {
1771 if (power == true)
1772 biosScratch2 &= ~ATOM_S2_LCD1_DPMS_STATE;
1773 else
1774 biosScratch2 |= ATOM_S2_LCD1_DPMS_STATE;
1776 if ((connectorFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) {
1777 if (power == true)
1778 biosScratch2 &= ~ATOM_S2_DFP1_DPMS_STATE;
1779 else
1780 biosScratch2 |= ATOM_S2_DFP1_DPMS_STATE;
1782 if ((connectorFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) {
1783 if (power == true)
1784 biosScratch2 &= ~ATOM_S2_DFP2_DPMS_STATE;
1785 else
1786 biosScratch2 |= ATOM_S2_DFP2_DPMS_STATE;
1788 if ((connectorFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) {
1789 if (power == true)
1790 biosScratch2 &= ~ATOM_S2_DFP3_DPMS_STATE;
1791 else
1792 biosScratch2 |= ATOM_S2_DFP3_DPMS_STATE;
1794 if ((connectorFlags & ATOM_DEVICE_DFP4_SUPPORT) != 0) {
1795 if (power == true)
1796 biosScratch2 &= ~ATOM_S2_DFP4_DPMS_STATE;
1797 else
1798 biosScratch2 |= ATOM_S2_DFP4_DPMS_STATE;
1800 if ((connectorFlags & ATOM_DEVICE_DFP5_SUPPORT) != 0) {
1801 if (power == true)
1802 biosScratch2 &= ~ATOM_S2_DFP5_DPMS_STATE;
1803 else
1804 biosScratch2 |= ATOM_S2_DFP5_DPMS_STATE;
1806 Write32(OUT, R600_SCRATCH_REG2, biosScratch2);
1810 void
1811 encoder_dpms_set(uint8 crtcID, int mode)
1813 TRACE("%s: display %" B_PRIu8 ", power: %s\n", __func__, crtcID,
1814 mode == B_DPMS_ON ? "true" : "false");
1816 int index = -1;
1817 radeon_shared_info &info = *gInfo->shared_info;
1819 DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
1820 memset(&args, 0, sizeof(args));
1822 uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
1823 uint32 connectorFlags = gConnector[connectorIndex]->flags;
1824 uint16 encoderID = gConnector[connectorIndex]->encoder.objectID;
1826 switch (encoderID) {
1827 case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
1828 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
1829 index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl);
1830 break;
1831 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
1832 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
1833 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
1834 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
1835 encoder_dpms_set_dig(crtcID, mode);
1836 break;
1837 case ENCODER_OBJECT_ID_INTERNAL_DVO1:
1838 case ENCODER_OBJECT_ID_INTERNAL_DDI:
1839 index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
1840 break;
1841 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
1842 if (info.dceMajor >= 5)
1843 encoder_dpms_set_dvo(crtcID, mode);
1844 else if (info.dceMajor >= 3)
1845 encoder_dpms_set_dig(crtcID, mode);
1846 else
1847 index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
1848 break;
1849 case ENCODER_OBJECT_ID_INTERNAL_LVDS:
1850 index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
1851 break;
1852 case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
1853 if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
1854 index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
1855 else
1856 index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl);
1857 break;
1858 case ENCODER_OBJECT_ID_INTERNAL_DAC1:
1859 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
1860 if ((connectorFlags & ATOM_DEVICE_TV_SUPPORT) != 0)
1861 index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
1862 else if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0)
1863 index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
1864 else
1865 index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
1866 break;
1867 case ENCODER_OBJECT_ID_INTERNAL_DAC2:
1868 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
1869 if ((connectorFlags & ATOM_DEVICE_TV_SUPPORT) != 0)
1870 index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
1871 else if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0)
1872 index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
1873 else
1874 index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
1875 break;
1876 // default, none on purpose
1879 // If we have an index, we need to execute a table.
1880 if (index >= 0) {
1881 switch (mode) {
1882 case B_DPMS_ON:
1883 args.ucAction = ATOM_ENABLE;
1884 break;
1885 case B_DPMS_STAND_BY:
1886 case B_DPMS_SUSPEND:
1887 case B_DPMS_OFF:
1888 args.ucAction = ATOM_DISABLE;
1889 break;
1892 atom_execute_table(gAtomContext, index, (uint32*)&args);
1893 if (info.dceMajor < 5) {
1894 if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
1895 args.ucAction = args.ucAction == ATOM_DISABLE
1896 ? ATOM_LCD_BLOFF : ATOM_LCD_BLON;
1897 atom_execute_table(gAtomContext, index, (uint32*)&args);
1900 if (info.dceMajor < 4)
1901 encoder_dpms_scratch(crtcID, true);
1906 void
1907 encoder_dpms_set_dig(uint8 crtcID, int mode)
1909 TRACE("%s: display %" B_PRIu8 ", power: %s\n", __func__, crtcID,
1910 mode == B_DPMS_ON ? "true" : "false");
1912 radeon_shared_info &info = *gInfo->shared_info;
1913 uint32 connectorIndex = gDisplay[crtcID]->connectorIndex;
1914 connector_info* connector = gConnector[connectorIndex];
1915 uint32 connectorFlags = connector->flags;
1916 pll_info* pll = &connector->encoder.pll;
1917 bool hasExternal = connector->encoderExternal.valid;
1918 bool travisQuirk = info.dceMajor < 5
1919 && (connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0
1920 && connector->encoderExternal.objectID == ENCODER_OBJECT_ID_TRAVIS;
1922 switch (mode) {
1923 case B_DPMS_ON:
1924 if ((info.dceMajor == 4 && info.dceMinor == 1)
1925 || info.dceMajor >= 5) {
1926 // Setup encoder
1927 encoder_dig_setup(connectorIndex, pll->pixelClock,
1928 ATOM_ENCODER_CMD_SETUP);
1929 encoder_dig_setup(connectorIndex, pll->pixelClock,
1930 ATOM_ENCODER_CMD_SETUP_PANEL_MODE);
1931 } else if (info.dceMajor >= 4) {
1932 // Setup encoder
1933 encoder_dig_setup(connectorIndex, pll->pixelClock,
1934 ATOM_ENCODER_CMD_SETUP);
1935 } else {
1936 // Setup encoder and transmitter
1937 encoder_dig_setup(connectorIndex, pll->pixelClock, ATOM_ENABLE);
1938 transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
1939 ATOM_TRANSMITTER_ACTION_SETUP);
1942 if (connector->type == VIDEO_CONNECTOR_EDP) {
1943 // TODO: If VIDEO_CONNECTOR_EDP, ATOM_TRANSMITTER_ACTION_POWER_ON
1944 ERROR("%s: TODO, edp_panel_power!\n",
1945 __func__);
1948 // Enable transmitter
1949 transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
1950 ATOM_TRANSMITTER_ACTION_ENABLE);
1952 if (connector_is_dp(connectorIndex)) {
1953 if (info.dceMajor >= 4) {
1954 encoder_dig_setup(connectorIndex, pll->pixelClock,
1955 ATOM_ENCODER_CMD_DP_VIDEO_OFF);
1957 // dp link train
1958 dp_link_train(crtcID);
1959 if (info.dceMajor >= 4) {
1960 encoder_dig_setup(connectorIndex, pll->pixelClock,
1961 ATOM_ENCODER_CMD_DP_VIDEO_ON);
1963 // not sure what AtomBIOS table/command sets this
1964 // register, but it's required to get the video output
1965 Write32(OUT, AVIVO_DP_VID_STREAM_CNTL, 0x201);
1967 if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
1968 transmitter_dig_setup(connectorIndex, pll->pixelClock,
1969 0, 0, ATOM_TRANSMITTER_ACTION_LCD_BLON);
1971 if (hasExternal)
1972 encoder_external_setup(connectorIndex, ATOM_ENABLE);
1973 break;
1974 case B_DPMS_STAND_BY:
1975 case B_DPMS_SUSPEND:
1976 case B_DPMS_OFF:
1977 if (connector_is_dp(connectorIndex)) {
1978 if (info.dceMajor >= 4) {
1979 encoder_dig_setup(connectorIndex, pll->pixelClock,
1980 ATOM_ENCODER_CMD_DP_VIDEO_OFF);
1983 if (hasExternal)
1984 encoder_external_setup(connectorIndex, ATOM_DISABLE);
1985 if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) {
1986 transmitter_dig_setup(connectorIndex, pll->pixelClock,
1987 0, 0, ATOM_TRANSMITTER_ACTION_LCD_BLOFF);
1989 if (connector_is_dp(connectorIndex) && !travisQuirk) {
1990 // If not TRAVIS on < DCE 5, set_rx_power_state D3
1991 ERROR("%s: TODO: dpms off set_rx_power_state D3\n", __func__);
1993 if (info.dceMajor >= 4) {
1994 // Disable transmitter
1995 transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
1996 ATOM_TRANSMITTER_ACTION_DISABLE);
1997 } else {
1998 // Disable transmitter and encoder
1999 transmitter_dig_setup(connectorIndex, pll->pixelClock, 0, 0,
2000 ATOM_TRANSMITTER_ACTION_DISABLE);
2001 encoder_dig_setup(connectorIndex, pll->pixelClock, ATOM_DISABLE);
2004 if (connector_is_dp(connectorIndex)) {
2005 if (travisQuirk) {
2006 ERROR("%s: TODO: dpms off set_rx_power_state D3\n",
2007 __func__);
2009 if (connector->type == VIDEO_CONNECTOR_EDP) {
2010 // TODO: ATOM_TRANSMITTER_ACTION_POWER_OFF
2011 ERROR("%s: TODO, edp_panel_power!\n", __func__);
2014 break;
2019 void
2020 encoder_dpms_set_dvo(uint8 crtcID, int mode)
2022 ERROR("%s: TODO, dvo encoder dpms stub\n", __func__);
2026 void
2027 encoder_output_lock(bool lock)
2029 TRACE("%s: %s\n", __func__, lock ? "true" : "false");
2030 uint32 biosScratch6 = Read32(OUT, R600_SCRATCH_REG6);
2032 if (lock) {
2033 biosScratch6 |= ATOM_S6_CRITICAL_STATE;
2034 biosScratch6 &= ~ATOM_S6_ACC_MODE;
2035 } else {
2036 biosScratch6 &= ~ATOM_S6_CRITICAL_STATE;
2037 biosScratch6 |= ATOM_S6_ACC_MODE;
2040 Write32(OUT, R600_SCRATCH_REG6, biosScratch6);
2043 static const char* encoder_name_matrix[] = {
2044 "NONE",
2045 "Internal Radeon LVDS",
2046 "Internal Radeon TMDS1",
2047 "Internal Radeon TMDS2",
2048 "Internal Radeon DAC1",
2049 "Internal Radeon DAC2 (TV)",
2050 "Internal Radeon SDVOA",
2051 "Internal Radeon SDVOB",
2052 "External 3rd party SI170B",
2053 "External 3rd party CH7303",
2054 "External 3rd party CH7301",
2055 "Internal Radeon DVO1",
2056 "External 3rd party SDVOA",
2057 "External 3rd party SDVOB",
2058 "External 3rd party TITFP513",
2059 "Internal LVTM1",
2060 "External 3rd party VT1623",
2061 "External HDMI SI1930",
2062 "Internal HDMI",
2063 "Internal Kaleidoscope TMDS1",
2064 "Internal Kaleidoscope DVO1",
2065 "Internal Kaleidoscope DAC1",
2066 "Internal Kaleidoscope DAC2",
2067 "External Kaleidoscope SI178",
2068 "MVPU FPGA",
2069 "Internal Kaleidoscope DDI",
2070 "External Kaleidoscope VT1625",
2071 "External Kaleidoscope HDMI SI1932",
2072 "External Kaleidoscope DP AN9801",
2073 "External Kaleidoscope DP DP501",
2074 "Internal Kaleidoscope UNIPHY",
2075 "Internal Kaleidoscope LVTMA",
2076 "Internal Kaleidoscope UNIPHY1",
2077 "Internal Kaleidoscope UNIPHY2",
2078 "External Nutmeg Bridge",
2079 "External Travis Bridge",
2080 "Internal Kaleidoscope VCE"
2084 const char*
2085 encoder_name_lookup(uint32 encoderID) {
2086 if (encoderID < B_COUNT_OF(encoder_name_matrix))
2087 return encoder_name_matrix[encoderID];
2088 else
2089 return "Unknown";
2093 uint32
2094 encoder_object_lookup(uint32 connectorFlags, uint8 dacID)
2096 // used on older cards to take a guess at the encoder
2097 // object
2099 radeon_shared_info &info = *gInfo->shared_info;
2101 uint32 ret = 0;
2103 switch (connectorFlags) {
2104 case ATOM_DEVICE_CRT1_SUPPORT:
2105 case ATOM_DEVICE_TV1_SUPPORT:
2106 case ATOM_DEVICE_TV2_SUPPORT:
2107 case ATOM_DEVICE_CRT2_SUPPORT:
2108 case ATOM_DEVICE_CV_SUPPORT:
2109 switch (dacID) {
2110 case 1:
2111 if ((info.chipsetID == RADEON_RS400)
2112 || (info.chipsetID == RADEON_RS480))
2113 ret = ENCODER_INTERNAL_DAC2_ENUM_ID1;
2114 else if (info.chipsetID >= RADEON_RS600)
2115 ret = ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1;
2116 else
2117 ret = ENCODER_INTERNAL_DAC1_ENUM_ID1;
2118 break;
2119 case 2:
2120 if (info.chipsetID >= RADEON_RS600)
2121 ret = ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1;
2122 else {
2123 ret = ENCODER_INTERNAL_DAC2_ENUM_ID1;
2125 break;
2126 case 3: // external dac
2127 if (info.chipsetID >= RADEON_RS600)
2128 ret = ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1;
2129 else
2130 ret = ENCODER_INTERNAL_DVO1_ENUM_ID1;
2131 break;
2133 break;
2134 case ATOM_DEVICE_LCD1_SUPPORT:
2135 if (info.chipsetID >= RADEON_RS600)
2136 ret = ENCODER_INTERNAL_LVTM1_ENUM_ID1;
2137 else
2138 ret = ENCODER_INTERNAL_LVDS_ENUM_ID1;
2139 break;
2140 case ATOM_DEVICE_DFP1_SUPPORT:
2141 if ((info.chipsetID == RADEON_RS400)
2142 || (info.chipsetID == RADEON_RS480))
2143 ret = ENCODER_INTERNAL_DVO1_ENUM_ID1;
2144 else if (info.chipsetID >= RADEON_RS600)
2145 ret = ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1;
2146 else
2147 ret = ENCODER_INTERNAL_TMDS1_ENUM_ID1;
2148 break;
2149 case ATOM_DEVICE_LCD2_SUPPORT:
2150 case ATOM_DEVICE_DFP2_SUPPORT:
2151 if ((info.chipsetID == RADEON_RS600)
2152 || (info.chipsetID == RADEON_RS690)
2153 || (info.chipsetID == RADEON_RS740))
2154 ret = ENCODER_INTERNAL_DDI_ENUM_ID1;
2155 else if (info.chipsetID >= RADEON_RS600)
2156 ret = ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1;
2157 else
2158 ret = ENCODER_INTERNAL_DVO1_ENUM_ID1;
2159 break;
2160 case ATOM_DEVICE_DFP3_SUPPORT:
2161 ret = ENCODER_INTERNAL_LVTM1_ENUM_ID1;
2162 break;
2165 return ret;
2169 uint32
2170 encoder_type_lookup(uint32 encoderID, uint32 connectorFlags)
2172 switch (encoderID) {
2173 case ENCODER_OBJECT_ID_INTERNAL_LVDS:
2174 case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
2175 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
2176 case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
2177 if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
2178 return VIDEO_ENCODER_LVDS;
2179 else
2180 return VIDEO_ENCODER_TMDS;
2181 break;
2182 case ENCODER_OBJECT_ID_INTERNAL_DAC1:
2183 return VIDEO_ENCODER_DAC;
2184 case ENCODER_OBJECT_ID_INTERNAL_DAC2:
2185 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
2186 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
2187 return VIDEO_ENCODER_TVDAC;
2188 case ENCODER_OBJECT_ID_INTERNAL_DVO1:
2189 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
2190 case ENCODER_OBJECT_ID_INTERNAL_DDI:
2191 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
2192 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
2193 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
2194 case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
2195 if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
2196 return VIDEO_ENCODER_LVDS;
2197 else if ((connectorFlags & ATOM_DEVICE_CRT_SUPPORT) != 0)
2198 return VIDEO_ENCODER_DAC;
2199 else
2200 return VIDEO_ENCODER_TMDS;
2201 break;
2202 case ENCODER_OBJECT_ID_SI170B:
2203 case ENCODER_OBJECT_ID_CH7303:
2204 case ENCODER_OBJECT_ID_EXTERNAL_SDVOA:
2205 case ENCODER_OBJECT_ID_EXTERNAL_SDVOB:
2206 case ENCODER_OBJECT_ID_TITFP513:
2207 case ENCODER_OBJECT_ID_VT1623:
2208 case ENCODER_OBJECT_ID_HDMI_SI1930:
2209 case ENCODER_OBJECT_ID_TRAVIS:
2210 case ENCODER_OBJECT_ID_NUTMEG:
2211 if ((connectorFlags & ATOM_DEVICE_LCD_SUPPORT) != 0)
2212 return VIDEO_ENCODER_LVDS;
2213 else if ((connectorFlags & ATOM_DEVICE_CRT_SUPPORT) != 0)
2214 return VIDEO_ENCODER_DAC;
2215 else
2216 return VIDEO_ENCODER_TMDS;
2217 break;
2220 return VIDEO_ENCODER_NONE;
2224 bool
2225 encoder_is_external(uint32 encoderID)
2227 switch (encoderID) {
2228 case ENCODER_OBJECT_ID_SI170B:
2229 case ENCODER_OBJECT_ID_CH7303:
2230 case ENCODER_OBJECT_ID_EXTERNAL_SDVOA:
2231 case ENCODER_OBJECT_ID_EXTERNAL_SDVOB:
2232 case ENCODER_OBJECT_ID_TITFP513:
2233 case ENCODER_OBJECT_ID_VT1623:
2234 case ENCODER_OBJECT_ID_HDMI_SI1930:
2235 case ENCODER_OBJECT_ID_TRAVIS:
2236 case ENCODER_OBJECT_ID_NUTMEG:
2237 return true;
2240 return false;
2244 bool
2245 encoder_is_dp_bridge(uint32 encoderID)
2247 switch (encoderID) {
2248 case ENCODER_OBJECT_ID_TRAVIS:
2249 case ENCODER_OBJECT_ID_NUTMEG:
2250 return true;
2252 return false;