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

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
...@@ -318,6 +318,15 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) ...@@ -318,6 +318,15 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
goto out_err3; 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->tdev = ttm_object_device_init
(dev_priv->mem_global_ref.object, 12); (dev_priv->mem_global_ref.object, 12);
......
...@@ -187,6 +187,7 @@ struct vmw_private { ...@@ -187,6 +187,7 @@ struct vmw_private {
uint32_t vga_red_mask; uint32_t vga_red_mask;
uint32_t vga_blue_mask; uint32_t vga_blue_mask;
uint32_t vga_green_mask; uint32_t vga_green_mask;
uint32_t vga_pitchlock;
/* /*
* Framebuffer info. * Framebuffer info.
...@@ -401,6 +402,7 @@ extern int vmw_fifo_send_fence(struct vmw_private *dev_priv, ...@@ -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 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 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_3d(struct vmw_private *dev_priv);
extern bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv);
/** /**
* TTM glue - vmwgfx_ttm_glue.c * TTM glue - vmwgfx_ttm_glue.c
...@@ -491,6 +493,9 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, ...@@ -491,6 +493,9 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
struct ttm_object_file *tfile, struct ttm_object_file *tfile,
struct ttm_buffer_object *bo, struct ttm_buffer_object *bo,
SVGA3dCmdHeader *header); 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 * Overlay control - vmwgfx_overlay.c
......
...@@ -132,16 +132,14 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var, ...@@ -132,16 +132,14 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var,
return -EINVAL; return -EINVAL;
} }
/* without multimon its hard to resize */ if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) &&
if (!(vmw_priv->capabilities & SVGA_CAP_MULTIMON) && (var->xoffset != 0 || var->yoffset != 0)) {
(var->xres != par->max_width || DRM_ERROR("Can not handle panning without display topology\n");
var->yres != par->max_height)) {
DRM_ERROR("Tried to resize, but we don't have multimon\n");
return -EINVAL; return -EINVAL;
} }
if (var->xres > par->max_width || if ((var->xoffset + var->xres) > par->max_width ||
var->yres > par->max_height) { (var->yoffset + var->yres) > par->max_height) {
DRM_ERROR("Requested geom can not fit in framebuffer\n"); DRM_ERROR("Requested geom can not fit in framebuffer\n");
return -EINVAL; return -EINVAL;
} }
...@@ -154,8 +152,8 @@ static int vmw_fb_set_par(struct fb_info *info) ...@@ -154,8 +152,8 @@ static int vmw_fb_set_par(struct fb_info *info)
struct vmw_fb_par *par = info->par; struct vmw_fb_par *par = info->par;
struct vmw_private *vmw_priv = par->vmw_priv; struct vmw_private *vmw_priv = par->vmw_priv;
if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) { if (vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) {
vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); vmw_write(vmw_priv, SVGA_REG_ENABLE, 0);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 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_IS_PRIMARY, true);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0); vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0);
...@@ -164,18 +162,11 @@ static int vmw_fb_set_par(struct fb_info *info) ...@@ -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_HEIGHT, 0);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
vmw_write(vmw_priv, SVGA_REG_ENABLE, 1); vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres,
vmw_write(vmw_priv, SVGA_REG_WIDTH, par->max_width); info->fix.line_length,
vmw_write(vmw_priv, SVGA_REG_HEIGHT, par->max_height); par->bpp, par->depth);
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);
/* TODO check if pitch and offset changes */ /* 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_ID, 0);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, info->var.xoffset); 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) ...@@ -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_WIDTH, info->var.xres);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres); 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_DISPLAY_ID, SVGA_ID_INVALID);
vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
vmw_write(vmw_priv, SVGA_REG_ENABLE, 1);
} else { } else {
vmw_write(vmw_priv, SVGA_REG_WIDTH, info->var.xres); vmw_write(vmw_priv, SVGA_REG_ENABLE, 0);
vmw_write(vmw_priv, SVGA_REG_HEIGHT, info->var.yres); 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; return 0;
} }
...@@ -416,48 +416,23 @@ int vmw_fb_init(struct vmw_private *vmw_priv) ...@@ -416,48 +416,23 @@ int vmw_fb_init(struct vmw_private *vmw_priv)
unsigned fb_bbp, fb_depth, fb_offset, fb_pitch, fb_size; unsigned fb_bbp, fb_depth, fb_offset, fb_pitch, fb_size;
int ret; int ret;
/* XXX These shouldn't be hardcoded. */
initial_width = 800; initial_width = 800;
initial_height = 600; initial_height = 600;
fb_bbp = 32; fb_bbp = 32;
fb_depth = 24; 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_width = min(vmw_priv->fb_max_width, (unsigned)2048);
fb_height = min(vmw_priv->fb_max_height, (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_width = min(fb_width, initial_width);
initial_height = min(fb_height, initial_height); initial_height = min(fb_height, initial_height);
vmw_write(vmw_priv, SVGA_REG_WIDTH, fb_width); fb_pitch = fb_width * fb_bbp / 8;
vmw_write(vmw_priv, SVGA_REG_HEIGHT, fb_height); fb_size = fb_pitch * 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_offset = vmw_read(vmw_priv, SVGA_REG_FB_OFFSET); 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); info = framebuffer_alloc(sizeof(*par), device);
if (!info) if (!info)
......
...@@ -34,6 +34,9 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) ...@@ -34,6 +34,9 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
__le32 __iomem *fifo_mem = dev_priv->mmio_virt; __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
uint32_t fifo_min, hwversion; uint32_t fifo_min, hwversion;
if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO))
return false;
fifo_min = ioread32(fifo_mem + SVGA_FIFO_MIN); fifo_min = ioread32(fifo_mem + SVGA_FIFO_MIN);
if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int)) if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int))
return false; return false;
...@@ -48,6 +51,21 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) ...@@ -48,6 +51,21 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
return true; 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) int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
{ {
__le32 __iomem *fifo_mem = dev_priv->mmio_virt; __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
......
...@@ -596,31 +596,11 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) ...@@ -596,31 +596,11 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb)
vmw_framebuffer_to_vfbd(&vfb->base); vmw_framebuffer_to_vfbd(&vfb->base);
int ret; int ret;
vmw_overlay_pause_all(dev_priv); vmw_overlay_pause_all(dev_priv);
ret = vmw_dmabuf_to_start_of_vram(dev_priv, vfbd->buffer); 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); vmw_overlay_resume_all(dev_priv);
return 0; return 0;
...@@ -668,7 +648,7 @@ int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, ...@@ -668,7 +648,7 @@ int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
/* XXX get the first 3 from the surface info */ /* XXX get the first 3 from the surface info */
vfbd->base.base.bits_per_pixel = 32; 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.depth = 24;
vfbd->base.base.width = width; vfbd->base.base.width = width;
vfbd->base.base.height = height; vfbd->base.base.height = height;
...@@ -827,24 +807,25 @@ int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data, ...@@ -827,24 +807,25 @@ int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data,
return ret; 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)
{ {
/* if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK)
* setup a single multimon monitor with the size vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, pitch);
* of 0x0, this stops the UI from resizing when we else if (vmw_fifo_have_pitchlock(vmw_priv))
* change the framebuffer size iowrite32(pitch, vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK);
*/ vmw_write(vmw_priv, SVGA_REG_WIDTH, width);
if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) { vmw_write(vmw_priv, SVGA_REG_HEIGHT, height);
vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, bbp);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); vmw_write(vmw_priv, SVGA_REG_DEPTH, depth);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0); vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, 0); vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff);
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);
}
int vmw_kms_save_vga(struct vmw_private *vmw_priv)
{
vmw_priv->vga_width = vmw_read(vmw_priv, SVGA_REG_WIDTH); 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_height = vmw_read(vmw_priv, SVGA_REG_HEIGHT);
vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL); 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) ...@@ -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_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_green_mask = vmw_read(vmw_priv, SVGA_REG_GREEN_MASK);
vmw_priv->vga_blue_mask = vmw_read(vmw_priv, SVGA_REG_BLUE_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; return 0;
} }
...@@ -867,9 +854,12 @@ int vmw_kms_restore_vga(struct vmw_private *vmw_priv) ...@@ -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_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_GREEN_MASK, vmw_priv->vga_green_mask);
vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, vmw_priv->vga_blue_mask); vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, vmw_priv->vga_blue_mask);
if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK)
/* TODO check for multimon */ vmw_write(vmw_priv, SVGA_REG_PITCHLOCK,
vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 0); 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; return 0;
} }
...@@ -38,6 +38,7 @@ struct vmw_legacy_display { ...@@ -38,6 +38,7 @@ struct vmw_legacy_display {
struct list_head active; struct list_head active;
unsigned num_active; unsigned num_active;
unsigned last_num_active;
struct vmw_framebuffer *fb; struct vmw_framebuffer *fb;
}; };
...@@ -88,12 +89,37 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) ...@@ -88,12 +89,37 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
{ {
struct vmw_legacy_display *lds = dev_priv->ldu_priv; struct vmw_legacy_display *lds = dev_priv->ldu_priv;
struct vmw_legacy_display_unit *entry; struct vmw_legacy_display_unit *entry;
struct drm_crtc *crtc; struct drm_framebuffer *fb = NULL;
struct drm_crtc *crtc = NULL;
int i = 0; int i = 0;
/* to stop the screen from changing size on resize */ /* If there is no display topology the host just assumes
vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 0); * that the guest will set the same layout as the host.
for (i = 0; i < lds->num_active; i++) { */
if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) {
int w = 0, h = 0;
list_for_each_entry(entry, &lds->active, active) {
crtc = &entry->base.crtc;
w = max(w, crtc->x + crtc->mode.hdisplay);
h = max(h, crtc->y + crtc->mode.vdisplay);
i++;
}
if (crtc == NULL)
return 0;
fb = entry->base.crtc.fb;
vmw_write(dev_priv, SVGA_REG_ENABLE, 0);
vmw_kms_write_svga(dev_priv, w, h, fb->pitch,
fb->bits_per_pixel, fb->depth);
vmw_write(dev_priv, SVGA_REG_ENABLE, 1);
return 0;
}
vmw_write(dev_priv, SVGA_REG_ENABLE, 0);
for (i = 0; i < lds->last_num_active; i++) {
vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i); vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i);
vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i); vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i);
vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0); vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0);
...@@ -103,8 +129,14 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) ...@@ -103,8 +129,14 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
} }
/* Now set the mode */ if (!list_empty(&lds->active)) {
vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, lds->num_active); entry = list_entry(lds->active.next, typeof(*entry), active);
fb = entry->base.crtc.fb;
vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitch,
fb->bits_per_pixel, fb->depth);
}
i = 0; i = 0;
list_for_each_entry(entry, &lds->active, active) { list_for_each_entry(entry, &lds->active, active) {
crtc = &entry->base.crtc; crtc = &entry->base.crtc;
...@@ -120,6 +152,14 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) ...@@ -120,6 +152,14 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
i++; i++;
} }
/* Make sure we always show something. */
vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, i ? i : 1);
vmw_write(dev_priv, SVGA_REG_ENABLE, 1);
BUG_ON(i != lds->num_active);
lds->last_num_active = lds->num_active;
return 0; return 0;
} }
...@@ -491,18 +531,22 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv) ...@@ -491,18 +531,22 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv)
INIT_LIST_HEAD(&dev_priv->ldu_priv->active); INIT_LIST_HEAD(&dev_priv->ldu_priv->active);
dev_priv->ldu_priv->num_active = 0; dev_priv->ldu_priv->num_active = 0;
dev_priv->ldu_priv->last_num_active = 0;
dev_priv->ldu_priv->fb = NULL; dev_priv->ldu_priv->fb = NULL;
drm_mode_create_dirty_info_property(dev_priv->dev); drm_mode_create_dirty_info_property(dev_priv->dev);
vmw_ldu_init(dev_priv, 0); vmw_ldu_init(dev_priv, 0);
vmw_ldu_init(dev_priv, 1); /* for old hardware without multimon only enable one display */
vmw_ldu_init(dev_priv, 2); if (dev_priv->capabilities & SVGA_CAP_MULTIMON) {
vmw_ldu_init(dev_priv, 3); vmw_ldu_init(dev_priv, 1);
vmw_ldu_init(dev_priv, 4); vmw_ldu_init(dev_priv, 2);
vmw_ldu_init(dev_priv, 5); vmw_ldu_init(dev_priv, 3);
vmw_ldu_init(dev_priv, 6); vmw_ldu_init(dev_priv, 4);
vmw_ldu_init(dev_priv, 7); vmw_ldu_init(dev_priv, 5);
vmw_ldu_init(dev_priv, 6);
vmw_ldu_init(dev_priv, 7);
}
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment