OSDN Git Service

radeon: add parsing for r6xx object tables
authorDave Airlie <airlied@redhat.com>
Wed, 24 Sep 2008 03:58:26 +0000 (13:58 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 24 Sep 2008 03:58:26 +0000 (13:58 +1000)
linux-core/radeon_atombios.c

index 0915a7f..90a367a 100644 (file)
@@ -77,6 +77,11 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device *de
        return i2c;
 }
 
+static struct radeon_i2c_bus_rec radeon_parse_i2c_record(struct drm_device *dev, ATOM_I2C_RECORD *record)
+{
+    return radeon_lookup_gpio(dev, record->sucI2cId.bfI2C_LineMux);
+}
+
 static void radeon_atom_apply_quirks(struct drm_device *dev, int index)
 {
        struct drm_radeon_private *dev_priv = dev->dev_private;
@@ -100,6 +105,165 @@ static void radeon_atom_apply_quirks(struct drm_device *dev, int index)
        }
 }
 
+const int object_connector_convert[] =
+{ CONNECTOR_NONE,
+  CONNECTOR_DVI_I,
+  CONNECTOR_DVI_I,
+  CONNECTOR_DVI_D,
+  CONNECTOR_DVI_D,
+  CONNECTOR_VGA,
+  CONNECTOR_CTV,
+  CONNECTOR_STV,
+  CONNECTOR_NONE,
+  CONNECTOR_DIN,
+  CONNECTOR_SCART,
+  CONNECTOR_HDMI_TYPE_A,
+  CONNECTOR_HDMI_TYPE_B,
+  CONNECTOR_HDMI_TYPE_B,
+  CONNECTOR_LVDS,
+  CONNECTOR_DIN,
+  CONNECTOR_NONE,
+  CONNECTOR_NONE,
+  CONNECTOR_NONE,
+  CONNECTOR_DISPLAY_PORT,
+};
+
+bool radeon_get_atom_connector_info_from_bios_object_table(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_mode_info *mode_info = &dev_priv->mode_info;
+       struct atom_context *ctx = mode_info->atom_context;
+       int index = GetIndexIntoMasterTable(DATA, Object_Header);
+       uint16_t size, data_offset;
+       uint8_t frev, crev;
+       ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
+       ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj = NULL;
+       ATOM_OBJECT_HEADER *obj_header;
+       int i, j;
+
+       atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset);
+
+       if (crev < 2)
+               return false;
+
+
+       obj_header = (ATOM_OBJECT_HEADER *)(ctx->bios + data_offset);
+
+       con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)(ctx->bios + data_offset + obj_header->usConnectorObjectTableOffset);
+       DRM_ERROR("Num of objects %d\n", con_obj->ucNumberOfObjects);
+
+       for (i = 0; i < con_obj->ucNumberOfObjects; i++) {
+               ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *src_dst_table;
+               ATOM_COMMON_RECORD_HEADER *record;
+               uint8_t obj_id, num, obj_type;
+               int record_base;
+               uint16_t con_obj_id = le16_to_cpu(con_obj->asObjects[i].usObjectID);
+
+               obj_id = (con_obj_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+               num = (con_obj_id & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
+               obj_type = (con_obj_id & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
+               if (obj_type != GRAPH_OBJECT_TYPE_CONNECTOR)
+                       continue;
+
+               DRM_ERROR("offset is %04x\n", le16_to_cpu(con_obj->asObjects[i].usSrcDstTableOffset));
+               src_dst_table = (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
+                       (ctx->bios + data_offset + le16_to_cpu(con_obj->asObjects[i].usSrcDstTableOffset));
+
+               DRM_ERROR("object id %04x %02x\n", obj_id, src_dst_table->ucNumberOfSrc);
+              
+               if ((dev_priv->chip_family == CHIP_RS780) &&
+                   (obj_id == CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) {
+                       uint32_t slot_config, ct;
+
+                       // TODO
+               } else
+                       mode_info->bios_connector[i].connector_type = object_connector_convert[obj_id];
+
+               if (mode_info->bios_connector[i].connector_type == CONNECTOR_NONE)
+                       mode_info->bios_connector[i].valid = false;
+               else
+                       mode_info->bios_connector[i].valid = true;
+               mode_info->bios_connector[i].devices = 0;
+
+               for (j = 0; j < src_dst_table->ucNumberOfSrc; j++) {
+                       uint8_t sobj_id;
+
+                       sobj_id = (src_dst_table->usSrcObjectID[j] & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+                       DRM_ERROR("src object id %04x %d\n", src_dst_table->usSrcObjectID[j], sobj_id);
+
+                       switch(sobj_id) {
+                       case ENCODER_OBJECT_ID_INTERNAL_LVDS:
+                               mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_LCD1_INDEX);
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+                       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
+                               mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP1_INDEX);
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+                               if (num == 1)
+                                       mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP1_INDEX);
+                               else
+                                       mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP2_INDEX);
+                               mode_info->bios_connector[i].tmds_type = TMDS_UNIPHY;
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_TMDS2:
+                       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+                               mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP2_INDEX);
+                               mode_info->bios_connector[i].tmds_type = TMDS_EXT;
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+                       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+                               mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_DFP3_INDEX);
+                               mode_info->bios_connector[i].tmds_type = TMDS_LVTMA;
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_DAC1:
+                       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+                               if (mode_info->bios_connector[i].connector_type == CONNECTOR_DIN ||
+                                   mode_info->bios_connector[i].connector_type == CONNECTOR_STV ||
+                                   mode_info->bios_connector[i].connector_type == CONNECTOR_CTV)
+                                       mode_info->bios_connector[i].valid = false;
+                               else
+                                       mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_CRT1_INDEX);
+                               mode_info->bios_connector[i].dac_type = DAC_PRIMARY;
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_DAC2:
+                       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+                               if (mode_info->bios_connector[i].connector_type == CONNECTOR_DIN ||
+                                   mode_info->bios_connector[i].connector_type == CONNECTOR_STV ||
+                                   mode_info->bios_connector[i].connector_type == CONNECTOR_CTV)
+                                       mode_info->bios_connector[i].valid = false;
+                               else
+                                       mode_info->bios_connector[i].devices |= (1 << ATOM_DEVICE_CRT2_INDEX);
+                               mode_info->bios_connector[i].dac_type = DAC_TVDAC;
+                               break;
+                       }
+               }
+
+               record = (ATOM_COMMON_RECORD_HEADER *)
+                       (ctx->bios + data_offset + le16_to_cpu(con_obj->asObjects[i].usRecordOffset));
+               record_base = le16_to_cpu(con_obj->asObjects[i].usRecordOffset);
+
+               while (record->ucRecordType > 0 &&
+                      record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
+                       DRM_ERROR("record type %d\n", record->ucRecordType);
+
+                       switch(record->ucRecordType) {
+                       case ATOM_I2C_RECORD_TYPE:
+                               mode_info->bios_connector[i].ddc_i2c = radeon_parse_i2c_record(dev, (ATOM_I2C_RECORD *)record);
+                               break;
+                       case ATOM_HPD_INT_RECORD_TYPE:
+                               break;
+                       case ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE:
+                               break;
+                       }
+                       record = (ATOM_COMMON_RECORD_HEADER *)((char *)record + record->ucRecordSize);
+               }
+
+       }
+       return true;
+}
+
+
 bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device *dev)
 {
        struct drm_radeon_private *dev_priv = dev->dev_private;
@@ -112,6 +276,10 @@ bool radeon_get_atom_connector_info_from_bios_connector_table(struct drm_device
 
        union atom_supported_devices *supported_devices;
        int i,j;
+
+       if (radeon_get_atom_connector_info_from_bios_object_table(dev))
+               return true;
+
        atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset);
 
        supported_devices = (union atom_supported_devices *)(ctx->bios + data_offset);