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 "connector.h"
11
12 #include <assert.h>
13 #include <Debug.h>
14
15 #include "accelerant_protos.h"
16 #include "accelerant.h"
17 #include "bios.h"
18 #include "encoder.h"
19 #include "gpu.h"
20 #include "utility.h"
21
22
23 #undef TRACE
24
25 #define TRACE_CONNECTOR
26 #ifdef TRACE_CONNECTOR
27 # define TRACE(x...) _sPrintf("radeon_hd: " x)
28 #else
29 # define TRACE(x...) ;
30 #endif
31
32 #define ERROR(x...) _sPrintf("radeon_hd: " x)
33
34
35 static void
gpio_lock_i2c(void * cookie,bool lock)36 gpio_lock_i2c(void* cookie, bool lock)
37 {
38 gpio_info* info = (gpio_info*)cookie;
39
40 uint32 buffer = 0;
41
42 if (lock == true) {
43 // hwCapable and > DCE3
44 if (info->i2c.hwCapable == true && gInfo->shared_info->dceMajor >= 3) {
45 // Switch GPIO pads to ddc mode
46 buffer = Read32(OUT, info->i2c.sclMaskReg);
47 buffer &= ~(1 << 16);
48 Write32(OUT, info->i2c.sclMaskReg, buffer);
49 }
50
51 // Clear pins
52 buffer = Read32(OUT, info->i2c.sclAReg) & ~info->i2c.sclAMask;
53 Write32(OUT, info->i2c.sclAReg, buffer);
54 buffer = Read32(OUT, info->i2c.sdaAReg) & ~info->i2c.sdaAMask;
55 Write32(OUT, info->i2c.sdaAReg, buffer);
56 }
57
58 // Set pins to input
59 buffer = Read32(OUT, info->i2c.sclEnReg) & ~info->i2c.sclEnMask;
60 Write32(OUT, info->i2c.sclEnReg, buffer);
61 buffer = Read32(OUT, info->i2c.sdaEnReg) & ~info->i2c.sdaEnMask;
62 Write32(OUT, info->i2c.sdaEnReg, buffer);
63
64 // mask clock GPIO pins for software use
65 buffer = Read32(OUT, info->i2c.sclMaskReg);
66 if (lock == true)
67 buffer |= info->i2c.sclMask;
68 else
69 buffer &= ~info->i2c.sclMask;
70
71 Write32(OUT, info->i2c.sclMaskReg, buffer);
72 Read32(OUT, info->i2c.sclMaskReg);
73
74 // mask data GPIO pins for software use
75 buffer = Read32(OUT, info->i2c.sdaMaskReg);
76 if (lock == true)
77 buffer |= info->i2c.sdaMask;
78 else
79 buffer &= ~info->i2c.sdaMask;
80
81 Write32(OUT, info->i2c.sdaMaskReg, buffer);
82 Read32(OUT, info->i2c.sdaMaskReg);
83 }
84
85
86 static status_t
gpio_get_i2c_bit(void * cookie,int * _clock,int * _data)87 gpio_get_i2c_bit(void* cookie, int* _clock, int* _data)
88 {
89 gpio_info* info = (gpio_info*)cookie;
90
91 uint32 scl = Read32(OUT, info->i2c.sclYReg) & info->i2c.sclYMask;
92 uint32 sda = Read32(OUT, info->i2c.sdaYReg) & info->i2c.sdaYMask;
93
94 *_clock = scl != 0;
95 *_data = sda != 0;
96
97 return B_OK;
98 }
99
100
101 static status_t
gpio_set_i2c_bit(void * cookie,int clock,int data)102 gpio_set_i2c_bit(void* cookie, int clock, int data)
103 {
104 gpio_info* info = (gpio_info*)cookie;
105
106 uint32 scl = Read32(OUT, info->i2c.sclEnReg) & ~info->i2c.sclEnMask;
107 scl |= clock ? 0 : info->i2c.sclEnMask;
108 Write32(OUT, info->i2c.sclEnReg, scl);
109 Read32(OUT, info->i2c.sclEnReg);
110
111 uint32 sda = Read32(OUT, info->i2c.sdaEnReg) & ~info->i2c.sdaEnMask;
112 sda |= data ? 0 : info->i2c.sdaEnMask;
113 Write32(OUT, info->i2c.sdaEnReg, sda);
114 Read32(OUT, info->i2c.sdaEnReg);
115
116 return B_OK;
117 }
118
119
120 uint16
connector_pick_atom_hpdid(uint32 connectorIndex)121 connector_pick_atom_hpdid(uint32 connectorIndex)
122 {
123 radeon_shared_info &info = *gInfo->shared_info;
124
125 uint16 atomHPDID = 0xff;
126 uint16 hpdPinIndex = gConnector[connectorIndex]->hpdPinIndex;
127 if (info.dceMajor >= 4
128 && gGPIOInfo[hpdPinIndex]->valid) {
129
130 // See mmDC_GPIO_HPD_A in drm for register value
131 uint32 targetReg = AVIVO_DC_GPIO_HPD_A;
132 if (info.dceMajor >= 13) {
133 ERROR("WARNING: CHECK NEW DCE mmDC_GPIO_HPD_A value!\n");
134 targetReg = POL_mmDC_GPIO_HPD_A;
135 } else if (info.dceMajor >= 12)
136 targetReg = POL_mmDC_GPIO_HPD_A;
137 else if (info.dceMajor >= 11)
138 targetReg = CAR_mmDC_GPIO_HPD_A;
139 else if (info.dceMajor >= 10)
140 targetReg = VOL_mmDC_GPIO_HPD_A;
141 else if (info.dceMajor >= 8)
142 targetReg = SEA_mmDC_GPIO_HPD_A;
143 else if (info.dceMajor >= 6)
144 targetReg = SI_DC_GPIO_HPD_A;
145 else if (info.dceMajor >= 4)
146 targetReg = EVERGREEN_DC_GPIO_HPD_A;
147
148 // You're drunk AMD, go home. (this makes no sense)
149 if (gGPIOInfo[hpdPinIndex]->hwReg == targetReg) {
150 switch(gGPIOInfo[hpdPinIndex]->hwMask) {
151 case (1 << 0):
152 atomHPDID = 0;
153 break;
154 case (1 << 8):
155 atomHPDID = 1;
156 break;
157 case (1 << 16):
158 atomHPDID = 2;
159 break;
160 case (1 << 24):
161 atomHPDID = 3;
162 break;
163 case (1 << 26):
164 atomHPDID = 4;
165 break;
166 case (1 << 28):
167 atomHPDID = 5;
168 break;
169 }
170 }
171 }
172 return atomHPDID;
173 }
174
175
176 bool
connector_read_edid(uint32 connectorIndex,edid1_info * edid)177 connector_read_edid(uint32 connectorIndex, edid1_info* edid)
178 {
179 // ensure things are sane
180 uint32 i2cPinIndex = gConnector[connectorIndex]->i2cPinIndex;
181 if (gGPIOInfo[i2cPinIndex]->valid == false
182 || gGPIOInfo[i2cPinIndex]->i2c.valid == false) {
183 ERROR("%s: invalid gpio %" B_PRIu32 " for connector %" B_PRIu32 "\n",
184 __func__, i2cPinIndex, connectorIndex);
185 return false;
186 }
187
188 i2c_bus bus;
189
190 ddc2_init_timing(&bus);
191 bus.cookie = (void*)gGPIOInfo[i2cPinIndex];
192 bus.set_signals = &gpio_set_i2c_bit;
193 bus.get_signals = &gpio_get_i2c_bit;
194
195 gpio_lock_i2c(bus.cookie, true);
196 status_t edid_result = ddc2_read_edid1(&bus, edid, NULL, NULL);
197 gpio_lock_i2c(bus.cookie, false);
198
199 if (edid_result != B_OK)
200 return false;
201
202 TRACE("%s: found edid monitor on connector #%" B_PRId32 "\n",
203 __func__, connectorIndex);
204
205 return true;
206 }
207
208
209 bool
connector_read_mode_lvds(uint32 connectorIndex,display_mode * mode)210 connector_read_mode_lvds(uint32 connectorIndex, display_mode* mode)
211 {
212 assert(mode);
213
214 uint8 dceMajor;
215 uint8 dceMinor;
216 int index = GetIndexIntoMasterTable(DATA, LVDS_Info);
217 uint16 offset;
218
219 union atomLVDSInfo {
220 struct _ATOM_LVDS_INFO info;
221 struct _ATOM_LVDS_INFO_V12 info_12;
222 };
223
224 // Wipe out display_mode
225 memset(mode, 0, sizeof(display_mode));
226
227 if (atom_parse_data_header(gAtomContext, index, NULL,
228 &dceMajor, &dceMinor, &offset) == B_OK) {
229
230 union atomLVDSInfo* lvdsInfo
231 = (union atomLVDSInfo*)(gAtomContext->bios + offset);
232
233 display_timing* timing = &mode->timing;
234
235 // Pixel Clock
236 timing->pixel_clock
237 = B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usPixClk) * 10;
238 // Horizontal
239 timing->h_display
240 = B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usHActive);
241 timing->h_total = timing->h_display + B_LENDIAN_TO_HOST_INT16(
242 lvdsInfo->info.sLCDTiming.usHBlanking_Time);
243 timing->h_sync_start = timing->h_display
244 + B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usHSyncOffset);
245 timing->h_sync_end = timing->h_sync_start
246 + B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usHSyncWidth);
247 // Vertical
248 timing->v_display
249 = B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usVActive);
250 timing->v_total = timing->v_display + B_LENDIAN_TO_HOST_INT16(
251 lvdsInfo->info.sLCDTiming.usVBlanking_Time);
252 timing->v_sync_start = timing->v_display
253 + B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usVSyncOffset);
254 timing->v_sync_end = timing->v_sync_start
255 + B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usVSyncWidth);
256
257 #if 0
258 // Who cares.
259 uint32 powerDelay
260 = B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.usOffDelayInMs);
261 #endif
262
263 // Store special lvds flags the encoder setup needs
264 gConnector[connectorIndex]->lvdsFlags = lvdsInfo->info.ucLVDS_Misc;
265
266 // Spread Spectrum ID (in SS table)
267 gInfo->lvdsSpreadSpectrumID = lvdsInfo->info.ucSS_Id;
268
269 uint16 flags = B_LENDIAN_TO_HOST_INT16(
270 lvdsInfo->info.sLCDTiming.susModeMiscInfo.usAccess);
271
272 if ((flags & ATOM_VSYNC_POLARITY) == 0)
273 timing->flags |= B_POSITIVE_VSYNC;
274 if ((flags & ATOM_HSYNC_POLARITY) == 0)
275 timing->flags |= B_POSITIVE_HSYNC;
276
277 // Extra flags
278 if ((flags & ATOM_INTERLACE) != 0)
279 timing->flags |= B_TIMING_INTERLACED;
280
281 #if 0
282 // We don't use these timing flags at the moment
283 if ((flags & ATOM_COMPOSITESYNC) != 0)
284 timing->flags |= MODE_FLAG_CSYNC;
285 if ((flags & ATOM_DOUBLE_CLOCK_MODE) != 0)
286 timing->flags |= MODE_FLAG_DBLSCAN;
287 #endif
288
289 mode->h_display_start = 0;
290 mode->v_display_start = 0;
291 mode->virtual_width = timing->h_display;
292 mode->virtual_height = timing->v_display;
293
294 // Assume 32-bit color
295 mode->space = B_RGB32_LITTLE;
296
297 TRACE("%s: %" B_PRIu32 " %" B_PRIu16 " %" B_PRIu16 " %" B_PRIu16
298 " %" B_PRIu16 " %" B_PRIu16 " %" B_PRIu16 " %" B_PRIu16
299 " %" B_PRIu16 "\n", __func__, timing->pixel_clock,
300 timing->h_display, timing->h_sync_start, timing->h_sync_end,
301 timing->h_total, timing->v_display, timing->v_sync_start,
302 timing->v_sync_end, timing->v_total);
303
304 return true;
305 }
306 return false;
307 }
308
309
310 static status_t
connector_attach_gpio_i2c(uint32 connectorIndex,uint8 hwPin)311 connector_attach_gpio_i2c(uint32 connectorIndex, uint8 hwPin)
312 {
313 gConnector[connectorIndex]->i2cPinIndex = 0;
314 for (uint32 i = 0; i < MAX_GPIO_PINS; i++) {
315 if (gGPIOInfo[i]->hwPin != hwPin)
316 continue;
317 gConnector[connectorIndex]->i2cPinIndex = i;
318 return B_OK;
319 }
320
321 // We couldnt find the GPIO pin in the known GPIO pins.
322 TRACE("%s: can't find GPIO pin 0x%" B_PRIX8 " for connector %" B_PRIu32 "\n",
323 __func__, hwPin, connectorIndex);
324 return B_ERROR;
325 }
326
327
328 static status_t
connector_attach_gpio_router(uint32 connectorIndex,uint8 hwPin)329 connector_attach_gpio_router(uint32 connectorIndex, uint8 hwPin)
330 {
331 gConnector[connectorIndex]->router.i2cPinIndex = 0;
332 for (uint32 i = 0; i < MAX_GPIO_PINS; i++) {
333 if (gGPIOInfo[i]->hwPin != hwPin)
334 continue;
335 gConnector[connectorIndex]->router.i2cPinIndex = i;
336 return B_OK;
337 }
338
339 // We couldnt find the GPIO pin in the known GPIO pins.
340 TRACE("%s: can't find GPIO pin 0x%" B_PRIX8 " for connector %" B_PRIu32 "\n",
341 __func__, hwPin, connectorIndex);
342 return B_ERROR;
343 }
344
345
346 static status_t
connector_attach_gpio_hpd(uint32 connectorIndex,uint8 hwPin)347 connector_attach_gpio_hpd(uint32 connectorIndex, uint8 hwPin)
348 {
349 gConnector[connectorIndex]->hpdPinIndex = 0;
350
351 for (uint32 i = 0; i < MAX_GPIO_PINS; i++) {
352 if (gGPIOInfo[i]->hwPin != hwPin)
353 continue;
354 gConnector[connectorIndex]->hpdPinIndex = i;
355 return B_OK;
356 }
357
358 // We couldnt find the GPIO pin in the known GPIO pins.
359 TRACE("%s: can't find GPIO pin 0x%" B_PRIX8 " for connector %" B_PRIu32 "\n",
360 __func__, hwPin, connectorIndex);
361 return B_ERROR;
362 }
363
364
365 static status_t
gpio_general_populate()366 gpio_general_populate()
367 {
368 int index = GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT);
369 uint16 tableOffset;
370 uint16 tableSize;
371
372 struct _ATOM_GPIO_PIN_LUT* gpioInfo;
373
374 if (atom_parse_data_header(gAtomContext, index, &tableSize, NULL, NULL,
375 &tableOffset)) {
376 ERROR("%s: could't read GPIO_Pin_LUT table from AtomBIOS index %d!\n",
377 __func__, index);
378 }
379 gpioInfo = (struct _ATOM_GPIO_PIN_LUT*)(gAtomContext->bios + tableOffset);
380
381 int numIndices = (tableSize - sizeof(ATOM_COMMON_TABLE_HEADER)) /
382 sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
383
384 // Find the next available GPIO pin index
385 int32 gpioIndex = -1;
386 for(int32 pin = 0; pin < MAX_GPIO_PINS; pin++) {
387 if (!gGPIOInfo[pin]->valid) {
388 gpioIndex = pin;
389 break;
390 }
391 }
392 if (gpioIndex < 0) {
393 ERROR("%s: ERROR: Out of space for additional GPIO pins!\n", __func__);
394 return B_ERROR;
395 }
396
397 ATOM_GPIO_PIN_ASSIGNMENT* pin = gpioInfo->asGPIO_Pin;
398 for (int i = 0; i < numIndices; i++) {
399 if (gGPIOInfo[gpioIndex]->valid) {
400 ERROR("%s: BUG: Attempting to fill already populated gpio pin!\n",
401 __func__);
402 return B_ERROR;
403 }
404 gGPIOInfo[gpioIndex]->valid = true;
405 gGPIOInfo[gpioIndex]->i2c.valid = false;
406 gGPIOInfo[gpioIndex]->hwPin = pin->ucGPIO_ID;
407 gGPIOInfo[gpioIndex]->hwReg
408 = B_LENDIAN_TO_HOST_INT16(pin->usGpioPin_AIndex) * 4;
409 gGPIOInfo[gpioIndex]->hwMask
410 = (1 << pin->ucGpioPinBitShift);
411 pin = (ATOM_GPIO_PIN_ASSIGNMENT*)((uint8*)pin
412 + sizeof(ATOM_GPIO_PIN_ASSIGNMENT));
413
414 TRACE("%s: general GPIO @ %" B_PRId32 ", valid: %s, "
415 "hwPin: 0x%" B_PRIX32 "\n", __func__, gpioIndex,
416 gGPIOInfo[gpioIndex]->valid ? "true" : "false",
417 gGPIOInfo[gpioIndex]->hwPin);
418
419 gpioIndex++;
420 }
421 return B_OK;
422 }
423
424
425 static status_t
gpio_i2c_populate()426 gpio_i2c_populate()
427 {
428 radeon_shared_info &info = *gInfo->shared_info;
429
430 int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
431 uint16 tableOffset;
432 uint16 tableSize;
433
434 if (atom_parse_data_header(gAtomContext, index, &tableSize,
435 NULL, NULL, &tableOffset) != B_OK) {
436 ERROR("%s: could't read GPIO_I2C_Info table from AtomBIOS index %d!\n",
437 __func__, index);
438 return B_ERROR;
439 }
440
441 struct _ATOM_GPIO_I2C_INFO* i2cInfo
442 = (struct _ATOM_GPIO_I2C_INFO*)(gAtomContext->bios + tableOffset);
443
444 uint32 numIndices = (tableSize - sizeof(ATOM_COMMON_TABLE_HEADER))
445 / sizeof(ATOM_GPIO_I2C_ASSIGMENT);
446
447 if (numIndices > ATOM_MAX_SUPPORTED_DEVICE) {
448 ERROR("%s: ERROR: AtomBIOS contains more GPIO_Info items then I"
449 "was prepared for! (seen: %" B_PRIu32 "; max: %" B_PRIu32 ")\n",
450 __func__, numIndices, (uint32)ATOM_MAX_SUPPORTED_DEVICE);
451 return B_ERROR;
452 }
453
454 // Find the next available GPIO pin index
455 int32 gpioIndex = -1;
456 for(int32 pin = 0; pin < MAX_GPIO_PINS; pin++) {
457 if (!gGPIOInfo[pin]->valid) {
458 gpioIndex = pin;
459 break;
460 }
461 }
462 if (gpioIndex < 0) {
463 ERROR("%s: ERROR: Out of space for additional GPIO pins!\n", __func__);
464 return B_ERROR;
465 }
466
467 for (uint32 i = 0; i < numIndices; i++) {
468 if (gGPIOInfo[gpioIndex]->valid) {
469 ERROR("%s: BUG: Attempting to fill already populated gpio pin!\n",
470 __func__);
471 return B_ERROR;
472 }
473 ATOM_GPIO_I2C_ASSIGMENT* gpio = &i2cInfo->asGPIO_Info[i];
474
475 if (info.dceMajor >= 3) {
476 if (i == 4 && B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex)
477 == 0x1fda && gpio->sucI2cId.ucAccess == 0x94) {
478 gpio->sucI2cId.ucAccess = 0x14;
479 TRACE("%s: BUG: GPIO override for DCE 3 occured\n", __func__);
480 }
481 }
482
483 if (info.dceMajor >= 4) {
484 if (i == 7 && B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex)
485 == 0x1936 && gpio->sucI2cId.ucAccess == 0) {
486 gpio->sucI2cId.ucAccess = 0x97;
487 gpio->ucDataMaskShift = 8;
488 gpio->ucDataEnShift = 8;
489 gpio->ucDataY_Shift = 8;
490 gpio->ucDataA_Shift = 8;
491 TRACE("%s: BUG: GPIO override for DCE 4 occured\n", __func__);
492 }
493 }
494
495 // populate gpio information
496 gGPIOInfo[gpioIndex]->hwPin = gpio->sucI2cId.ucAccess;
497 gGPIOInfo[gpioIndex]->i2c.hwCapable
498 = (gpio->sucI2cId.sbfAccess.bfHW_Capable) ? true : false;
499
500 // GPIO mask (Allows software to control the GPIO pad)
501 // 0 = chip access; 1 = only software;
502 gGPIOInfo[gpioIndex]->i2c.sclMaskReg
503 = B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex) * 4;
504 gGPIOInfo[gpioIndex]->i2c.sdaMaskReg
505 = B_LENDIAN_TO_HOST_INT16(gpio->usDataMaskRegisterIndex) * 4;
506 gGPIOInfo[gpioIndex]->i2c.sclMask = 1 << gpio->ucClkMaskShift;
507 gGPIOInfo[gpioIndex]->i2c.sdaMask = 1 << gpio->ucDataMaskShift;
508
509 // GPIO output / write (A) enable
510 // 0 = GPIO input (Y); 1 = GPIO output (A);
511 gGPIOInfo[gpioIndex]->i2c.sclEnReg
512 = B_LENDIAN_TO_HOST_INT16(gpio->usClkEnRegisterIndex) * 4;
513 gGPIOInfo[gpioIndex]->i2c.sdaEnReg
514 = B_LENDIAN_TO_HOST_INT16(gpio->usDataEnRegisterIndex) * 4;
515 gGPIOInfo[gpioIndex]->i2c.sclEnMask = 1 << gpio->ucClkEnShift;
516 gGPIOInfo[gpioIndex]->i2c.sdaEnMask = 1 << gpio->ucDataEnShift;
517
518 // GPIO output / write (A)
519 gGPIOInfo[gpioIndex]->i2c.sclAReg
520 = B_LENDIAN_TO_HOST_INT16(gpio->usClkA_RegisterIndex) * 4;
521 gGPIOInfo[gpioIndex]->i2c.sdaAReg
522 = B_LENDIAN_TO_HOST_INT16(gpio->usDataA_RegisterIndex) * 4;
523 gGPIOInfo[gpioIndex]->i2c.sclAMask = 1 << gpio->ucClkA_Shift;
524 gGPIOInfo[gpioIndex]->i2c.sdaAMask = 1 << gpio->ucDataA_Shift;
525
526 // GPIO input / read (Y)
527 gGPIOInfo[gpioIndex]->i2c.sclYReg
528 = B_LENDIAN_TO_HOST_INT16(gpio->usClkY_RegisterIndex) * 4;
529 gGPIOInfo[gpioIndex]->i2c.sdaYReg
530 = B_LENDIAN_TO_HOST_INT16(gpio->usDataY_RegisterIndex) * 4;
531 gGPIOInfo[gpioIndex]->i2c.sclYMask = 1 << gpio->ucClkY_Shift;
532 gGPIOInfo[gpioIndex]->i2c.sdaYMask = 1 << gpio->ucDataY_Shift;
533
534 // ensure data is valid
535 gGPIOInfo[gpioIndex]->i2c.valid
536 = gGPIOInfo[gpioIndex]->i2c.sclMaskReg ? true : false;
537 gGPIOInfo[gpioIndex]->valid = gGPIOInfo[gpioIndex]->i2c.valid;
538
539 TRACE("%s: i2c GPIO @ %" B_PRIu32 ", valid: %s, hwPin: 0x%" B_PRIX32 "\n",
540 __func__, gpioIndex, gGPIOInfo[gpioIndex]->valid ? "true" : "false",
541 gGPIOInfo[gpioIndex]->hwPin);
542
543 gpioIndex++;
544 }
545
546 return B_OK;
547 }
548
549
550 status_t
gpio_populate()551 gpio_populate()
552 {
553 status_t result = gpio_general_populate();
554 if (result != B_OK)
555 return result;
556
557 result = gpio_i2c_populate();
558 return result;
559 }
560
561
562 status_t
connector_probe_legacy()563 connector_probe_legacy()
564 {
565 int index = GetIndexIntoMasterTable(DATA, SupportedDevicesInfo);
566 uint8 tableMajor;
567 uint8 tableMinor;
568 uint16 tableSize;
569 uint16 tableOffset;
570
571 if (atom_parse_data_header(gAtomContext, index, &tableSize,
572 &tableMajor, &tableMinor, &tableOffset) != B_OK) {
573 ERROR("%s: unable to parse data header!\n", __func__);
574 return B_ERROR;
575 }
576
577 union atomSupportedDevices {
578 struct _ATOM_SUPPORTED_DEVICES_INFO info;
579 struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2;
580 struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1;
581 };
582 union atomSupportedDevices* supportedDevices;
583 supportedDevices = (union atomSupportedDevices*)
584 (gAtomContext->bios + tableOffset);
585
586 uint16 deviceSupport
587 = B_LENDIAN_TO_HOST_INT16(supportedDevices->info.usDeviceSupport);
588
589 uint32 maxDevice;
590
591 if (tableMajor > 1)
592 maxDevice = ATOM_MAX_SUPPORTED_DEVICE;
593 else
594 maxDevice = ATOM_MAX_SUPPORTED_DEVICE_INFO;
595
596 uint32 i;
597 uint32 connectorIndex = 0;
598 for (i = 0; i < maxDevice; i++) {
599
600 gConnector[connectorIndex]->valid = false;
601
602 // check if this connector is used
603 if ((deviceSupport & (1 << i)) == 0)
604 continue;
605
606 if (i == ATOM_DEVICE_CV_INDEX) {
607 TRACE("%s: skipping component video\n",
608 __func__);
609 continue;
610 }
611
612 ATOM_CONNECTOR_INFO_I2C ci
613 = supportedDevices->info.asConnInfo[i];
614
615 gConnector[connectorIndex]->type = kConnectorConvertLegacy[
616 ci.sucConnectorInfo.sbfAccess.bfConnectorType];
617
618 if (gConnector[connectorIndex]->type == VIDEO_CONNECTOR_UNKNOWN) {
619 TRACE("%s: skipping unknown connector at %" B_PRId32
620 " of 0x%" B_PRIX8 "\n", __func__, i,
621 ci.sucConnectorInfo.sbfAccess.bfConnectorType);
622 continue;
623 }
624
625 // TODO: give tv unique connector ids
626
627 // Always set CRT1 and CRT2 as VGA, some cards incorrectly set
628 // VGA ports as DVI
629 if (i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX)
630 gConnector[connectorIndex]->type = VIDEO_CONNECTOR_VGA;
631
632 uint8 dac = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC;
633 uint32 encoderObject = encoder_object_lookup((1 << i), dac);
634 uint32 encoderID = (encoderObject & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
635
636 gConnector[connectorIndex]->valid = true;
637 gConnector[connectorIndex]->flags = (1 << i);
638 gConnector[connectorIndex]->encoder.valid = true;
639 gConnector[connectorIndex]->encoder.objectID = encoderID;
640 gConnector[connectorIndex]->encoder.type
641 = encoder_type_lookup(encoderID, (1 << i));
642
643 // TODO: Eval external encoders on legacy connector probe
644 gConnector[connectorIndex]->encoderExternal.valid = false;
645 // encoder_is_external(encoderID);
646
647 connector_attach_gpio_i2c(connectorIndex, ci.sucI2cId.ucAccess);
648
649 pll_limit_probe(&gConnector[connectorIndex]->encoder.pll);
650
651 connectorIndex++;
652 }
653
654 // TODO: combine shared connectors
655
656 if (connectorIndex == 0) {
657 TRACE("%s: zero connectors found using legacy detection\n", __func__);
658 return B_ERROR;
659 }
660
661 return B_OK;
662 }
663
664
665 // r600+
666 status_t
connector_probe()667 connector_probe()
668 {
669 int index = GetIndexIntoMasterTable(DATA, Object_Header);
670 uint8 tableMajor;
671 uint8 tableMinor;
672 uint16 tableSize;
673 uint16 tableOffset;
674
675 if (atom_parse_data_header(gAtomContext, index, &tableSize,
676 &tableMajor, &tableMinor, &tableOffset) != B_OK) {
677 ERROR("%s: ERROR: parsing data header failed!\n", __func__);
678 return B_ERROR;
679 }
680
681 if (tableMinor < 2) {
682 ERROR("%s: ERROR: table minor version unknown! "
683 "(%" B_PRIu8 ".%" B_PRIu8 ")\n", __func__, tableMajor, tableMinor);
684 return B_ERROR;
685 }
686
687 ATOM_CONNECTOR_OBJECT_TABLE* connectorObject;
688 ATOM_ENCODER_OBJECT_TABLE* encoderObject;
689 ATOM_OBJECT_TABLE* routerObject;
690 ATOM_DISPLAY_OBJECT_PATH_TABLE* pathObject;
691 ATOM_OBJECT_HEADER* objectHeader;
692
693 objectHeader = (ATOM_OBJECT_HEADER*)(gAtomContext->bios + tableOffset);
694 pathObject = (ATOM_DISPLAY_OBJECT_PATH_TABLE*)
695 (gAtomContext->bios + tableOffset
696 + B_LENDIAN_TO_HOST_INT16(objectHeader->usDisplayPathTableOffset));
697 connectorObject = (ATOM_CONNECTOR_OBJECT_TABLE*)
698 (gAtomContext->bios + tableOffset
699 + B_LENDIAN_TO_HOST_INT16(objectHeader->usConnectorObjectTableOffset));
700 encoderObject = (ATOM_ENCODER_OBJECT_TABLE*)
701 (gAtomContext->bios + tableOffset
702 + B_LENDIAN_TO_HOST_INT16(objectHeader->usEncoderObjectTableOffset));
703 routerObject = (ATOM_OBJECT_TABLE*)
704 (gAtomContext->bios + tableOffset
705 + B_LENDIAN_TO_HOST_INT16(objectHeader->usRouterObjectTableOffset));
706 int deviceSupport = B_LENDIAN_TO_HOST_INT16(objectHeader->usDeviceSupport);
707
708 int pathSize = 0;
709 int32 i = 0;
710
711 TRACE("%s: found %" B_PRIu8 " potential display paths.\n", __func__,
712 pathObject->ucNumOfDispPath);
713
714 uint32 connectorIndex = 0;
715 for (i = 0; i < pathObject->ucNumOfDispPath; i++) {
716
717 if (connectorIndex >= ATOM_MAX_SUPPORTED_DEVICE)
718 continue;
719
720 uint8* address = (uint8*)pathObject->asDispPath;
721 ATOM_DISPLAY_OBJECT_PATH* path;
722 address += pathSize;
723 path = (ATOM_DISPLAY_OBJECT_PATH*)address;
724 pathSize += B_LENDIAN_TO_HOST_INT16(path->usSize);
725
726 uint32 connectorType;
727 uint16 connectorFlags = B_LENDIAN_TO_HOST_INT16(path->usDeviceTag);
728
729 if ((deviceSupport & connectorFlags) != 0) {
730
731 uint16 connectorObjectID
732 = (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
733 & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
734 //uint8 con_obj_num
735 // = (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
736 // & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
737 //uint8 con_obj_type
738 // = (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
739 // & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
740
741 if (connectorFlags == ATOM_DEVICE_CV_SUPPORT) {
742 TRACE("%s: Path #%" B_PRId32 ": skipping component video.\n",
743 __func__, i);
744 continue;
745 }
746
747 radeon_shared_info &info = *gInfo->shared_info;
748
749 // protect kConnectorConvert
750 if (connectorObjectID >= B_COUNT_OF(kConnectorConvert)) {
751 // This can happen when new atombios revisions introduce
752 // new CONNECTOR_OBJECT_ID_* defines (rare)
753 ERROR("%s: Path #%" B_PRId32 ": Unknown connector object ID!\n",
754 __func__, i);
755 continue;
756 }
757
758 uint16 igpLaneInfo;
759 if ((info.chipsetFlags & CHIP_IGP) != 0) {
760 ERROR("%s: TODO: IGP chip connector detection\n", __func__);
761 // try non-IGP method for now
762 igpLaneInfo = 0;
763 connectorType = kConnectorConvert[connectorObjectID];
764 } else {
765 igpLaneInfo = 0;
766 connectorType = kConnectorConvert[connectorObjectID];
767 }
768
769 if (connectorType == VIDEO_CONNECTOR_UNKNOWN) {
770 ERROR("%s: Path #%" B_PRId32 ": skipping unknown connector.\n",
771 __func__, i);
772 continue;
773 }
774
775 connector_info* connector = gConnector[connectorIndex];
776
777 int32 j;
778 for (j = 0; j < ((B_LENDIAN_TO_HOST_INT16(path->usSize) - 8) / 2);
779 j++) {
780 //uint16 grph_obj_id
781 // = (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j])
782 // & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
783 //uint8 grph_obj_num
784 // = (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) &
785 // ENUM_ID_MASK) >> ENUM_ID_SHIFT;
786 uint8 graphicObjectType
787 = (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) &
788 OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
789
790 if (graphicObjectType == GRAPH_OBJECT_TYPE_ENCODER) {
791 // Found an encoder
792 int32 k;
793 for (k = 0; k < encoderObject->ucNumberOfObjects; k++) {
794 uint16 encoderObjectRaw
795 = B_LENDIAN_TO_HOST_INT16(
796 encoderObject->asObjects[k].usObjectID);
797 if (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j])
798 == encoderObjectRaw) {
799 ATOM_COMMON_RECORD_HEADER* record
800 = (ATOM_COMMON_RECORD_HEADER*)
801 ((uint16*)gAtomContext->bios + tableOffset
802 + B_LENDIAN_TO_HOST_INT16(
803 encoderObject->asObjects[k].usRecordOffset));
804 ATOM_ENCODER_CAP_RECORD* capRecord;
805 uint16 caps = 0;
806 while (record->ucRecordSize > 0
807 && record->ucRecordType > 0
808 && record->ucRecordType
809 <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
810 switch (record->ucRecordType) {
811 case ATOM_ENCODER_CAP_RECORD_TYPE:
812 capRecord = (ATOM_ENCODER_CAP_RECORD*)
813 record;
814 caps = B_LENDIAN_TO_HOST_INT16(
815 capRecord->usEncoderCap);
816 break;
817 }
818 record = (ATOM_COMMON_RECORD_HEADER*)
819 ((char*)record + record->ucRecordSize);
820 }
821
822 uint32 encoderID
823 = (encoderObjectRaw & OBJECT_ID_MASK)
824 >> OBJECT_ID_SHIFT;
825
826 uint32 encoderType = encoder_type_lookup(encoderID,
827 connectorFlags);
828
829 if (encoderType == VIDEO_ENCODER_NONE) {
830 ERROR("%s: Path #%" B_PRId32 ":"
831 "skipping unknown encoder.\n",
832 __func__, i);
833 continue;
834 }
835
836 encoder_info* encoder;
837
838 // External encoders are behind DVO or UNIPHY
839 if (encoder_is_external(encoderID)) {
840 encoder = &connector->encoderExternal;
841 encoder->isExternal = true;
842 encoder->isDPBridge
843 = encoder_is_dp_bridge(encoderID);
844 } else {
845 encoder = &connector->encoder;
846 encoder->isExternal = false;
847 encoder->isDPBridge = false;
848 }
849
850 // Set up found connector encoder generics
851 encoder->valid = true;
852 encoder->capabilities = caps;
853 encoder->objectID = encoderID;
854 encoder->type = encoderType;
855 encoder->linkEnumeration
856 = (encoderObjectRaw & ENUM_ID_MASK)
857 >> ENUM_ID_SHIFT;
858 pll_limit_probe(&encoder->pll);
859 }
860 }
861 // END if object is encoder
862 } else if (graphicObjectType == GRAPH_OBJECT_TYPE_ROUTER) {
863 int32 k;
864 for (k = 0; k < routerObject->ucNumberOfObjects; k++) {
865 uint16 routerObjectID
866 = B_LENDIAN_TO_HOST_INT16(routerObject->asObjects[k].usObjectID);
867 if (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) == routerObjectID) {
868 ATOM_COMMON_RECORD_HEADER* record = (ATOM_COMMON_RECORD_HEADER*)
869 ((uint16*)gAtomContext->bios + tableOffset
870 + B_LENDIAN_TO_HOST_INT16(
871 routerObject->asObjects[k].usRecordOffset));
872 ATOM_I2C_RECORD* i2cRecord;
873 ATOM_I2C_ID_CONFIG_ACCESS* i2cConfig;
874 ATOM_ROUTER_DDC_PATH_SELECT_RECORD* ddcPath;
875 ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD* cdPath;
876 ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT* routerConnTable
877 = (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
878 ((uint16*)gAtomContext->bios + tableOffset
879 + B_LENDIAN_TO_HOST_INT16(
880 routerObject->asObjects[k].usSrcDstTableOffset));
881 uint8* destObjCount = (uint8*)((uint8*)routerConnTable + 1
882 + (routerConnTable->ucNumberOfSrc * 2));
883 uint16 *dstObjs = (uint16 *)(destObjCount + 1);
884
885 int enumId;
886 router_info* router = &connector->router;
887 router->objectID = routerObjectID;
888 for (enumId = 0; enumId < (*destObjCount); enumId++) {
889 if (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
890 == B_LENDIAN_TO_HOST_INT16(dstObjs[enumId]))
891 break;
892 }
893 while (record->ucRecordSize > 0 &&
894 record->ucRecordType > 0 &&
895 record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
896 switch (record->ucRecordType) {
897 case ATOM_I2C_RECORD_TYPE:
898 i2cRecord = (ATOM_I2C_RECORD*)record;
899 i2cConfig
900 = (ATOM_I2C_ID_CONFIG_ACCESS*)&i2cRecord->sucI2cId;
901 connector_attach_gpio_router(connectorIndex,
902 i2cConfig->ucAccess);
903 router->i2cAddr = i2cRecord->ucI2CAddr >> 1; // ??
904 break;
905 case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
906 ddcPath = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD*)record;
907 router->ddcValid = true;
908 router->ddcMuxType = ddcPath->ucMuxType;
909 router->ddcMuxControlPin = ddcPath->ucMuxControlPin;
910 router->ddcMuxState = ddcPath->ucMuxState[enumId];
911 break;
912 case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE:
913 cdPath
914 = (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *)record;
915 router->cdValid = true;
916 router->cdMuxType = cdPath->ucMuxType;
917 router->cdMuxControlPin = cdPath->ucMuxControlPin;
918 router->cdMuxState = cdPath->ucMuxState[enumId];
919 break;
920 }
921
922 // move to next record
923 record = (ATOM_COMMON_RECORD_HEADER*)
924 ((char *)record + record->ucRecordSize);
925 }
926 }
927 }
928 } // END if object is router
929 }
930
931 // Set up information buses such as ddc
932 if (((connectorFlags & ATOM_DEVICE_TV_SUPPORT) == 0)
933 && (connectorFlags & ATOM_DEVICE_CV_SUPPORT) == 0) {
934 for (j = 0; j < connectorObject->ucNumberOfObjects; j++) {
935 if (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
936 == B_LENDIAN_TO_HOST_INT16(
937 connectorObject->asObjects[j].usObjectID)) {
938 ATOM_COMMON_RECORD_HEADER* record
939 = (ATOM_COMMON_RECORD_HEADER*)(gAtomContext->bios
940 + tableOffset + B_LENDIAN_TO_HOST_INT16(
941 connectorObject->asObjects[j].usRecordOffset));
942 while (record->ucRecordSize > 0
943 && record->ucRecordType > 0
944 && record->ucRecordType
945 <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
946 ATOM_I2C_RECORD* i2cRecord;
947 ATOM_I2C_ID_CONFIG_ACCESS* i2cConfig;
948 ATOM_HPD_INT_RECORD* hpdRecord;
949
950 switch (record->ucRecordType) {
951 case ATOM_I2C_RECORD_TYPE:
952 i2cRecord
953 = (ATOM_I2C_RECORD*)record;
954 i2cConfig
955 = (ATOM_I2C_ID_CONFIG_ACCESS*)
956 &i2cRecord->sucI2cId;
957 connector_attach_gpio_i2c(connectorIndex,
958 i2cConfig->ucAccess);
959 break;
960 case ATOM_HPD_INT_RECORD_TYPE:
961 hpdRecord = (ATOM_HPD_INT_RECORD*)record;
962 connector_attach_gpio_hpd(connectorIndex,
963 hpdRecord->ucHPDIntGPIOID);
964 break;
965 }
966
967 // move to next record
968 record = (ATOM_COMMON_RECORD_HEADER*)
969 ((char*)record + record->ucRecordSize);
970 }
971 }
972 }
973 }
974
975 connector->valid = true;
976 connector->flags = connectorFlags;
977 connector->type = connectorType;
978 connector->objectID = connectorObjectID;
979
980 connectorIndex++;
981 } // END for each valid connector
982 } // end for each display path
983
984 return B_OK;
985 }
986
987
988 bool
connector_is_dp(uint32 connectorIndex)989 connector_is_dp(uint32 connectorIndex)
990 {
991 connector_info* connector = gConnector[connectorIndex];
992
993 // Traditional DisplayPort connector, or DP over USBC
994 if (connector->type == VIDEO_CONNECTOR_DP
995 || connector->type == VIDEO_CONNECTOR_EDP
996 || connector->type == VIDEO_CONNECTOR_USBC) {
997 return true;
998 }
999
1000 // DisplayPort bridge on external encoder
1001 if (connector->encoderExternal.valid == true
1002 && connector->encoderExternal.isDPBridge == true) {
1003 return true;
1004 }
1005
1006 return false;
1007 }
1008
1009
1010 void
debug_connectors()1011 debug_connectors()
1012 {
1013 ERROR("Currently detected connectors=============\n");
1014 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
1015 if (gConnector[id]->valid == true) {
1016 uint32 connectorType = gConnector[id]->type;
1017 uint16 i2cPinIndex = gConnector[id]->i2cPinIndex;
1018 uint16 hpdPinIndex = gConnector[id]->hpdPinIndex;
1019
1020 ERROR("Connector #%" B_PRIu32 ")\n", id);
1021 ERROR(" + connector: %s\n",
1022 get_connector_name(connectorType));
1023 ERROR(" + i2c gpio table id: %" B_PRIu16 "\n", i2cPinIndex);
1024 ERROR(" - gpio hw pin: 0x%" B_PRIX32 "\n",
1025 gGPIOInfo[i2cPinIndex]->hwPin);
1026 ERROR(" - gpio valid: %s\n",
1027 gGPIOInfo[i2cPinIndex]->valid ? "true" : "false");
1028 ERROR(" - i2c valid: %s\n",
1029 gGPIOInfo[i2cPinIndex]->i2c.valid ? "true" : "false");
1030
1031 // hot plug detection info
1032 ERROR(" + hpd gpio table id: %" B_PRIu16 "\n", hpdPinIndex);
1033 ERROR(" - gpio hw pin: 0x%" B_PRIX32 "\n",
1034 gGPIOInfo[hpdPinIndex]->hwPin);
1035 ERROR(" - gpio valid: %s\n",
1036 gGPIOInfo[hpdPinIndex]->valid ? "true" : "false");
1037
1038 // router info
1039 router_info* router = &gConnector[id]->router;
1040 ERROR(" + router gpio table id: %" B_PRIu16 "\n", router->i2cPinIndex);
1041 ERROR(" + router (ddc): %s\n",
1042 router->ddcValid ? "true" : "false");
1043 if (router->ddcValid) {
1044 ERROR(" - mux type: 0x%" B_PRIX8 "\n", router->ddcMuxType);
1045 ERROR(" - mux pin: 0x%" B_PRIX8 "\n", router->ddcMuxControlPin);
1046 ERROR(" - mux state: 0x%" B_PRIX8 "\n", router->ddcMuxState);
1047 }
1048 ERROR(" + router (c/d): %s\n",
1049 router->cdValid ? "true" : "false");
1050 if (router->cdValid) {
1051 ERROR(" - mux type: 0x%" B_PRIX8 "\n", router->cdMuxType);
1052 ERROR(" - mux pin: 0x%" B_PRIX8 "\n", router->cdMuxControlPin);
1053 ERROR(" - mux state: 0x%" B_PRIX8 "\n", router->cdMuxState);
1054 }
1055
1056 // encoder info
1057 encoder_info* encoder = &gConnector[id]->encoder;
1058 ERROR(" + encoder: %s\n",
1059 get_encoder_name(encoder->type));
1060 ERROR(" - id: %" B_PRIu16 "\n", encoder->objectID);
1061 ERROR(" - type: %s\n",
1062 encoder_name_lookup(encoder->objectID));
1063 ERROR(" - capabilities: 0x%" B_PRIX32 "\n",
1064 encoder->capabilities);
1065 ERROR(" - enumeration: %" B_PRIu32 "\n",
1066 encoder->linkEnumeration);
1067
1068 encoder = &gConnector[id]->encoderExternal;
1069
1070 ERROR(" - is bridge: %s\n",
1071 encoder->valid ? "true" : "false");
1072
1073 if (!encoder->valid)
1074 ERROR(" + external encoder: none\n");
1075 else {
1076 ERROR(" + external encoder: %s\n",
1077 get_encoder_name(encoder->type));
1078 ERROR(" - valid: true\n");
1079 ERROR(" - id: %" B_PRIu16 "\n",
1080 encoder->objectID);
1081 ERROR(" - type: %s\n",
1082 encoder_name_lookup(encoder->objectID));
1083 ERROR(" - enumeration: %" B_PRIu32 "\n",
1084 encoder->linkEnumeration);
1085 }
1086
1087 uint32 connectorFlags = gConnector[id]->flags;
1088 bool flags = false;
1089 ERROR(" + flags:\n");
1090 if ((connectorFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) {
1091 ERROR(" * device CRT1 support\n");
1092 flags = true;
1093 }
1094 if ((connectorFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) {
1095 ERROR(" * device CRT2 support\n");
1096 flags = true;
1097 }
1098 if ((connectorFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) {
1099 ERROR(" * device LCD1 support\n");
1100 flags = true;
1101 }
1102 if ((connectorFlags & ATOM_DEVICE_LCD2_SUPPORT) != 0) {
1103 ERROR(" * device LCD2 support\n");
1104 flags = true;
1105 }
1106 if ((connectorFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
1107 ERROR(" * device TV1 support\n");
1108 flags = true;
1109 }
1110 if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0) {
1111 ERROR(" * device CV support\n");
1112 flags = true;
1113 }
1114 if ((connectorFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) {
1115 ERROR(" * device DFP1 support\n");
1116 flags = true;
1117 }
1118 if ((connectorFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) {
1119 ERROR(" * device DFP2 support\n");
1120 flags = true;
1121 }
1122 if ((connectorFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) {
1123 ERROR(" * device DFP3 support\n");
1124 flags = true;
1125 }
1126 if ((connectorFlags & ATOM_DEVICE_DFP4_SUPPORT) != 0) {
1127 ERROR(" * device DFP4 support\n");
1128 flags = true;
1129 }
1130 if ((connectorFlags & ATOM_DEVICE_DFP5_SUPPORT) != 0) {
1131 ERROR(" * device DFP5 support\n");
1132 flags = true;
1133 }
1134 if ((connectorFlags & ATOM_DEVICE_DFP6_SUPPORT) != 0) {
1135 ERROR(" * device DFP6 support\n");
1136 flags = true;
1137 }
1138 if (flags == false)
1139 ERROR(" * no known flags\n");
1140 }
1141 }
1142 ERROR("==========================================\n");
1143 }
1144