Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d7e1958d authored by Jakob Bornecrantz's avatar Jakob Bornecrantz Committed by Dave Airlie
Browse files

drm/vmwgfx: Support older hardware.



V2: Fix a couple of typos.

Signed-off-by: default avatarJakob Bornecrantz <jakob@vmware.com>
Signed-off-by: default avatarThomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 1ae1ddd5
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -318,6 +318,15 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
		goto out_err3;
	}

	/* Need mmio memory to check for fifo pitchlock cap. */
	if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) &&
	    !(dev_priv->capabilities & SVGA_CAP_PITCHLOCK) &&
	    !vmw_fifo_have_pitchlock(dev_priv)) {
		ret = -ENOSYS;
		DRM_ERROR("Hardware has no pitchlock\n");
		goto out_err4;
	}

	dev_priv->tdev = ttm_object_device_init
	    (dev_priv->mem_global_ref.object, 12);

+5 −0
Original line number Diff line number Diff line
@@ -187,6 +187,7 @@ struct vmw_private {
	uint32_t vga_red_mask;
	uint32_t vga_blue_mask;
	uint32_t vga_green_mask;
	uint32_t vga_pitchlock;

	/*
	 * Framebuffer info.
@@ -401,6 +402,7 @@ extern int vmw_fifo_send_fence(struct vmw_private *dev_priv,
extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason);
extern int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma);
extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv);
extern bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv);

/**
 * TTM glue - vmwgfx_ttm_glue.c
@@ -491,6 +493,9 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
			  struct ttm_object_file *tfile,
			  struct ttm_buffer_object *bo,
			  SVGA3dCmdHeader *header);
void vmw_kms_write_svga(struct vmw_private *vmw_priv,
			unsigned width, unsigned height, unsigned pitch,
			unsigned bbp, unsigned depth);

/**
 * Overlay control - vmwgfx_overlay.c
+28 −53
Original line number Diff line number Diff line
@@ -132,16 +132,14 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var,
		return -EINVAL;
	}

	/* without multimon its hard to resize */
	if (!(vmw_priv->capabilities & SVGA_CAP_MULTIMON) &&
	    (var->xres != par->max_width ||
	     var->yres != par->max_height)) {
		DRM_ERROR("Tried to resize, but we don't have multimon\n");
	if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) &&
	    (var->xoffset != 0 || var->yoffset != 0)) {
		DRM_ERROR("Can not handle panning without display topology\n");
		return -EINVAL;
	}

	if (var->xres > par->max_width ||
	    var->yres > par->max_height) {
	if ((var->xoffset + var->xres) > par->max_width ||
	    (var->yoffset + var->yres) > par->max_height) {
		DRM_ERROR("Requested geom can not fit in framebuffer\n");
		return -EINVAL;
	}
@@ -154,8 +152,8 @@ static int vmw_fb_set_par(struct fb_info *info)
	struct vmw_fb_par *par = info->par;
	struct vmw_private *vmw_priv = par->vmw_priv;

	if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) {
		vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
	if (vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) {
		vmw_write(vmw_priv, SVGA_REG_ENABLE, 0);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0);
@@ -164,18 +162,11 @@ static int vmw_fb_set_par(struct fb_info *info)
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, 0);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);

		vmw_write(vmw_priv, SVGA_REG_ENABLE, 1);
		vmw_write(vmw_priv, SVGA_REG_WIDTH, par->max_width);
		vmw_write(vmw_priv, SVGA_REG_HEIGHT, par->max_height);
		vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, par->bpp);
		vmw_write(vmw_priv, SVGA_REG_DEPTH, par->depth);
		vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000);
		vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00);
		vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff);
		vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres,
				   info->fix.line_length,
				   par->bpp, par->depth);

		/* TODO check if pitch and offset changes */

		vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, info->var.xoffset);
@@ -183,13 +174,22 @@ static int vmw_fb_set_par(struct fb_info *info)
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, info->var.xres);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
		vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
		vmw_write(vmw_priv, SVGA_REG_ENABLE, 1);
	} else {
		vmw_write(vmw_priv, SVGA_REG_WIDTH, info->var.xres);
		vmw_write(vmw_priv, SVGA_REG_HEIGHT, info->var.yres);
		vmw_write(vmw_priv, SVGA_REG_ENABLE, 0);
		vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres,
				   info->fix.line_length,
				   par->bpp, par->depth);
		vmw_write(vmw_priv, SVGA_REG_ENABLE, 1);

		/* TODO check if pitch and offset changes */
	}

	/* This is really helpful since if this fails the user
	 * can probably not see anything on the screen.
	 */
	WARN_ON(vmw_read(vmw_priv, SVGA_REG_FB_OFFSET) != 0);

	return 0;
}

@@ -416,48 +416,23 @@ int vmw_fb_init(struct vmw_private *vmw_priv)
	unsigned fb_bbp, fb_depth, fb_offset, fb_pitch, fb_size;
	int ret;

	/* XXX These shouldn't be hardcoded. */
	initial_width = 800;
	initial_height = 600;

	fb_bbp = 32;
	fb_depth = 24;

	if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) {
	/* XXX As shouldn't these be as well. */
	fb_width = min(vmw_priv->fb_max_width, (unsigned)2048);
	fb_height = min(vmw_priv->fb_max_height, (unsigned)2048);
	} else {
		fb_width = min(vmw_priv->fb_max_width, initial_width);
		fb_height = min(vmw_priv->fb_max_height, initial_height);
	}

	initial_width = min(fb_width, initial_width);
	initial_height = min(fb_height, initial_height);

	vmw_write(vmw_priv, SVGA_REG_WIDTH, fb_width);
	vmw_write(vmw_priv, SVGA_REG_HEIGHT, fb_height);
	vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, fb_bbp);
	vmw_write(vmw_priv, SVGA_REG_DEPTH, fb_depth);
	vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000);
	vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00);
	vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff);

	fb_size = vmw_read(vmw_priv, SVGA_REG_FB_SIZE);
	fb_pitch = fb_width * fb_bbp / 8;
	fb_size = fb_pitch * fb_height;
	fb_offset = vmw_read(vmw_priv, SVGA_REG_FB_OFFSET);
	fb_pitch = vmw_read(vmw_priv, SVGA_REG_BYTES_PER_LINE);

	DRM_DEBUG("width  %u\n", vmw_read(vmw_priv, SVGA_REG_MAX_WIDTH));
	DRM_DEBUG("height %u\n", vmw_read(vmw_priv, SVGA_REG_MAX_HEIGHT));
	DRM_DEBUG("width  %u\n", vmw_read(vmw_priv, SVGA_REG_WIDTH));
	DRM_DEBUG("height %u\n", vmw_read(vmw_priv, SVGA_REG_HEIGHT));
	DRM_DEBUG("bpp    %u\n", vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL));
	DRM_DEBUG("depth  %u\n", vmw_read(vmw_priv, SVGA_REG_DEPTH));
	DRM_DEBUG("bpl    %u\n", vmw_read(vmw_priv, SVGA_REG_BYTES_PER_LINE));
	DRM_DEBUG("r mask %08x\n", vmw_read(vmw_priv, SVGA_REG_RED_MASK));
	DRM_DEBUG("g mask %08x\n", vmw_read(vmw_priv, SVGA_REG_GREEN_MASK));
	DRM_DEBUG("b mask %08x\n", vmw_read(vmw_priv, SVGA_REG_BLUE_MASK));
	DRM_DEBUG("fb_offset 0x%08x\n", fb_offset);
	DRM_DEBUG("fb_pitch  %u\n", fb_pitch);
	DRM_DEBUG("fb_size   %u kiB\n", fb_size / 1024);

	info = framebuffer_alloc(sizeof(*par), device);
	if (!info)
+18 −0
Original line number Diff line number Diff line
@@ -34,6 +34,9 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
	__le32 __iomem *fifo_mem = dev_priv->mmio_virt;
	uint32_t fifo_min, hwversion;

	if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO))
		return false;

	fifo_min = ioread32(fifo_mem  + SVGA_FIFO_MIN);
	if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int))
		return false;
@@ -48,6 +51,21 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
	return true;
}

bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv)
{
	__le32 __iomem *fifo_mem = dev_priv->mmio_virt;
	uint32_t caps;

	if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO))
		return false;

	caps = ioread32(fifo_mem + SVGA_FIFO_CAPABILITIES);
	if (caps & SVGA_FIFO_CAP_PITCHLOCK)
		return true;

	return false;
}

int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
{
	__le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+31 −41
Original line number Diff line number Diff line
@@ -596,31 +596,11 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb)
		vmw_framebuffer_to_vfbd(&vfb->base);
	int ret;


	vmw_overlay_pause_all(dev_priv);

	ret = vmw_dmabuf_to_start_of_vram(dev_priv, vfbd->buffer);

	if (dev_priv->capabilities & SVGA_CAP_MULTIMON) {
		vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
		vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, 0);
		vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true);
		vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0);
		vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, 0);
		vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, 0);
		vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, 0);
		vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);

		vmw_write(dev_priv, SVGA_REG_ENABLE, 1);
		vmw_write(dev_priv, SVGA_REG_WIDTH, vfb->base.width);
		vmw_write(dev_priv, SVGA_REG_HEIGHT, vfb->base.height);
		vmw_write(dev_priv, SVGA_REG_BITS_PER_PIXEL, vfb->base.bits_per_pixel);
		vmw_write(dev_priv, SVGA_REG_DEPTH, vfb->base.depth);
		vmw_write(dev_priv, SVGA_REG_RED_MASK, 0x00ff0000);
		vmw_write(dev_priv, SVGA_REG_GREEN_MASK, 0x0000ff00);
		vmw_write(dev_priv, SVGA_REG_BLUE_MASK, 0x000000ff);
	} else
		WARN_ON(true);

	vmw_overlay_resume_all(dev_priv);

	return 0;
@@ -668,7 +648,7 @@ int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,

	/* XXX get the first 3 from the surface info */
	vfbd->base.base.bits_per_pixel = 32;
	vfbd->base.base.pitch = width * 32 / 4;
	vfbd->base.base.pitch = width * vfbd->base.base.bits_per_pixel / 8;
	vfbd->base.base.depth = 24;
	vfbd->base.base.width = width;
	vfbd->base.base.height = height;
@@ -827,24 +807,25 @@ int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data,
	return ret;
}

int vmw_kms_save_vga(struct vmw_private *vmw_priv)
void vmw_kms_write_svga(struct vmw_private *vmw_priv,
			unsigned width, unsigned height, unsigned pitch,
			unsigned bbp, unsigned depth)
{
	/*
	 * setup a single multimon monitor with the size
	 * of 0x0, this stops the UI from resizing when we
	 * change the framebuffer size
	 */
	if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) {
		vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, 0);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, 0);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, 0);
		vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
	if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK)
		vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, pitch);
	else if (vmw_fifo_have_pitchlock(vmw_priv))
		iowrite32(pitch, vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK);
	vmw_write(vmw_priv, SVGA_REG_WIDTH, width);
	vmw_write(vmw_priv, SVGA_REG_HEIGHT, height);
	vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, bbp);
	vmw_write(vmw_priv, SVGA_REG_DEPTH, depth);
	vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000);
	vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00);
	vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff);
}

int vmw_kms_save_vga(struct vmw_private *vmw_priv)
{
	vmw_priv->vga_width = vmw_read(vmw_priv, SVGA_REG_WIDTH);
	vmw_priv->vga_height = vmw_read(vmw_priv, SVGA_REG_HEIGHT);
	vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL);
@@ -853,6 +834,12 @@ int vmw_kms_save_vga(struct vmw_private *vmw_priv)
	vmw_priv->vga_red_mask = vmw_read(vmw_priv, SVGA_REG_RED_MASK);
	vmw_priv->vga_green_mask = vmw_read(vmw_priv, SVGA_REG_GREEN_MASK);
	vmw_priv->vga_blue_mask = vmw_read(vmw_priv, SVGA_REG_BLUE_MASK);
	if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK)
		vmw_priv->vga_pitchlock =
			vmw_read(vmw_priv, SVGA_REG_PITCHLOCK);
	else if (vmw_fifo_have_pitchlock(vmw_priv))
		vmw_priv->vga_pitchlock =
			ioread32(vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK);

	return 0;
}
@@ -867,9 +854,12 @@ int vmw_kms_restore_vga(struct vmw_private *vmw_priv)
	vmw_write(vmw_priv, SVGA_REG_RED_MASK, vmw_priv->vga_red_mask);
	vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, vmw_priv->vga_green_mask);
	vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, vmw_priv->vga_blue_mask);

	/* TODO check for multimon */
	vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 0);
	if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK)
		vmw_write(vmw_priv, SVGA_REG_PITCHLOCK,
			  vmw_priv->vga_pitchlock);
	else if (vmw_fifo_have_pitchlock(vmw_priv))
		iowrite32(vmw_priv->vga_pitchlock,
			  vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK);

	return 0;
}
Loading