diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2009-12-04 14:45:27 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-12-07 19:46:28 -0500 |
commit | eed45b30cd1423f8dc10b4312700773cac13c1c8 (patch) | |
tree | f47c667d753ce1fc2abd116449ca7c2ce290cecf /drivers/gpu/drm/radeon/radeon_atombios.c | |
parent | 53c1e09fea4cf3fc0ec1f735a5fcab78c43cb55d (diff) |
drm/radeon/kms: get HPD info for connectors
This populates the connectors with HPD (Hot Plug Detect)
information. This will be used in subsequent patches
for automatic digital monitor connect/disconnect handling.
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_atombios.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_atombios.c | 190 |
1 files changed, 149 insertions, 41 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 87bf6b9d10a4..d7b0feb7d47f 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c | |||
@@ -47,7 +47,8 @@ radeon_add_atom_connector(struct drm_device *dev, | |||
47 | int connector_type, | 47 | int connector_type, |
48 | struct radeon_i2c_bus_rec *i2c_bus, | 48 | struct radeon_i2c_bus_rec *i2c_bus, |
49 | bool linkb, uint32_t igp_lane_info, | 49 | bool linkb, uint32_t igp_lane_info, |
50 | uint16_t connector_object_id); | 50 | uint16_t connector_object_id, |
51 | struct radeon_hpd *hpd); | ||
51 | 52 | ||
52 | /* from radeon_legacy_encoder.c */ | 53 | /* from radeon_legacy_encoder.c */ |
53 | extern void | 54 | extern void |
@@ -60,10 +61,9 @@ union atom_supported_devices { | |||
60 | struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1; | 61 | struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1; |
61 | }; | 62 | }; |
62 | 63 | ||
63 | static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device *dev, | 64 | static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_device *rdev, |
64 | uint8_t id) | 65 | uint8_t id) |
65 | { | 66 | { |
66 | struct radeon_device *rdev = dev->dev_private; | ||
67 | struct atom_context *ctx = rdev->mode_info.atom_context; | 67 | struct atom_context *ctx = rdev->mode_info.atom_context; |
68 | ATOM_GPIO_I2C_ASSIGMENT *gpio; | 68 | ATOM_GPIO_I2C_ASSIGMENT *gpio; |
69 | struct radeon_i2c_bus_rec i2c; | 69 | struct radeon_i2c_bus_rec i2c; |
@@ -114,11 +114,80 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device *de | |||
114 | return i2c; | 114 | return i2c; |
115 | } | 115 | } |
116 | 116 | ||
117 | static inline struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev, | ||
118 | u8 id) | ||
119 | { | ||
120 | struct atom_context *ctx = rdev->mode_info.atom_context; | ||
121 | struct radeon_gpio_rec gpio; | ||
122 | int index = GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT); | ||
123 | struct _ATOM_GPIO_PIN_LUT *gpio_info; | ||
124 | ATOM_GPIO_PIN_ASSIGNMENT *pin; | ||
125 | u16 data_offset, size; | ||
126 | int i, num_indices; | ||
127 | |||
128 | memset(&gpio, 0, sizeof(struct radeon_gpio_rec)); | ||
129 | gpio.valid = false; | ||
130 | |||
131 | atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset); | ||
132 | |||
133 | gpio_info = (struct _ATOM_GPIO_PIN_LUT *)(ctx->bios + data_offset); | ||
134 | |||
135 | num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_GPIO_PIN_ASSIGNMENT); | ||
136 | |||
137 | for (i = 0; i < num_indices; i++) { | ||
138 | pin = &gpio_info->asGPIO_Pin[i]; | ||
139 | if (id == pin->ucGPIO_ID) { | ||
140 | gpio.id = pin->ucGPIO_ID; | ||
141 | gpio.reg = pin->usGpioPin_AIndex * 4; | ||
142 | gpio.mask = (1 << pin->ucGpioPinBitShift); | ||
143 | gpio.valid = true; | ||
144 | break; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | return gpio; | ||
149 | } | ||
150 | |||
151 | static struct radeon_hpd radeon_atom_get_hpd_info_from_gpio(struct radeon_device *rdev, | ||
152 | struct radeon_gpio_rec *gpio) | ||
153 | { | ||
154 | struct radeon_hpd hpd; | ||
155 | hpd.gpio = *gpio; | ||
156 | if (gpio->reg == AVIVO_DC_GPIO_HPD_A) { | ||
157 | switch(gpio->mask) { | ||
158 | case (1 << 0): | ||
159 | hpd.hpd = RADEON_HPD_1; | ||
160 | break; | ||
161 | case (1 << 8): | ||
162 | hpd.hpd = RADEON_HPD_2; | ||
163 | break; | ||
164 | case (1 << 16): | ||
165 | hpd.hpd = RADEON_HPD_3; | ||
166 | break; | ||
167 | case (1 << 24): | ||
168 | hpd.hpd = RADEON_HPD_4; | ||
169 | break; | ||
170 | case (1 << 26): | ||
171 | hpd.hpd = RADEON_HPD_5; | ||
172 | break; | ||
173 | case (1 << 28): | ||
174 | hpd.hpd = RADEON_HPD_6; | ||
175 | break; | ||
176 | default: | ||
177 | hpd.hpd = RADEON_HPD_NONE; | ||
178 | break; | ||
179 | } | ||
180 | } else | ||
181 | hpd.hpd = RADEON_HPD_NONE; | ||
182 | return hpd; | ||
183 | } | ||
184 | |||
117 | static bool radeon_atom_apply_quirks(struct drm_device *dev, | 185 | static bool radeon_atom_apply_quirks(struct drm_device *dev, |
118 | uint32_t supported_device, | 186 | uint32_t supported_device, |
119 | int *connector_type, | 187 | int *connector_type, |
120 | struct radeon_i2c_bus_rec *i2c_bus, | 188 | struct radeon_i2c_bus_rec *i2c_bus, |
121 | uint16_t *line_mux) | 189 | uint16_t *line_mux, |
190 | struct radeon_hpd *hpd) | ||
122 | { | 191 | { |
123 | 192 | ||
124 | /* Asus M2A-VM HDMI board lists the DVI port as HDMI */ | 193 | /* Asus M2A-VM HDMI board lists the DVI port as HDMI */ |
@@ -279,16 +348,19 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
279 | struct radeon_mode_info *mode_info = &rdev->mode_info; | 348 | struct radeon_mode_info *mode_info = &rdev->mode_info; |
280 | struct atom_context *ctx = mode_info->atom_context; | 349 | struct atom_context *ctx = mode_info->atom_context; |
281 | int index = GetIndexIntoMasterTable(DATA, Object_Header); | 350 | int index = GetIndexIntoMasterTable(DATA, Object_Header); |
282 | uint16_t size, data_offset; | 351 | u16 size, data_offset; |
283 | uint8_t frev, crev, line_mux = 0; | 352 | u8 frev, crev; |
284 | ATOM_CONNECTOR_OBJECT_TABLE *con_obj; | 353 | ATOM_CONNECTOR_OBJECT_TABLE *con_obj; |
285 | ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj; | 354 | ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj; |
286 | ATOM_OBJECT_HEADER *obj_header; | 355 | ATOM_OBJECT_HEADER *obj_header; |
287 | int i, j, path_size, device_support; | 356 | int i, j, path_size, device_support; |
288 | int connector_type; | 357 | int connector_type; |
289 | uint16_t igp_lane_info, conn_id, connector_object_id; | 358 | u16 igp_lane_info, conn_id, connector_object_id; |
290 | bool linkb; | 359 | bool linkb; |
291 | struct radeon_i2c_bus_rec ddc_bus; | 360 | struct radeon_i2c_bus_rec ddc_bus; |
361 | struct radeon_gpio_rec gpio; | ||
362 | struct radeon_hpd hpd; | ||
363 | |||
292 | atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); | 364 | atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); |
293 | 365 | ||
294 | if (data_offset == 0) | 366 | if (data_offset == 0) |
@@ -414,10 +486,9 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
414 | } | 486 | } |
415 | } | 487 | } |
416 | 488 | ||
417 | /* look up gpio for ddc */ | 489 | /* look up gpio for ddc, hpd */ |
418 | if ((le16_to_cpu(path->usDeviceTag) & | 490 | if ((le16_to_cpu(path->usDeviceTag) & |
419 | (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) | 491 | (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) { |
420 | == 0) { | ||
421 | for (j = 0; j < con_obj->ucNumberOfObjects; j++) { | 492 | for (j = 0; j < con_obj->ucNumberOfObjects; j++) { |
422 | if (le16_to_cpu(path->usConnObjectId) == | 493 | if (le16_to_cpu(path->usConnObjectId) == |
423 | le16_to_cpu(con_obj->asObjects[j]. | 494 | le16_to_cpu(con_obj->asObjects[j]. |
@@ -431,21 +502,31 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
431 | asObjects[j]. | 502 | asObjects[j]. |
432 | usRecordOffset)); | 503 | usRecordOffset)); |
433 | ATOM_I2C_RECORD *i2c_record; | 504 | ATOM_I2C_RECORD *i2c_record; |
505 | ATOM_HPD_INT_RECORD *hpd_record; | ||
506 | hpd.hpd = RADEON_HPD_NONE; | ||
434 | 507 | ||
435 | while (record->ucRecordType > 0 | 508 | while (record->ucRecordType > 0 |
436 | && record-> | 509 | && record-> |
437 | ucRecordType <= | 510 | ucRecordType <= |
438 | ATOM_MAX_OBJECT_RECORD_NUMBER) { | 511 | ATOM_MAX_OBJECT_RECORD_NUMBER) { |
439 | switch (record-> | 512 | switch (record->ucRecordType) { |
440 | ucRecordType) { | ||
441 | case ATOM_I2C_RECORD_TYPE: | 513 | case ATOM_I2C_RECORD_TYPE: |
442 | i2c_record = | 514 | i2c_record = |
443 | (ATOM_I2C_RECORD | 515 | (ATOM_I2C_RECORD *) |
444 | *) record; | 516 | record; |
445 | line_mux = | 517 | ddc_bus = radeon_lookup_i2c_gpio(rdev, |
446 | i2c_record-> | 518 | i2c_record-> |
447 | sucI2cId. | 519 | sucI2cId. |
448 | bfI2C_LineMux; | 520 | bfI2C_LineMux); |
521 | break; | ||
522 | case ATOM_HPD_INT_RECORD_TYPE: | ||
523 | hpd_record = | ||
524 | (ATOM_HPD_INT_RECORD *) | ||
525 | record; | ||
526 | gpio = radeon_lookup_gpio(rdev, | ||
527 | hpd_record->ucHPDIntGPIOID); | ||
528 | hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio); | ||
529 | hpd.plugged_state = hpd_record->ucPlugged_PinState; | ||
449 | break; | 530 | break; |
450 | } | 531 | } |
451 | record = | 532 | record = |
@@ -458,24 +539,16 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
458 | break; | 539 | break; |
459 | } | 540 | } |
460 | } | 541 | } |
461 | } else | 542 | } else { |
462 | line_mux = 0; | 543 | hpd.hpd = RADEON_HPD_NONE; |
463 | |||
464 | if ((le16_to_cpu(path->usDeviceTag) == | ||
465 | ATOM_DEVICE_TV1_SUPPORT) | ||
466 | || (le16_to_cpu(path->usDeviceTag) == | ||
467 | ATOM_DEVICE_TV2_SUPPORT) | ||
468 | || (le16_to_cpu(path->usDeviceTag) == | ||
469 | ATOM_DEVICE_CV_SUPPORT)) | ||
470 | ddc_bus.valid = false; | 544 | ddc_bus.valid = false; |
471 | else | 545 | } |
472 | ddc_bus = radeon_lookup_gpio(dev, line_mux); | ||
473 | 546 | ||
474 | conn_id = le16_to_cpu(path->usConnObjectId); | 547 | conn_id = le16_to_cpu(path->usConnObjectId); |
475 | 548 | ||
476 | if (!radeon_atom_apply_quirks | 549 | if (!radeon_atom_apply_quirks |
477 | (dev, le16_to_cpu(path->usDeviceTag), &connector_type, | 550 | (dev, le16_to_cpu(path->usDeviceTag), &connector_type, |
478 | &ddc_bus, &conn_id)) | 551 | &ddc_bus, &conn_id, &hpd)) |
479 | continue; | 552 | continue; |
480 | 553 | ||
481 | radeon_add_atom_connector(dev, | 554 | radeon_add_atom_connector(dev, |
@@ -484,7 +557,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) | |||
484 | usDeviceTag), | 557 | usDeviceTag), |
485 | connector_type, &ddc_bus, | 558 | connector_type, &ddc_bus, |
486 | linkb, igp_lane_info, | 559 | linkb, igp_lane_info, |
487 | connector_object_id); | 560 | connector_object_id, |
561 | &hpd); | ||
488 | 562 | ||
489 | } | 563 | } |
490 | } | 564 | } |
@@ -539,6 +613,7 @@ struct bios_connector { | |||
539 | uint16_t devices; | 613 | uint16_t devices; |
540 | int connector_type; | 614 | int connector_type; |
541 | struct radeon_i2c_bus_rec ddc_bus; | 615 | struct radeon_i2c_bus_rec ddc_bus; |
616 | struct radeon_hpd hpd; | ||
542 | }; | 617 | }; |
543 | 618 | ||
544 | bool radeon_get_atom_connector_info_from_supported_devices_table(struct | 619 | bool radeon_get_atom_connector_info_from_supported_devices_table(struct |
@@ -554,7 +629,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct | |||
554 | uint16_t device_support; | 629 | uint16_t device_support; |
555 | uint8_t dac; | 630 | uint8_t dac; |
556 | union atom_supported_devices *supported_devices; | 631 | union atom_supported_devices *supported_devices; |
557 | int i, j; | 632 | int i, j, max_device; |
558 | struct bios_connector bios_connectors[ATOM_MAX_SUPPORTED_DEVICE]; | 633 | struct bios_connector bios_connectors[ATOM_MAX_SUPPORTED_DEVICE]; |
559 | 634 | ||
560 | atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); | 635 | atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); |
@@ -564,7 +639,12 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct | |||
564 | 639 | ||
565 | device_support = le16_to_cpu(supported_devices->info.usDeviceSupport); | 640 | device_support = le16_to_cpu(supported_devices->info.usDeviceSupport); |
566 | 641 | ||
567 | for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { | 642 | if (frev > 1) |
643 | max_device = ATOM_MAX_SUPPORTED_DEVICE; | ||
644 | else | ||
645 | max_device = ATOM_MAX_SUPPORTED_DEVICE_INFO; | ||
646 | |||
647 | for (i = 0; i < max_device; i++) { | ||
568 | ATOM_CONNECTOR_INFO_I2C ci = | 648 | ATOM_CONNECTOR_INFO_I2C ci = |
569 | supported_devices->info.asConnInfo[i]; | 649 | supported_devices->info.asConnInfo[i]; |
570 | 650 | ||
@@ -619,8 +699,30 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct | |||
619 | bios_connectors[i].line_mux = 52; | 699 | bios_connectors[i].line_mux = 52; |
620 | } else | 700 | } else |
621 | bios_connectors[i].ddc_bus = | 701 | bios_connectors[i].ddc_bus = |
622 | radeon_lookup_gpio(dev, | 702 | radeon_lookup_i2c_gpio(rdev, |
623 | bios_connectors[i].line_mux); | 703 | bios_connectors[i].line_mux); |
704 | |||
705 | if ((crev > 1) && (frev > 1)) { | ||
706 | u8 isb = supported_devices->info_2d1.asIntSrcInfo[i].ucIntSrcBitmap; | ||
707 | switch (isb) { | ||
708 | case 0x4: | ||
709 | bios_connectors[i].hpd.hpd = RADEON_HPD_1; | ||
710 | break; | ||
711 | case 0xa: | ||
712 | bios_connectors[i].hpd.hpd = RADEON_HPD_2; | ||
713 | break; | ||
714 | default: | ||
715 | bios_connectors[i].hpd.hpd = RADEON_HPD_NONE; | ||
716 | break; | ||
717 | } | ||
718 | } else { | ||
719 | if (i == ATOM_DEVICE_DFP1_INDEX) | ||
720 | bios_connectors[i].hpd.hpd = RADEON_HPD_1; | ||
721 | else if (i == ATOM_DEVICE_DFP2_INDEX) | ||
722 | bios_connectors[i].hpd.hpd = RADEON_HPD_2; | ||
723 | else | ||
724 | bios_connectors[i].hpd.hpd = RADEON_HPD_NONE; | ||
725 | } | ||
624 | 726 | ||
625 | /* Always set the connector type to VGA for CRT1/CRT2. if they are | 727 | /* Always set the connector type to VGA for CRT1/CRT2. if they are |
626 | * shared with a DVI port, we'll pick up the DVI connector when we | 728 | * shared with a DVI port, we'll pick up the DVI connector when we |
@@ -632,7 +734,8 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct | |||
632 | 734 | ||
633 | if (!radeon_atom_apply_quirks | 735 | if (!radeon_atom_apply_quirks |
634 | (dev, (1 << i), &bios_connectors[i].connector_type, | 736 | (dev, (1 << i), &bios_connectors[i].connector_type, |
635 | &bios_connectors[i].ddc_bus, &bios_connectors[i].line_mux)) | 737 | &bios_connectors[i].ddc_bus, &bios_connectors[i].line_mux, |
738 | &bios_connectors[i].hpd)) | ||
636 | continue; | 739 | continue; |
637 | 740 | ||
638 | bios_connectors[i].valid = true; | 741 | bios_connectors[i].valid = true; |
@@ -654,9 +757,9 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct | |||
654 | } | 757 | } |
655 | 758 | ||
656 | /* combine shared connectors */ | 759 | /* combine shared connectors */ |
657 | for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { | 760 | for (i = 0; i < max_device; i++) { |
658 | if (bios_connectors[i].valid) { | 761 | if (bios_connectors[i].valid) { |
659 | for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) { | 762 | for (j = 0; j < max_device; j++) { |
660 | if (bios_connectors[j].valid && (i != j)) { | 763 | if (bios_connectors[j].valid && (i != j)) { |
661 | if (bios_connectors[i].line_mux == | 764 | if (bios_connectors[i].line_mux == |
662 | bios_connectors[j].line_mux) { | 765 | bios_connectors[j].line_mux) { |
@@ -680,6 +783,10 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct | |||
680 | bios_connectors[i]. | 783 | bios_connectors[i]. |
681 | connector_type = | 784 | connector_type = |
682 | DRM_MODE_CONNECTOR_DVII; | 785 | DRM_MODE_CONNECTOR_DVII; |
786 | if (bios_connectors[j].devices & | ||
787 | (ATOM_DEVICE_DFP_SUPPORT)) | ||
788 | bios_connectors[i].hpd = | ||
789 | bios_connectors[j].hpd; | ||
683 | bios_connectors[j]. | 790 | bios_connectors[j]. |
684 | valid = false; | 791 | valid = false; |
685 | } | 792 | } |
@@ -690,7 +797,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct | |||
690 | } | 797 | } |
691 | 798 | ||
692 | /* add the connectors */ | 799 | /* add the connectors */ |
693 | for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { | 800 | for (i = 0; i < max_device; i++) { |
694 | if (bios_connectors[i].valid) { | 801 | if (bios_connectors[i].valid) { |
695 | uint16_t connector_object_id = | 802 | uint16_t connector_object_id = |
696 | atombios_get_connector_object_id(dev, | 803 | atombios_get_connector_object_id(dev, |
@@ -703,7 +810,8 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct | |||
703 | connector_type, | 810 | connector_type, |
704 | &bios_connectors[i].ddc_bus, | 811 | &bios_connectors[i].ddc_bus, |
705 | false, 0, | 812 | false, 0, |
706 | connector_object_id); | 813 | connector_object_id, |
814 | &bios_connectors[i].hpd); | ||
707 | } | 815 | } |
708 | } | 816 | } |
709 | 817 | ||