示例#1
0
文件: vmwgfx_scrn.c 项目: Lyude/linux
/**
 * vmw_sou_crtc_mode_set_nofb - Create new screen
 *
 * @crtc: CRTC associated with the new screen
 *
 * This function creates/destroys a screen.  This function cannot fail, so if
 * somehow we run into a failure, just do the best we can to get out.
 */
static void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc)
{
	struct vmw_private *dev_priv;
	struct vmw_screen_object_unit *sou;
	struct vmw_framebuffer *vfb;
	struct drm_framebuffer *fb;
	struct drm_plane_state *ps;
	struct vmw_plane_state *vps;
	int ret;

	sou = vmw_crtc_to_sou(crtc);
	dev_priv = vmw_priv(crtc->dev);
	ps = crtc->primary->state;
	fb = ps->fb;
	vps = vmw_plane_state_to_vps(ps);

	vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;

	if (sou->defined) {
		ret = vmw_sou_fifo_destroy(dev_priv, sou);
		if (ret) {
			DRM_ERROR("Failed to destroy Screen Object\n");
			return;
		}
	}

	if (vfb) {
		struct drm_connector_state *conn_state;
		struct vmw_connector_state *vmw_conn_state;
		int x, y;

		sou->buffer = vps->bo;
		sou->buffer_size = vps->bo_size;

		if (sou->base.is_implicit) {
			x = crtc->x;
			y = crtc->y;
		} else {
			conn_state = sou->base.connector.state;
			vmw_conn_state = vmw_connector_state_to_vcs(conn_state);

			x = vmw_conn_state->gui_x;
			y = vmw_conn_state->gui_y;
		}

		ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode);
		if (ret)
			DRM_ERROR("Failed to define Screen Object %dx%d\n",
				  crtc->x, crtc->y);

		vmw_kms_add_active(dev_priv, &sou->base, vfb);
	} else {
		sou->buffer = NULL;
		sou->buffer_size = 0;

		vmw_kms_del_active(dev_priv, &sou->base);
	}
}
示例#2
0
static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
{
	struct vmw_private *dev_priv;
	struct vmw_screen_object_unit *sou;
	struct drm_connector *connector;
	struct drm_display_mode *mode;
	struct drm_encoder *encoder;
	struct vmw_framebuffer *vfb;
	struct drm_framebuffer *fb;
	struct drm_crtc *crtc;
	int ret = 0;

	if (!set)
		return -EINVAL;

	if (!set->crtc)
		return -EINVAL;

	/* get the sou */
	crtc = set->crtc;
	sou = vmw_crtc_to_sou(crtc);
	vfb = set->fb ? vmw_framebuffer_to_vfb(set->fb) : NULL;
	dev_priv = vmw_priv(crtc->dev);

	if (set->num_connectors > 1) {
		DRM_ERROR("Too many connectors\n");
		return -EINVAL;
	}

	if (set->num_connectors == 1 &&
	    set->connectors[0] != &sou->base.connector) {
		DRM_ERROR("Connector doesn't match %p %p\n",
			set->connectors[0], &sou->base.connector);
		return -EINVAL;
	}

	/* Only one active implicit frame-buffer at a time. */
	if (sou->base.is_implicit &&
	    dev_priv->implicit_fb && vfb &&
	    !(dev_priv->num_implicit == 1 &&
	      sou->base.active_implicit) &&
	    dev_priv->implicit_fb != vfb) {
		DRM_ERROR("Multiple implicit framebuffers not supported.\n");
		return -EINVAL;
	}

	/* since they always map one to one these are safe */
	connector = &sou->base.connector;
	encoder = &sou->base.encoder;

	/* should we turn the crtc off */
	if (set->num_connectors == 0 || !set->mode || !set->fb) {
		ret = vmw_sou_fifo_destroy(dev_priv, sou);
		/* the hardware has hung don't do anything more */
		if (unlikely(ret != 0))
			return ret;

		connector->encoder = NULL;
		encoder->crtc = NULL;
		crtc->primary->fb = NULL;
		crtc->x = 0;
		crtc->y = 0;
		crtc->enabled = false;

		vmw_kms_del_active(dev_priv, &sou->base);

		vmw_sou_backing_free(dev_priv, sou);

		return 0;
	}


	/* we now know we want to set a mode */
	mode = set->mode;
	fb = set->fb;

	if (set->x + mode->hdisplay > fb->width ||
	    set->y + mode->vdisplay > fb->height) {
		DRM_ERROR("set outside of framebuffer\n");
		return -EINVAL;
	}

	vmw_svga_enable(dev_priv);

	if (mode->hdisplay != crtc->mode.hdisplay ||
	    mode->vdisplay != crtc->mode.vdisplay) {
		/* no need to check if depth is different, because backing
		 * store depth is forced to 4 by the device.
		 */

		ret = vmw_sou_fifo_destroy(dev_priv, sou);
		/* the hardware has hung don't do anything more */
		if (unlikely(ret != 0))
			return ret;

		vmw_sou_backing_free(dev_priv, sou);
	}

	if (!sou->buffer) {
		/* forced to depth 4 by the device */
		size_t size = mode->hdisplay * mode->vdisplay * 4;
		ret = vmw_sou_backing_alloc(dev_priv, sou, size);
		if (unlikely(ret != 0))
			return ret;
	}

	ret = vmw_sou_fifo_create(dev_priv, sou, set->x, set->y, mode);
	if (unlikely(ret != 0)) {
		/*
		 * We are in a bit of a situation here, the hardware has
		 * hung and we may or may not have a buffer hanging of
		 * the screen object, best thing to do is not do anything
		 * if we where defined, if not just turn the crtc of.
		 * Not what userspace wants but it needs to htfu.
		 */
		if (sou->defined)
			return ret;

		connector->encoder = NULL;
		encoder->crtc = NULL;
		crtc->primary->fb = NULL;
		crtc->x = 0;
		crtc->y = 0;
		crtc->enabled = false;

		return ret;
	}

	vmw_kms_add_active(dev_priv, &sou->base, vfb);

	connector->encoder = encoder;
	encoder->crtc = crtc;
	crtc->mode = *mode;
	crtc->primary->fb = fb;
	crtc->x = set->x;
	crtc->y = set->y;
	crtc->enabled = true;

	return 0;
}
示例#3
0
文件: vmwgfx_stdu.c 项目: mhei/linux
/**
 * vmw_stdu_crtc_set_config - Sets a mode
 *
 * @set:  mode parameters
 *
 * This function is the device-specific portion of the DRM CRTC mode set.
 * For the SVGA device, we do this by defining a Screen Target, binding a
 * GB Surface to that target, and finally update the screen target.
 *
 * RETURNS:
 * 0 on success, error code otherwise
 */
static int vmw_stdu_crtc_set_config(struct drm_mode_set *set)
{
    struct vmw_private *dev_priv;
    struct vmw_framebuffer *vfb;
    struct vmw_screen_target_display_unit *stdu;
    struct drm_display_mode *mode;
    struct drm_framebuffer  *new_fb;
    struct drm_crtc      *crtc;
    struct drm_encoder   *encoder;
    struct drm_connector *connector;
    bool turning_off;
    int    ret;


    if (!set || !set->crtc)
        return -EINVAL;

    crtc     = set->crtc;
    stdu     = vmw_crtc_to_stdu(crtc);
    mode     = set->mode;
    new_fb   = set->fb;
    dev_priv = vmw_priv(crtc->dev);
    turning_off = set->num_connectors == 0 || !mode || !new_fb;
    vfb = (new_fb) ? vmw_framebuffer_to_vfb(new_fb) : NULL;

    if (set->num_connectors > 1) {
        DRM_ERROR("Too many connectors\n");
        return -EINVAL;
    }

    if (set->num_connectors == 1 &&
            set->connectors[0] != &stdu->base.connector) {
        DRM_ERROR("Connectors don't match %p %p\n",
                  set->connectors[0], &stdu->base.connector);
        return -EINVAL;
    }

    if (!turning_off && (set->x + mode->hdisplay > new_fb->width ||
                         set->y + mode->vdisplay > new_fb->height)) {
        DRM_ERROR("Set outside of framebuffer\n");
        return -EINVAL;
    }

    /* Only one active implicit frame-buffer at a time. */
    mutex_lock(&dev_priv->global_kms_state_mutex);
    if (!turning_off && stdu->base.is_implicit && dev_priv->implicit_fb &&
            !(dev_priv->num_implicit == 1 && stdu->base.active_implicit)
            && dev_priv->implicit_fb != vfb) {
        mutex_unlock(&dev_priv->global_kms_state_mutex);
        DRM_ERROR("Multiple implicit framebuffers not supported.\n");
        return -EINVAL;
    }
    mutex_unlock(&dev_priv->global_kms_state_mutex);

    /* Since they always map one to one these are safe */
    connector = &stdu->base.connector;
    encoder   = &stdu->base.encoder;

    if (stdu->defined) {
        ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
        if (ret)
            return ret;

        vmw_stdu_unpin_display(stdu);
        (void) vmw_stdu_update_st(dev_priv, stdu);
        vmw_kms_del_active(dev_priv, &stdu->base);

        ret = vmw_stdu_destroy_st(dev_priv, stdu);
        if (ret)
            return ret;

        crtc->primary->fb = NULL;
        crtc->enabled = false;
        encoder->crtc = NULL;
        connector->encoder = NULL;
        stdu->content_fb_type = SAME_AS_DISPLAY;
        crtc->x = set->x;
        crtc->y = set->y;
    }

    if (turning_off)
        return 0;

    /*
     * Steps to displaying a surface, assume surface is already
     * bound:
     *   1.  define a screen target
     *   2.  bind a fb to the screen target
     *   3.  update that screen target (this is done later by
     *       vmw_kms_stdu_do_surface_dirty_or_present)
     */
    /*
     * Note on error handling: We can't really restore the crtc to
     * it's original state on error, but we at least update the
     * current state to what's submitted to hardware to enable
     * future recovery.
     */
    vmw_svga_enable(dev_priv);
    ret = vmw_stdu_define_st(dev_priv, stdu, mode, set->x, set->y);
    if (ret)
        return ret;

    crtc->x = set->x;
    crtc->y = set->y;
    crtc->mode = *mode;

    ret = vmw_stdu_bind_fb(dev_priv, crtc, mode, new_fb);
    if (ret)
        return ret;

    vmw_kms_add_active(dev_priv, &stdu->base, vfb);
    crtc->enabled = true;
    connector->encoder = encoder;
    encoder->crtc      = crtc;

    return 0;
}