diff options
author | Jakob Bornecrantz <jakob@vmware.com> | 2011-10-04 14:13:22 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-10-05 05:17:14 -0400 |
commit | 56d1c78df52323cdcd937505dccaa5d665dfab97 (patch) | |
tree | b358c5d21fbf0016507ba554fbf517e549fb4869 /drivers/gpu/drm | |
parent | d991ef0395596c4aeabcded322011d3f5fa9e74e (diff) |
vmwgfx: Add screen object support
Signed-off-by: Jakob Bornecrantz <jakob@vmware.com>
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 34 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 165 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 566 |
7 files changed, 752 insertions, 31 deletions
diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index e13a118b2ee1..586869c8c11f 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile | |||
@@ -5,6 +5,6 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ | |||
5 | vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \ | 5 | vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \ |
6 | vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ | 6 | vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \ |
7 | vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \ | 7 | vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \ |
8 | vmwgfx_fence.o vmwgfx_dmabuf.o | 8 | vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o |
9 | 9 | ||
10 | obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o | 10 | obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index d4829cbf326d..d1e132589963 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | |||
@@ -451,22 +451,28 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) | |||
451 | dev_priv->fman = vmw_fence_manager_init(dev_priv); | 451 | dev_priv->fman = vmw_fence_manager_init(dev_priv); |
452 | if (unlikely(dev_priv->fman == NULL)) | 452 | if (unlikely(dev_priv->fman == NULL)) |
453 | goto out_no_fman; | 453 | goto out_no_fman; |
454 | |||
455 | /* Need to start the fifo to check if we can do screen objects */ | ||
456 | ret = vmw_3d_resource_inc(dev_priv, true); | ||
457 | if (unlikely(ret != 0)) | ||
458 | goto out_no_fifo; | ||
459 | vmw_kms_save_vga(dev_priv); | ||
460 | DRM_INFO("%s", vmw_fifo_have_3d(dev_priv) ? | ||
461 | "Detected device 3D availability.\n" : | ||
462 | "Detected no device 3D availability.\n"); | ||
463 | |||
464 | /* Start kms and overlay systems, needs fifo. */ | ||
454 | ret = vmw_kms_init(dev_priv); | 465 | ret = vmw_kms_init(dev_priv); |
455 | if (unlikely(ret != 0)) | 466 | if (unlikely(ret != 0)) |
456 | goto out_no_kms; | 467 | goto out_no_kms; |
457 | vmw_overlay_init(dev_priv); | 468 | vmw_overlay_init(dev_priv); |
469 | |||
470 | /* We might be done with the fifo now */ | ||
458 | if (dev_priv->enable_fb) { | 471 | if (dev_priv->enable_fb) { |
459 | ret = vmw_3d_resource_inc(dev_priv, false); | ||
460 | if (unlikely(ret != 0)) | ||
461 | goto out_no_fifo; | ||
462 | vmw_kms_save_vga(dev_priv); | ||
463 | vmw_fb_init(dev_priv); | 472 | vmw_fb_init(dev_priv); |
464 | DRM_INFO("%s", vmw_fifo_have_3d(dev_priv) ? | ||
465 | "Detected device 3D availability.\n" : | ||
466 | "Detected no device 3D availability.\n"); | ||
467 | } else { | 473 | } else { |
468 | DRM_INFO("Delayed 3D detection since we're not " | 474 | vmw_kms_restore_vga(dev_priv); |
469 | "running the device in SVGA mode yet.\n"); | 475 | vmw_3d_resource_dec(dev_priv, true); |
470 | } | 476 | } |
471 | 477 | ||
472 | if (dev_priv->capabilities & SVGA_CAP_IRQMASK) { | 478 | if (dev_priv->capabilities & SVGA_CAP_IRQMASK) { |
@@ -483,15 +489,17 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) | |||
483 | return 0; | 489 | return 0; |
484 | 490 | ||
485 | out_no_irq: | 491 | out_no_irq: |
486 | if (dev_priv->enable_fb) { | 492 | if (dev_priv->enable_fb) |
487 | vmw_fb_close(dev_priv); | 493 | vmw_fb_close(dev_priv); |
494 | vmw_overlay_close(dev_priv); | ||
495 | vmw_kms_close(dev_priv); | ||
496 | out_no_kms: | ||
497 | /* We still have a 3D resource reference held */ | ||
498 | if (dev_priv->enable_fb) { | ||
488 | vmw_kms_restore_vga(dev_priv); | 499 | vmw_kms_restore_vga(dev_priv); |
489 | vmw_3d_resource_dec(dev_priv, false); | 500 | vmw_3d_resource_dec(dev_priv, false); |
490 | } | 501 | } |
491 | out_no_fifo: | 502 | out_no_fifo: |
492 | vmw_overlay_close(dev_priv); | ||
493 | vmw_kms_close(dev_priv); | ||
494 | out_no_kms: | ||
495 | vmw_fence_manager_takedown(dev_priv->fman); | 503 | vmw_fence_manager_takedown(dev_priv->fman); |
496 | out_no_fman: | 504 | out_no_fman: |
497 | if (dev_priv->stealth) | 505 | if (dev_priv->stealth) |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 5acf1f2c4987..2124fbc919aa 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | |||
@@ -217,6 +217,7 @@ struct vmw_private { | |||
217 | 217 | ||
218 | void *fb_info; | 218 | void *fb_info; |
219 | struct vmw_legacy_display *ldu_priv; | 219 | struct vmw_legacy_display *ldu_priv; |
220 | struct vmw_screen_object_display *sou_priv; | ||
220 | struct vmw_overlay *overlay_priv; | 221 | struct vmw_overlay *overlay_priv; |
221 | 222 | ||
222 | /* | 223 | /* |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index b3d5120b1f4f..346e2321b016 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | #include "vmwgfx_kms.h" | 28 | #include "vmwgfx_kms.h" |
29 | 29 | ||
30 | |||
30 | /* Might need a hrtimer here? */ | 31 | /* Might need a hrtimer here? */ |
31 | #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) | 32 | #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) |
32 | 33 | ||
@@ -474,6 +475,62 @@ static int do_surface_dirty_ldu(struct vmw_private *dev_priv, | |||
474 | 475 | ||
475 | vmw_fifo_commit(dev_priv, sizeof(*cmd) + (num_clips - 1) * | 476 | vmw_fifo_commit(dev_priv, sizeof(*cmd) + (num_clips - 1) * |
476 | sizeof(cmd->cr)); | 477 | sizeof(cmd->cr)); |
478 | |||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | static int do_surface_dirty_sou(struct vmw_private *dev_priv, | ||
483 | struct vmw_framebuffer *framebuffer, | ||
484 | struct vmw_surface *surf, | ||
485 | unsigned flags, unsigned color, | ||
486 | struct drm_clip_rect *clips, | ||
487 | unsigned num_clips, int inc) | ||
488 | { | ||
489 | int left = clips->x2, right = clips->x1; | ||
490 | int top = clips->y2, bottom = clips->y1; | ||
491 | size_t fifo_size; | ||
492 | int i; | ||
493 | |||
494 | struct { | ||
495 | SVGA3dCmdHeader header; | ||
496 | SVGA3dCmdBlitSurfaceToScreen body; | ||
497 | } *cmd; | ||
498 | |||
499 | |||
500 | fifo_size = sizeof(*cmd); | ||
501 | cmd = vmw_fifo_reserve(dev_priv, fifo_size); | ||
502 | if (unlikely(cmd == NULL)) { | ||
503 | DRM_ERROR("Fifo reserve failed.\n"); | ||
504 | return -ENOMEM; | ||
505 | } | ||
506 | |||
507 | memset(cmd, 0, fifo_size); | ||
508 | |||
509 | cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); | ||
510 | cmd->header.size = cpu_to_le32(sizeof(cmd->body)); | ||
511 | |||
512 | cmd->body.srcImage.sid = cpu_to_le32(surf->res.id); | ||
513 | cmd->body.destScreenId = SVGA_ID_INVALID; /* virtual coords */ | ||
514 | |||
515 | for (i = 0; i < num_clips; i++, clips += inc) { | ||
516 | left = min_t(int, left, (int)clips->x1); | ||
517 | right = max_t(int, right, (int)clips->x2); | ||
518 | top = min_t(int, top, (int)clips->y1); | ||
519 | bottom = max_t(int, bottom, (int)clips->y2); | ||
520 | } | ||
521 | |||
522 | cmd->body.srcRect.left = left; | ||
523 | cmd->body.srcRect.right = right; | ||
524 | cmd->body.srcRect.top = top; | ||
525 | cmd->body.srcRect.bottom = bottom; | ||
526 | |||
527 | cmd->body.destRect.left = left; | ||
528 | cmd->body.destRect.right = right; | ||
529 | cmd->body.destRect.top = top; | ||
530 | cmd->body.destRect.bottom = bottom; | ||
531 | |||
532 | vmw_fifo_commit(dev_priv, fifo_size); | ||
533 | |||
477 | return 0; | 534 | return 0; |
478 | } | 535 | } |
479 | 536 | ||
@@ -498,9 +555,8 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, | |||
498 | if (unlikely(ret != 0)) | 555 | if (unlikely(ret != 0)) |
499 | return ret; | 556 | return ret; |
500 | 557 | ||
501 | if (!num_clips || | 558 | /* Are we using screen objects? */ |
502 | !(dev_priv->fifo.capabilities & | 559 | if (!dev_priv->sou_priv) { |
503 | SVGA_FIFO_CAP_SCREEN_OBJECT)) { | ||
504 | int ret; | 560 | int ret; |
505 | 561 | ||
506 | mutex_lock(&vfbs->work_lock); | 562 | mutex_lock(&vfbs->work_lock); |
@@ -528,9 +584,14 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, | |||
528 | inc = 2; /* skip source rects */ | 584 | inc = 2; /* skip source rects */ |
529 | } | 585 | } |
530 | 586 | ||
531 | ret = do_surface_dirty_ldu(dev_priv, &vfbs->base, surf, | 587 | if (!dev_priv->sou_priv) |
532 | flags, color, | 588 | ret = do_surface_dirty_ldu(dev_priv, &vfbs->base, surf, |
533 | clips, num_clips, inc); | 589 | flags, color, |
590 | clips, num_clips, inc); | ||
591 | else | ||
592 | ret = do_surface_dirty_sou(dev_priv, &vfbs->base, surf, | ||
593 | flags, color, | ||
594 | clips, num_clips, inc); | ||
534 | 595 | ||
535 | ttm_read_unlock(&vmaster->lock); | 596 | ttm_read_unlock(&vmaster->lock); |
536 | return 0; | 597 | return 0; |
@@ -618,8 +679,13 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, | |||
618 | vfbs->base.base.depth = mode_cmd->depth; | 679 | vfbs->base.base.depth = mode_cmd->depth; |
619 | vfbs->base.base.width = mode_cmd->width; | 680 | vfbs->base.base.width = mode_cmd->width; |
620 | vfbs->base.base.height = mode_cmd->height; | 681 | vfbs->base.base.height = mode_cmd->height; |
621 | vfbs->base.pin = &vmw_surface_dmabuf_pin; | 682 | /* Don't need to fill start of vram with empty |
622 | vfbs->base.unpin = &vmw_surface_dmabuf_unpin; | 683 | * buffer if we have screen objects support. |
684 | */ | ||
685 | if (!dev_priv->sou_priv) { | ||
686 | vfbs->base.pin = &vmw_surface_dmabuf_pin; | ||
687 | vfbs->base.unpin = &vmw_surface_dmabuf_unpin; | ||
688 | } | ||
623 | vfbs->surface = surface; | 689 | vfbs->surface = surface; |
624 | vfbs->master = drm_master_get(file_priv->master); | 690 | vfbs->master = drm_master_get(file_priv->master); |
625 | mutex_init(&vfbs->work_lock); | 691 | mutex_init(&vfbs->work_lock); |
@@ -651,6 +717,7 @@ out_err1: | |||
651 | struct vmw_framebuffer_dmabuf { | 717 | struct vmw_framebuffer_dmabuf { |
652 | struct vmw_framebuffer base; | 718 | struct vmw_framebuffer base; |
653 | struct vmw_dma_buffer *buffer; | 719 | struct vmw_dma_buffer *buffer; |
720 | uint32_t handle; | ||
654 | }; | 721 | }; |
655 | 722 | ||
656 | void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) | 723 | void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) |
@@ -699,6 +766,63 @@ static int do_dmabuf_dirty_ldu(struct vmw_private *dev_priv, | |||
699 | return 0; | 766 | return 0; |
700 | } | 767 | } |
701 | 768 | ||
769 | static int do_dmabuf_dirty_sou(struct drm_file *file_priv, | ||
770 | struct vmw_private *dev_priv, | ||
771 | struct vmw_framebuffer *framebuffer, | ||
772 | struct vmw_dma_buffer *buffer, | ||
773 | unsigned flags, unsigned color, | ||
774 | struct drm_clip_rect *clips, | ||
775 | unsigned num_clips, int increment) | ||
776 | { | ||
777 | struct vmw_framebuffer_dmabuf *vfbd = | ||
778 | vmw_framebuffer_to_vfbd(&framebuffer->base); | ||
779 | size_t fifo_size; | ||
780 | int i, ret; | ||
781 | |||
782 | struct { | ||
783 | uint32_t header; | ||
784 | SVGAFifoCmdDefineGMRFB body; | ||
785 | } *cmd; | ||
786 | struct { | ||
787 | uint32_t header; | ||
788 | SVGAFifoCmdBlitGMRFBToScreen body; | ||
789 | } *blits; | ||
790 | |||
791 | fifo_size = sizeof(*cmd) + sizeof(*blits) * num_clips; | ||
792 | cmd = kmalloc(fifo_size, GFP_KERNEL); | ||
793 | if (unlikely(cmd == NULL)) { | ||
794 | DRM_ERROR("Failed to allocate temporary cmd buffer.\n"); | ||
795 | return -ENOMEM; | ||
796 | } | ||
797 | |||
798 | memset(cmd, 0, fifo_size); | ||
799 | cmd->header = SVGA_CMD_DEFINE_GMRFB; | ||
800 | cmd->body.format.bitsPerPixel = framebuffer->base.bits_per_pixel; | ||
801 | cmd->body.format.colorDepth = framebuffer->base.depth; | ||
802 | cmd->body.format.reserved = 0; | ||
803 | cmd->body.bytesPerLine = framebuffer->base.pitch; | ||
804 | cmd->body.ptr.gmrId = vfbd->handle; | ||
805 | cmd->body.ptr.offset = 0; | ||
806 | |||
807 | blits = (void *)&cmd[1]; | ||
808 | for (i = 0; i < num_clips; i++, clips += increment) { | ||
809 | blits[i].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; | ||
810 | blits[i].body.srcOrigin.x = clips->x1; | ||
811 | blits[i].body.srcOrigin.y = clips->y1; | ||
812 | blits[i].body.destRect.left = clips->x1; | ||
813 | blits[i].body.destRect.top = clips->y1; | ||
814 | blits[i].body.destRect.right = clips->x2; | ||
815 | blits[i].body.destRect.bottom = clips->y2; | ||
816 | } | ||
817 | |||
818 | ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, | ||
819 | fifo_size, 0, NULL); | ||
820 | |||
821 | kfree(cmd); | ||
822 | |||
823 | return ret; | ||
824 | } | ||
825 | |||
702 | int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, | 826 | int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, |
703 | struct drm_file *file_priv, | 827 | struct drm_file *file_priv, |
704 | unsigned flags, unsigned color, | 828 | unsigned flags, unsigned color, |
@@ -728,9 +852,15 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, | |||
728 | increment = 2; | 852 | increment = 2; |
729 | } | 853 | } |
730 | 854 | ||
731 | ret = do_dmabuf_dirty_ldu(dev_priv, &vfbd->base, dmabuf, | 855 | if (dev_priv->ldu_priv) { |
732 | flags, color, | 856 | ret = do_dmabuf_dirty_ldu(dev_priv, &vfbd->base, dmabuf, |
733 | clips, num_clips, increment); | 857 | flags, color, |
858 | clips, num_clips, increment); | ||
859 | } else { | ||
860 | ret = do_dmabuf_dirty_sou(file_priv, dev_priv, &vfbd->base, | ||
861 | dmabuf, flags, color, | ||
862 | clips, num_clips, increment); | ||
863 | } | ||
734 | 864 | ||
735 | ttm_read_unlock(&vmaster->lock); | 865 | ttm_read_unlock(&vmaster->lock); |
736 | return ret; | 866 | return ret; |
@@ -801,6 +931,8 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) | |||
801 | vmw_framebuffer_to_vfbd(&vfb->base); | 931 | vmw_framebuffer_to_vfbd(&vfb->base); |
802 | int ret; | 932 | int ret; |
803 | 933 | ||
934 | /* This code should not be used with screen objects */ | ||
935 | BUG_ON(dev_priv->sou_priv); | ||
804 | 936 | ||
805 | vmw_overlay_pause_all(dev_priv); | 937 | vmw_overlay_pause_all(dev_priv); |
806 | 938 | ||
@@ -867,9 +999,12 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, | |||
867 | vfbd->base.base.depth = mode_cmd->depth; | 999 | vfbd->base.base.depth = mode_cmd->depth; |
868 | vfbd->base.base.width = mode_cmd->width; | 1000 | vfbd->base.base.width = mode_cmd->width; |
869 | vfbd->base.base.height = mode_cmd->height; | 1001 | vfbd->base.base.height = mode_cmd->height; |
870 | vfbd->base.pin = vmw_framebuffer_dmabuf_pin; | 1002 | if (!dev_priv->sou_priv) { |
871 | vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin; | 1003 | vfbd->base.pin = vmw_framebuffer_dmabuf_pin; |
1004 | vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin; | ||
1005 | } | ||
872 | vfbd->buffer = dmabuf; | 1006 | vfbd->buffer = dmabuf; |
1007 | vfbd->handle = mode_cmd->handle; | ||
873 | *out = &vfbd->base; | 1008 | *out = &vfbd->base; |
874 | 1009 | ||
875 | return 0; | 1010 | return 0; |
@@ -981,7 +1116,9 @@ int vmw_kms_init(struct vmw_private *dev_priv) | |||
981 | dev->mode_config.max_width = 8192; | 1116 | dev->mode_config.max_width = 8192; |
982 | dev->mode_config.max_height = 8192; | 1117 | dev->mode_config.max_height = 8192; |
983 | 1118 | ||
984 | ret = vmw_kms_init_legacy_display_system(dev_priv); | 1119 | ret = vmw_kms_init_screen_object_display(dev_priv); |
1120 | if (ret) /* Fallback */ | ||
1121 | (void)vmw_kms_init_legacy_display_system(dev_priv); | ||
985 | 1122 | ||
986 | return 0; | 1123 | return 0; |
987 | } | 1124 | } |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 4e4313fd3012..ee16a06e4ca1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | |||
@@ -31,6 +31,8 @@ | |||
31 | #include "drmP.h" | 31 | #include "drmP.h" |
32 | #include "vmwgfx_drv.h" | 32 | #include "vmwgfx_drv.h" |
33 | 33 | ||
34 | #define VMWGFX_NUM_DISPLAY_UNITS 8 | ||
35 | |||
34 | 36 | ||
35 | #define vmw_framebuffer_to_vfb(x) \ | 37 | #define vmw_framebuffer_to_vfb(x) \ |
36 | container_of(x, struct vmw_framebuffer, base) | 38 | container_of(x, struct vmw_framebuffer, base) |
@@ -128,4 +130,12 @@ int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, | |||
128 | int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv); | 130 | int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv); |
129 | int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv); | 131 | int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv); |
130 | 132 | ||
133 | /* | ||
134 | * Screen Objects display functions - vmwgfx_scrn.c | ||
135 | */ | ||
136 | int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv); | ||
137 | int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv); | ||
138 | int vmw_kms_sou_update_layout(struct vmw_private *dev_priv, unsigned num, | ||
139 | struct drm_vmw_rect *rects); | ||
140 | |||
131 | #endif | 141 | #endif |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 4a4e5ccd40d6..7fc8e7de180b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | |||
@@ -27,7 +27,6 @@ | |||
27 | 27 | ||
28 | #include "vmwgfx_kms.h" | 28 | #include "vmwgfx_kms.h" |
29 | 29 | ||
30 | #define VMWGFX_LDU_NUM_DU 8 | ||
31 | 30 | ||
32 | #define vmw_crtc_to_ldu(x) \ | 31 | #define vmw_crtc_to_ldu(x) \ |
33 | container_of(x, struct vmw_legacy_display_unit, base.crtc) | 32 | container_of(x, struct vmw_legacy_display_unit, base.crtc) |
@@ -384,9 +383,9 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv) | |||
384 | drm_mode_create_dirty_info_property(dev_priv->dev); | 383 | drm_mode_create_dirty_info_property(dev_priv->dev); |
385 | 384 | ||
386 | if (dev_priv->capabilities & SVGA_CAP_MULTIMON) { | 385 | if (dev_priv->capabilities & SVGA_CAP_MULTIMON) { |
387 | for (i = 0; i < VMWGFX_LDU_NUM_DU; ++i) | 386 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) |
388 | vmw_ldu_init(dev_priv, i); | 387 | vmw_ldu_init(dev_priv, i); |
389 | ret = drm_vblank_init(dev, VMWGFX_LDU_NUM_DU); | 388 | ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); |
390 | } else { | 389 | } else { |
391 | /* for old hardware without multimon only enable one display */ | 390 | /* for old hardware without multimon only enable one display */ |
392 | vmw_ldu_init(dev_priv, 0); | 391 | vmw_ldu_init(dev_priv, 0); |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c new file mode 100644 index 000000000000..e74b8e31d042 --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | |||
@@ -0,0 +1,566 @@ | |||
1 | /************************************************************************** | ||
2 | * | ||
3 | * Copyright © 2011 VMware, Inc., Palo Alto, CA., USA | ||
4 | * All Rights Reserved. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the | ||
8 | * "Software"), to deal in the Software without restriction, including | ||
9 | * without limitation the rights to use, copy, modify, merge, publish, | ||
10 | * distribute, sub license, and/or sell copies of the Software, and to | ||
11 | * permit persons to whom the Software is furnished to do so, subject to | ||
12 | * the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice (including the | ||
15 | * next paragraph) shall be included in all copies or substantial portions | ||
16 | * of the Software. | ||
17 | * | ||
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
21 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
22 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
23 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
24 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
25 | * | ||
26 | **************************************************************************/ | ||
27 | |||
28 | #include "vmwgfx_kms.h" | ||
29 | |||
30 | |||
31 | #define vmw_crtc_to_sou(x) \ | ||
32 | container_of(x, struct vmw_screen_object_unit, base.crtc) | ||
33 | #define vmw_encoder_to_sou(x) \ | ||
34 | container_of(x, struct vmw_screen_object_unit, base.encoder) | ||
35 | #define vmw_connector_to_sou(x) \ | ||
36 | container_of(x, struct vmw_screen_object_unit, base.connector) | ||
37 | |||
38 | struct vmw_screen_object_display { | ||
39 | struct list_head active; | ||
40 | |||
41 | unsigned num_active; | ||
42 | unsigned last_num_active; | ||
43 | |||
44 | struct vmw_framebuffer *fb; | ||
45 | }; | ||
46 | |||
47 | /** | ||
48 | * Display unit using screen objects. | ||
49 | */ | ||
50 | struct vmw_screen_object_unit { | ||
51 | struct vmw_display_unit base; | ||
52 | |||
53 | unsigned long buffer_size; /**< Size of allocated buffer */ | ||
54 | struct vmw_dma_buffer *buffer; /**< Backing store buffer */ | ||
55 | |||
56 | bool defined; | ||
57 | |||
58 | struct list_head active; | ||
59 | }; | ||
60 | |||
61 | static void vmw_sou_destroy(struct vmw_screen_object_unit *sou) | ||
62 | { | ||
63 | list_del_init(&sou->active); | ||
64 | vmw_display_unit_cleanup(&sou->base); | ||
65 | kfree(sou); | ||
66 | } | ||
67 | |||
68 | |||
69 | /* | ||
70 | * Screen Object Display Unit CRTC functions | ||
71 | */ | ||
72 | |||
73 | static void vmw_sou_crtc_destroy(struct drm_crtc *crtc) | ||
74 | { | ||
75 | vmw_sou_destroy(vmw_crtc_to_sou(crtc)); | ||
76 | } | ||
77 | |||
78 | static int vmw_sou_del_active(struct vmw_private *vmw_priv, | ||
79 | struct vmw_screen_object_unit *sou) | ||
80 | { | ||
81 | struct vmw_screen_object_display *ld = vmw_priv->sou_priv; | ||
82 | if (list_empty(&sou->active)) | ||
83 | return 0; | ||
84 | |||
85 | /* Must init otherwise list_empty(&sou->active) will not work. */ | ||
86 | list_del_init(&sou->active); | ||
87 | if (--(ld->num_active) == 0) { | ||
88 | BUG_ON(!ld->fb); | ||
89 | if (ld->fb->unpin) | ||
90 | ld->fb->unpin(ld->fb); | ||
91 | ld->fb = NULL; | ||
92 | } | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int vmw_sou_add_active(struct vmw_private *vmw_priv, | ||
98 | struct vmw_screen_object_unit *sou, | ||
99 | struct vmw_framebuffer *vfb) | ||
100 | { | ||
101 | struct vmw_screen_object_display *ld = vmw_priv->sou_priv; | ||
102 | struct vmw_screen_object_unit *entry; | ||
103 | struct list_head *at; | ||
104 | |||
105 | BUG_ON(!ld->num_active && ld->fb); | ||
106 | if (vfb != ld->fb) { | ||
107 | if (ld->fb && ld->fb->unpin) | ||
108 | ld->fb->unpin(ld->fb); | ||
109 | if (vfb->pin) | ||
110 | vfb->pin(vfb); | ||
111 | ld->fb = vfb; | ||
112 | } | ||
113 | |||
114 | if (!list_empty(&sou->active)) | ||
115 | return 0; | ||
116 | |||
117 | at = &ld->active; | ||
118 | list_for_each_entry(entry, &ld->active, active) { | ||
119 | if (entry->base.unit > sou->base.unit) | ||
120 | break; | ||
121 | |||
122 | at = &entry->active; | ||
123 | } | ||
124 | |||
125 | list_add(&sou->active, at); | ||
126 | |||
127 | ld->num_active++; | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * Send the fifo command to create a screen. | ||
134 | */ | ||
135 | static int vmw_sou_fifo_create(struct vmw_private *dev_priv, | ||
136 | struct vmw_screen_object_unit *sou, | ||
137 | uint32_t x, uint32_t y, | ||
138 | struct drm_display_mode *mode) | ||
139 | { | ||
140 | size_t fifo_size; | ||
141 | |||
142 | struct { | ||
143 | struct { | ||
144 | uint32_t cmdType; | ||
145 | } header; | ||
146 | SVGAScreenObject obj; | ||
147 | } *cmd; | ||
148 | |||
149 | BUG_ON(!sou->buffer); | ||
150 | |||
151 | fifo_size = sizeof(*cmd); | ||
152 | cmd = vmw_fifo_reserve(dev_priv, fifo_size); | ||
153 | /* The hardware has hung, nothing we can do about it here. */ | ||
154 | if (unlikely(cmd == NULL)) { | ||
155 | DRM_ERROR("Fifo reserve failed.\n"); | ||
156 | return -ENOMEM; | ||
157 | } | ||
158 | |||
159 | memset(cmd, 0, fifo_size); | ||
160 | cmd->header.cmdType = SVGA_CMD_DEFINE_SCREEN; | ||
161 | cmd->obj.structSize = sizeof(SVGAScreenObject); | ||
162 | cmd->obj.id = sou->base.unit; | ||
163 | cmd->obj.flags = SVGA_SCREEN_HAS_ROOT | | ||
164 | (sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0); | ||
165 | cmd->obj.size.width = mode->hdisplay; | ||
166 | cmd->obj.size.height = mode->vdisplay; | ||
167 | cmd->obj.root.x = x; | ||
168 | cmd->obj.root.y = y; | ||
169 | |||
170 | /* Ok to assume that buffer is pinned in vram */ | ||
171 | vmw_dmabuf_get_guest_ptr(sou->buffer, &cmd->obj.backingStore.ptr); | ||
172 | cmd->obj.backingStore.pitch = mode->hdisplay * 4; | ||
173 | |||
174 | vmw_fifo_commit(dev_priv, fifo_size); | ||
175 | |||
176 | sou->defined = true; | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | /** | ||
182 | * Send the fifo command to destroy a screen. | ||
183 | */ | ||
184 | static int vmw_sou_fifo_destroy(struct vmw_private *dev_priv, | ||
185 | struct vmw_screen_object_unit *sou) | ||
186 | { | ||
187 | size_t fifo_size; | ||
188 | int ret; | ||
189 | |||
190 | struct { | ||
191 | struct { | ||
192 | uint32_t cmdType; | ||
193 | } header; | ||
194 | SVGAFifoCmdDestroyScreen body; | ||
195 | } *cmd; | ||
196 | |||
197 | /* no need to do anything */ | ||
198 | if (unlikely(!sou->defined)) | ||
199 | return 0; | ||
200 | |||
201 | fifo_size = sizeof(*cmd); | ||
202 | cmd = vmw_fifo_reserve(dev_priv, fifo_size); | ||
203 | /* the hardware has hung, nothing we can do about it here */ | ||
204 | if (unlikely(cmd == NULL)) { | ||
205 | DRM_ERROR("Fifo reserve failed.\n"); | ||
206 | return -ENOMEM; | ||
207 | } | ||
208 | |||
209 | memset(cmd, 0, fifo_size); | ||
210 | cmd->header.cmdType = SVGA_CMD_DESTROY_SCREEN; | ||
211 | cmd->body.screenId = sou->base.unit; | ||
212 | |||
213 | vmw_fifo_commit(dev_priv, fifo_size); | ||
214 | |||
215 | /* Force sync */ | ||
216 | ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ); | ||
217 | if (unlikely(ret != 0)) | ||
218 | DRM_ERROR("Failed to sync with HW"); | ||
219 | else | ||
220 | sou->defined = false; | ||
221 | |||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | /** | ||
226 | * Free the backing store. | ||
227 | */ | ||
228 | static void vmw_sou_backing_free(struct vmw_private *dev_priv, | ||
229 | struct vmw_screen_object_unit *sou) | ||
230 | { | ||
231 | struct ttm_buffer_object *bo; | ||
232 | |||
233 | if (unlikely(sou->buffer == NULL)) | ||
234 | return; | ||
235 | |||
236 | bo = &sou->buffer->base; | ||
237 | ttm_bo_unref(&bo); | ||
238 | sou->buffer = NULL; | ||
239 | sou->buffer_size = 0; | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * Allocate the backing store for the buffer. | ||
244 | */ | ||
245 | static int vmw_sou_backing_alloc(struct vmw_private *dev_priv, | ||
246 | struct vmw_screen_object_unit *sou, | ||
247 | unsigned long size) | ||
248 | { | ||
249 | int ret; | ||
250 | |||
251 | if (sou->buffer_size == size) | ||
252 | return 0; | ||
253 | |||
254 | if (sou->buffer) | ||
255 | vmw_sou_backing_free(dev_priv, sou); | ||
256 | |||
257 | sou->buffer = kzalloc(sizeof(*sou->buffer), GFP_KERNEL); | ||
258 | if (unlikely(sou->buffer == NULL)) | ||
259 | return -ENOMEM; | ||
260 | |||
261 | /* After we have alloced the backing store might not be able to | ||
262 | * resume the overlays, this is preferred to failing to alloc. | ||
263 | */ | ||
264 | vmw_overlay_pause_all(dev_priv); | ||
265 | ret = vmw_dmabuf_init(dev_priv, sou->buffer, size, | ||
266 | &vmw_vram_ne_placement, | ||
267 | false, &vmw_dmabuf_bo_free); | ||
268 | vmw_overlay_resume_all(dev_priv); | ||
269 | |||
270 | if (unlikely(ret != 0)) | ||
271 | sou->buffer = NULL; /* vmw_dmabuf_init frees on error */ | ||
272 | else | ||
273 | sou->buffer_size = size; | ||
274 | |||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | static int vmw_sou_crtc_set_config(struct drm_mode_set *set) | ||
279 | { | ||
280 | struct vmw_private *dev_priv; | ||
281 | struct vmw_screen_object_unit *sou; | ||
282 | struct drm_connector *connector; | ||
283 | struct drm_display_mode *mode; | ||
284 | struct drm_encoder *encoder; | ||
285 | struct vmw_framebuffer *vfb; | ||
286 | struct drm_framebuffer *fb; | ||
287 | struct drm_crtc *crtc; | ||
288 | int ret = 0; | ||
289 | |||
290 | if (!set) | ||
291 | return -EINVAL; | ||
292 | |||
293 | if (!set->crtc) | ||
294 | return -EINVAL; | ||
295 | |||
296 | /* get the sou */ | ||
297 | crtc = set->crtc; | ||
298 | sou = vmw_crtc_to_sou(crtc); | ||
299 | vfb = set->fb ? vmw_framebuffer_to_vfb(set->fb) : NULL; | ||
300 | dev_priv = vmw_priv(crtc->dev); | ||
301 | |||
302 | if (set->num_connectors > 1) { | ||
303 | DRM_ERROR("to many connectors\n"); | ||
304 | return -EINVAL; | ||
305 | } | ||
306 | |||
307 | if (set->num_connectors == 1 && | ||
308 | set->connectors[0] != &sou->base.connector) { | ||
309 | DRM_ERROR("connector doesn't match %p %p\n", | ||
310 | set->connectors[0], &sou->base.connector); | ||
311 | return -EINVAL; | ||
312 | } | ||
313 | |||
314 | /* sou only supports one fb active at the time */ | ||
315 | if (dev_priv->sou_priv->fb && vfb && | ||
316 | !(dev_priv->sou_priv->num_active == 1 && | ||
317 | !list_empty(&sou->active)) && | ||
318 | dev_priv->sou_priv->fb != vfb) { | ||
319 | DRM_ERROR("Multiple framebuffers not supported\n"); | ||
320 | return -EINVAL; | ||
321 | } | ||
322 | |||
323 | /* since they always map one to one these are safe */ | ||
324 | connector = &sou->base.connector; | ||
325 | encoder = &sou->base.encoder; | ||
326 | |||
327 | /* should we turn the crtc off */ | ||
328 | if (set->num_connectors == 0 || !set->mode || !set->fb) { | ||
329 | ret = vmw_sou_fifo_destroy(dev_priv, sou); | ||
330 | /* the hardware has hung don't do anything more */ | ||
331 | if (unlikely(ret != 0)) | ||
332 | return ret; | ||
333 | |||
334 | connector->encoder = NULL; | ||
335 | encoder->crtc = NULL; | ||
336 | crtc->fb = NULL; | ||
337 | crtc->x = 0; | ||
338 | crtc->y = 0; | ||
339 | |||
340 | vmw_sou_del_active(dev_priv, sou); | ||
341 | |||
342 | vmw_sou_backing_free(dev_priv, sou); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | |||
348 | /* we now know we want to set a mode */ | ||
349 | mode = set->mode; | ||
350 | fb = set->fb; | ||
351 | |||
352 | if (set->x + mode->hdisplay > fb->width || | ||
353 | set->y + mode->vdisplay > fb->height) { | ||
354 | DRM_ERROR("set outside of framebuffer\n"); | ||
355 | return -EINVAL; | ||
356 | } | ||
357 | |||
358 | vmw_fb_off(dev_priv); | ||
359 | |||
360 | if (mode->hdisplay != crtc->mode.hdisplay || | ||
361 | mode->vdisplay != crtc->mode.vdisplay) { | ||
362 | /* no need to check if depth is different, because backing | ||
363 | * store depth is forced to 4 by the device. | ||
364 | */ | ||
365 | |||
366 | ret = vmw_sou_fifo_destroy(dev_priv, sou); | ||
367 | /* the hardware has hung don't do anything more */ | ||
368 | if (unlikely(ret != 0)) | ||
369 | return ret; | ||
370 | |||
371 | vmw_sou_backing_free(dev_priv, sou); | ||
372 | } | ||
373 | |||
374 | if (!sou->buffer) { | ||
375 | /* forced to depth 4 by the device */ | ||
376 | size_t size = mode->hdisplay * mode->vdisplay * 4; | ||
377 | ret = vmw_sou_backing_alloc(dev_priv, sou, size); | ||
378 | if (unlikely(ret != 0)) | ||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | ret = vmw_sou_fifo_create(dev_priv, sou, set->x, set->y, mode); | ||
383 | if (unlikely(ret != 0)) { | ||
384 | /* | ||
385 | * We are in a bit of a situation here, the hardware has | ||
386 | * hung and we may or may not have a buffer hanging of | ||
387 | * the screen object, best thing to do is not do anything | ||
388 | * if we where defined, if not just turn the crtc of. | ||
389 | * Not what userspace wants but it needs to htfu. | ||
390 | */ | ||
391 | if (sou->defined) | ||
392 | return ret; | ||
393 | |||
394 | connector->encoder = NULL; | ||
395 | encoder->crtc = NULL; | ||
396 | crtc->fb = NULL; | ||
397 | crtc->x = 0; | ||
398 | crtc->y = 0; | ||
399 | |||
400 | return ret; | ||
401 | } | ||
402 | |||
403 | vmw_sou_add_active(dev_priv, sou, vfb); | ||
404 | |||
405 | connector->encoder = encoder; | ||
406 | encoder->crtc = crtc; | ||
407 | crtc->mode = *mode; | ||
408 | crtc->fb = fb; | ||
409 | crtc->x = set->x; | ||
410 | crtc->y = set->y; | ||
411 | |||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { | ||
416 | .save = vmw_du_crtc_save, | ||
417 | .restore = vmw_du_crtc_restore, | ||
418 | .cursor_set = vmw_du_crtc_cursor_set, | ||
419 | .cursor_move = vmw_du_crtc_cursor_move, | ||
420 | .gamma_set = vmw_du_crtc_gamma_set, | ||
421 | .destroy = vmw_sou_crtc_destroy, | ||
422 | .set_config = vmw_sou_crtc_set_config, | ||
423 | }; | ||
424 | |||
425 | /* | ||
426 | * Screen Object Display Unit encoder functions | ||
427 | */ | ||
428 | |||
429 | static void vmw_sou_encoder_destroy(struct drm_encoder *encoder) | ||
430 | { | ||
431 | vmw_sou_destroy(vmw_encoder_to_sou(encoder)); | ||
432 | } | ||
433 | |||
434 | static struct drm_encoder_funcs vmw_screen_object_encoder_funcs = { | ||
435 | .destroy = vmw_sou_encoder_destroy, | ||
436 | }; | ||
437 | |||
438 | /* | ||
439 | * Screen Object Display Unit connector functions | ||
440 | */ | ||
441 | |||
442 | static void vmw_sou_connector_destroy(struct drm_connector *connector) | ||
443 | { | ||
444 | vmw_sou_destroy(vmw_connector_to_sou(connector)); | ||
445 | } | ||
446 | |||
447 | static struct drm_connector_funcs vmw_legacy_connector_funcs = { | ||
448 | .dpms = vmw_du_connector_dpms, | ||
449 | .save = vmw_du_connector_save, | ||
450 | .restore = vmw_du_connector_restore, | ||
451 | .detect = vmw_du_connector_detect, | ||
452 | .fill_modes = vmw_du_connector_fill_modes, | ||
453 | .set_property = vmw_du_connector_set_property, | ||
454 | .destroy = vmw_sou_connector_destroy, | ||
455 | }; | ||
456 | |||
457 | static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) | ||
458 | { | ||
459 | struct vmw_screen_object_unit *sou; | ||
460 | struct drm_device *dev = dev_priv->dev; | ||
461 | struct drm_connector *connector; | ||
462 | struct drm_encoder *encoder; | ||
463 | struct drm_crtc *crtc; | ||
464 | |||
465 | sou = kzalloc(sizeof(*sou), GFP_KERNEL); | ||
466 | if (!sou) | ||
467 | return -ENOMEM; | ||
468 | |||
469 | sou->base.unit = unit; | ||
470 | crtc = &sou->base.crtc; | ||
471 | encoder = &sou->base.encoder; | ||
472 | connector = &sou->base.connector; | ||
473 | |||
474 | INIT_LIST_HEAD(&sou->active); | ||
475 | |||
476 | sou->base.pref_active = (unit == 0); | ||
477 | sou->base.pref_width = 800; | ||
478 | sou->base.pref_height = 600; | ||
479 | sou->base.pref_mode = NULL; | ||
480 | |||
481 | drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, | ||
482 | DRM_MODE_CONNECTOR_LVDS); | ||
483 | connector->status = vmw_du_connector_detect(connector, true); | ||
484 | |||
485 | drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs, | ||
486 | DRM_MODE_ENCODER_LVDS); | ||
487 | drm_mode_connector_attach_encoder(connector, encoder); | ||
488 | encoder->possible_crtcs = (1 << unit); | ||
489 | encoder->possible_clones = 0; | ||
490 | |||
491 | drm_crtc_init(dev, crtc, &vmw_screen_object_crtc_funcs); | ||
492 | |||
493 | drm_mode_crtc_set_gamma_size(crtc, 256); | ||
494 | |||
495 | drm_connector_attach_property(connector, | ||
496 | dev->mode_config.dirty_info_property, | ||
497 | 1); | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv) | ||
503 | { | ||
504 | struct drm_device *dev = dev_priv->dev; | ||
505 | int i; | ||
506 | int ret; | ||
507 | |||
508 | if (dev_priv->sou_priv) { | ||
509 | DRM_INFO("sou system already on\n"); | ||
510 | return -EINVAL; | ||
511 | } | ||
512 | |||
513 | if (!(dev_priv->fifo.capabilities & SVGA_FIFO_CAP_SCREEN_OBJECT_2)) { | ||
514 | DRM_INFO("Not using screen objects," | ||
515 | " missing cap SCREEN_OBJECT_2\n"); | ||
516 | return -ENOSYS; | ||
517 | } | ||
518 | |||
519 | ret = -ENOMEM; | ||
520 | dev_priv->sou_priv = kmalloc(sizeof(*dev_priv->sou_priv), GFP_KERNEL); | ||
521 | if (unlikely(!dev_priv->sou_priv)) | ||
522 | goto err_no_mem; | ||
523 | |||
524 | INIT_LIST_HEAD(&dev_priv->sou_priv->active); | ||
525 | dev_priv->sou_priv->num_active = 0; | ||
526 | dev_priv->sou_priv->last_num_active = 0; | ||
527 | dev_priv->sou_priv->fb = NULL; | ||
528 | |||
529 | ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); | ||
530 | if (unlikely(ret != 0)) | ||
531 | goto err_free; | ||
532 | |||
533 | ret = drm_mode_create_dirty_info_property(dev_priv->dev); | ||
534 | if (unlikely(ret != 0)) | ||
535 | goto err_vblank_cleanup; | ||
536 | |||
537 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) | ||
538 | vmw_sou_init(dev_priv, i); | ||
539 | |||
540 | DRM_INFO("Screen objects system initialized\n"); | ||
541 | |||
542 | return 0; | ||
543 | |||
544 | err_vblank_cleanup: | ||
545 | drm_vblank_cleanup(dev); | ||
546 | err_free: | ||
547 | kfree(dev_priv->sou_priv); | ||
548 | err_no_mem: | ||
549 | return ret; | ||
550 | } | ||
551 | |||
552 | int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv) | ||
553 | { | ||
554 | struct drm_device *dev = dev_priv->dev; | ||
555 | |||
556 | drm_vblank_cleanup(dev); | ||
557 | if (!dev_priv->sou_priv) | ||
558 | return -ENOSYS; | ||
559 | |||
560 | if (!list_empty(&dev_priv->sou_priv->active)) | ||
561 | DRM_ERROR("Still have active outputs when unloading driver"); | ||
562 | |||
563 | kfree(dev_priv->sou_priv); | ||
564 | |||
565 | return 0; | ||
566 | } | ||