drmModeModeInfoPtr
IntelHWComposerDrm::selectDisplayDrmMode(int disp, intel_display_mode_t *displayMode)
{
    if (disp != OUTPUT_HDMI)
        return NULL;
    drmModeModeInfoPtr mode = getOutputMode(OUTPUT_HDMI);

    // If mode no change, return current mode
    if (displayMode && !isModeChanged(mode, displayMode))
        return mode;
    if (mHdmiConnector != NULL) {
        freeConnector(mHdmiConnector);
        mHdmiConnector = NULL;
    }
    drmModeConnectorPtr connector;
    connector = getHdmiConnector();
    if (!connector) {
        ALOGW("%s: fail to get drm connector\n", __func__);
        return NULL;
    }

    mode = getSelectMode(displayMode, connector);

    if (!mode) {
        ALOGW("%s: fail to get selected mode or any other mode! \n", __func__);
        return NULL;
    }

    // update current mode to be selected
    setOutputMode(OUTPUT_HDMI, mode, 1);

    //freeConnector(connector);

    mode = getOutputMode(OUTPUT_HDMI);
    ALOGD("%s: mode is %dx%d@%dHz, 0x%x\n", __func__,
             mode->hdisplay, mode->vdisplay, mode->vrefresh, mode->flags);

    return mode;
}
bool IntelHWComposerDrm::setDisplayDrmMode(int disp,
                                           uint32_t fb_handler,
                                           drmModeModeInfoPtr mode)
{
    drmModeConnectorPtr connector = NULL;
    uint32_t crtc_id = 0;
    uint32_t fb_id = 0;

    if (mDrmFd < 0) {
        ALOGE("%s: invalid drm FD\n", __func__);
        return false;
    }

    if (!fb_handler) {
        ALOGE("%s: invalid fb handler\n", __func__);
        return false;
    }
    if (disp != OUTPUT_HDMI)
        return false;
    connector = getHdmiConnector();
    if (!connector) {
        ALOGW("%s: fail to get drm connector\n", __func__);
        return false;
    }

    setOutputConnection(OUTPUT_HDMI, connector->connection);

    // re-check connection status
    if (connector->connection != DRM_MODE_CONNECTED) {
        freeConnector(connector);
        return false;
    }

    // get fb_id
    if (setupDrmFb(OUTPUT_HDMI, fb_handler, mode))
        fb_id = getOutputFBId(OUTPUT_HDMI);

    if (!fb_id) {
        ALOGW("%s: fail to get drm fb id\n", __func__);
        freeConnector(connector);
        return false;
    }

    // get crtc_id
    crtc_id = getCrtcId(OUTPUT_HDMI);
    if (!crtc_id) {
        ALOGW("%s: fail to get drm crtc id\n", __func__);
        freeConnector(connector);
        return false;
    }

    // crtc mode setting
    int ret = drmModeSetCrtc(mDrmFd, crtc_id, fb_id, 0, 0,
                   &connector->connector_id, 1, mode);
    if (ret) {
        ALOGW("drm Mode Set Crtc Error: 0x%x!\n", ret);
        freeConnector(connector);
        return false;
    }

    return true;
}
Пример #3
0
// return number of unique modes
int drm_hdmi_getModeInfo(
    int *pWidth,
    int *pHeight,
    int *pRefresh,
    int *pInterlace,
    int *pRatio)
{
    if (!gDrmCxt.hdmiSupported || !gDrmCxt.connected) {
        LOGE("%s: HDMI is not supported or not connected.", __func__);
        return 0;
    }

    drmModeConnector *connector = getHdmiConnector();
    if (connector == NULL) {
        LOGE("%s: Failed to get HDMI connector.", __func__);
        return 0;
    }

    if (connector->count_modes < 0 || connector->count_modes > HDMI_TIMING_MAX) {
        LOGW("%s: unexpected count of modes %d", __func__, connector->count_modes);
        drmModeFreeConnector(connector);
        gDrmCxt.hdmiConnector = NULL;
        return 0;
    }

    int i, valid_mode_count = 0;
    // get resolution of each mode
    for (i = 0; i < connector->count_modes; i++) {
        unsigned int temp_hdisplay = connector->modes[i].hdisplay;
        unsigned int temp_vdisplay = connector->modes[i].vdisplay;
        unsigned int temp_refresh = connector->modes[i].vrefresh;
        // Only extract the required flags for comparison
        unsigned int temp_flags = connector->modes[i].flags &
          (DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_PAR16_9 | DRM_MODE_FLAG_PAR4_3);

        // re-traverse the connector mode list to see if there is
        // same resolution and refresh. The same mode will not be
        // counted into valid mode.

        int j = i;
        unsigned int flags = 0;

        while ((--j) >= 0) {
            flags = connector->modes[j].flags &
              (DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_PAR16_9 |
               DRM_MODE_FLAG_PAR4_3);

            if (temp_hdisplay == connector->modes[j].hdisplay &&
                temp_vdisplay == connector->modes[j].vdisplay &&
                temp_refresh == connector->modes[j].vrefresh &&
                temp_flags == flags) {
                  LOGV("Found duplicated mode: %dx%d@%d with flags = 0x%x",
                       temp_hdisplay, temp_vdisplay, temp_refresh, temp_flags);
                  break;
            }
        }

        // if j<0, mode is not duplicated
        if (j < 0) {
            // pWidth, pHeight, etc can be NULL to get mode count.
            if (pWidth && pHeight && pRefresh && pInterlace && pRatio) {
                // record the valid mode info into mode array
                pWidth[valid_mode_count] = temp_hdisplay;
                pHeight[valid_mode_count] = temp_vdisplay;
                pRefresh[valid_mode_count] = temp_refresh;
                if (temp_flags & DRM_MODE_FLAG_INTERLACE)
                    pInterlace[valid_mode_count] = 1;
                else
                    pInterlace[valid_mode_count] = 0;
                if (temp_flags & DRM_MODE_FLAG_PAR16_9)
                    pRatio[valid_mode_count] = 2;
                else if (temp_flags & DRM_MODE_FLAG_PAR4_3)
                    pRatio[valid_mode_count] = 1;
                else
                    pRatio[valid_mode_count] = 0;

                LOGV("Adding mode[%d]: %dx%d@%d with flags = 0x%x\n", valid_mode_count,
                     temp_hdisplay, temp_vdisplay, temp_refresh, temp_flags);
            }
            valid_mode_count++;
        }
    }

    return valid_mode_count;
}
Пример #4
0
bool drm_hdmi_getTiming(int mode, MDSHDMITiming* info)
{
    if (info == NULL)
        return false;

    if (!gDrmCxt.hdmiSupported || !gDrmCxt.connected) {
        LOGE("%s: HDMI is not supported or not connected.", __func__);
        return false;
    }

    LOGV("Initial HDMI timing is %dx%d@%dHz",
            info->width, info->height, info->refresh);

    if (gDrmCxt.modeValid) {
        LOGI("use user-selected mode.");
        memcpy(info, &gDrmCxt.modeSelected, sizeof(MDSHDMITiming));
        return true;
    }

    drmModeConnector *connector = getHdmiConnector();
    if (connector == NULL) {
        LOGE("%s: get HDMI connector failed.", __func__);
        return false;
    }

    if (mode != DRM_HDMI_VIDEO_EXT) {
        drm_hdmi_setTiming(connector, gDrmCxt.preferredModeIndex, info);
        return true;
    }

    // Video extended mode, aspect ratio/interlace matching is not supported yet.
    // select 720P or 1080P as output
    if (info->width <= 1280 && info->height <= 720) {
        info->width = 1280;
        info->height = 720;
    } else {
        info->width = 1920;
        info->height = 1080;
    }

    // Find number of matched modes by resolution
    int i, num_matched = 0;
    int index_matched[HDMI_TIMING_MAX];
    for (i = 0; i < connector->count_modes; i++) {
        if (info->width == connector->modes[i].hdisplay &&
            info->height == connector->modes[i].vdisplay) {
            index_matched[num_matched++] = i;
        }
        if (num_matched >= HDMI_TIMING_MAX) {
            LOGW("number of matched modes exceeds the limit.");
            break;
        }
    }

    if (num_matched == 0) {
        LOGW("%s: Number of matched modes is 0.", __func__);
        // Use preferred mode
        drm_hdmi_setTiming(connector, gDrmCxt.preferredModeIndex, info);
        return true;
    }

    // select the best one from the matched modes
    int max_vrefresh_index = index_matched[0];
    int best_vrefresh_index = -1;
    drmModeModeInfoPtr modeInfo;
    for (i = 0; i < num_matched; i++) {
        modeInfo = connector->modes + index_matched[i];
        if (modeInfo->vrefresh > connector->modes[max_vrefresh_index].vrefresh) {
            max_vrefresh_index = index_matched[i];
        } else if (modeInfo->vrefresh == connector->modes[max_vrefresh_index].vrefresh) {
            if (drm_is_preferred_flags(modeInfo->flags)) {
                max_vrefresh_index = index_matched[i];
            }
        }
        if (info->refresh == 0)
            continue;
        if ((modeInfo->vrefresh % info->refresh) == 0) {
            if (modeInfo->vrefresh == info->refresh) {
                if (drm_is_preferred_flags(modeInfo->flags)) {
                    best_vrefresh_index = index_matched[i];
                    break;
                }
            } else if (best_vrefresh_index == -1 ||
                modeInfo->vrefresh > connector->modes[best_vrefresh_index].vrefresh) {
                best_vrefresh_index = index_matched[i];
            }
        }
    }

    if (best_vrefresh_index != -1) {
        drm_hdmi_setTiming(connector, best_vrefresh_index, info);
    } else {
        drm_hdmi_setTiming(connector, max_vrefresh_index, info);
    }
    return true;
}
Пример #5
0
// return 0 - not connected, 1 - HDMI connected, 2 - DVI connected
int drm_hdmi_getConnectionStatus()
{
    if (!gDrmCxt.hdmiSupported)
        return 0;

    if (gDrmCxt.hdmiConnector)
        drmModeFreeConnector(gDrmCxt.hdmiConnector);
    gDrmCxt.hdmiConnector = NULL;
    // reset connection status
    gDrmCxt.connected = false;
    drmModeConnector *connector = getHdmiConnector();
    if (connector == NULL)
        return 0;

    // Read EDID, and check whether it's HDMI or DVI interface
    int ret = 0, i, j;
    for (i = 0; i < connector->count_props; i++) {
        drmModePropertyPtr props = drmModeGetProperty(gDrmCxt.drmFD, connector->props[i]);
        if (!props)
            continue;

        if (props->name == NULL ||
                strncmp(props->name, "EDID", sizeof("EDID")) != 0) {
            drmModeFreeProperty(props);
            continue;
        }

        uint64_t* edid = &connector->prop_values[i];
        drmModePropertyBlobPtr edidBlob = drmModeGetPropertyBlob(gDrmCxt.drmFD, *edid);
        if (edidBlob == NULL ||
            edidBlob->data == NULL ||
            edidBlob->length < HDMI_TIMING_MAX) {
            LOGE("%s: Invalid EDID Blob.", __func__);
            drmModeFreeProperty(props);
            ret = 0;
            break;
        }

        char* edid_binary = (char *)edidBlob->data;
        // offset of product_info
        char* product_info = edid_binary + 8;
        gDrmCxt.connected = true;
        if (memcmp(gDrmCxt.productInfo, product_info, EDID_PRODUCT_INFO_LEN)) {
            LOGI("A new HDMI sink is connected.");
            gDrmCxt.newDevice = true;
            gDrmCxt.modeValid = false;
            memcpy(gDrmCxt.productInfo, product_info, EDID_PRODUCT_INFO_LEN);
        }

        drm_select_preferredmode(connector);

        ret = 2; // DVI
        if (edid_binary[126] == 0) {
            drmModeFreeProperty(props);
            break;
        }

        // search VSDB in extend edid
        for (j = 0; j <= HDMI_TIMING_MAX - 3; j++) {
            int n = HDMI_TIMING_MAX + j;
            if (edid_binary[n]   == 0x03 &&
                edid_binary[n+1] == 0x0c &&
                edid_binary[n+2] == 0x00) {
                ret = 1; //HDMI
                break;
            }
        }
        drmModeFreeProperty(props);
        break;
    }

    LOGV("%s: connect status is %d", __func__, ret);
    return ret;
}