aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c106
1 files changed, 69 insertions, 37 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 90891593bf6..f7094dde18f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -38,6 +38,7 @@ struct vmw_legacy_display {
38 struct list_head active; 38 struct list_head active;
39 39
40 unsigned num_active; 40 unsigned num_active;
41 unsigned last_num_active;
41 42
42 struct vmw_framebuffer *fb; 43 struct vmw_framebuffer *fb;
43}; 44};
@@ -49,8 +50,6 @@ struct vmw_legacy_display_unit {
49 struct vmw_display_unit base; 50 struct vmw_display_unit base;
50 51
51 struct list_head active; 52 struct list_head active;
52
53 unsigned unit;
54}; 53};
55 54
56static void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu) 55static void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu)
@@ -88,23 +87,44 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
88{ 87{
89 struct vmw_legacy_display *lds = dev_priv->ldu_priv; 88 struct vmw_legacy_display *lds = dev_priv->ldu_priv;
90 struct vmw_legacy_display_unit *entry; 89 struct vmw_legacy_display_unit *entry;
91 struct drm_crtc *crtc; 90 struct drm_framebuffer *fb = NULL;
91 struct drm_crtc *crtc = NULL;
92 int i = 0; 92 int i = 0;
93 93
94 /* to stop the screen from changing size on resize */ 94 /* If there is no display topology the host just assumes
95 vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 0); 95 * that the guest will set the same layout as the host.
96 for (i = 0; i < lds->num_active; i++) { 96 */
97 vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i); 97 if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) {
98 vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i); 98 int w = 0, h = 0;
99 vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0); 99 list_for_each_entry(entry, &lds->active, active) {
100 vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, 0); 100 crtc = &entry->base.crtc;
101 vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, 0); 101 w = max(w, crtc->x + crtc->mode.hdisplay);
102 vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, 0); 102 h = max(h, crtc->y + crtc->mode.vdisplay);
103 vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); 103 i++;
104 }
105
106 if (crtc == NULL)
107 return 0;
108 fb = entry->base.crtc.fb;
109
110 vmw_kms_write_svga(dev_priv, w, h, fb->pitch,
111 fb->bits_per_pixel, fb->depth);
112
113 return 0;
114 }
115
116 if (!list_empty(&lds->active)) {
117 entry = list_entry(lds->active.next, typeof(*entry), active);
118 fb = entry->base.crtc.fb;
119
120 vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitch,
121 fb->bits_per_pixel, fb->depth);
104 } 122 }
105 123
106 /* Now set the mode */ 124 /* Make sure we always show something. */
107 vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, lds->num_active); 125 vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS,
126 lds->num_active ? lds->num_active : 1);
127
108 i = 0; 128 i = 0;
109 list_for_each_entry(entry, &lds->active, active) { 129 list_for_each_entry(entry, &lds->active, active) {
110 crtc = &entry->base.crtc; 130 crtc = &entry->base.crtc;
@@ -120,6 +140,10 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
120 i++; 140 i++;
121 } 141 }
122 142
143 BUG_ON(i != lds->num_active);
144
145 lds->last_num_active = lds->num_active;
146
123 return 0; 147 return 0;
124} 148}
125 149
@@ -130,6 +154,7 @@ static int vmw_ldu_del_active(struct vmw_private *vmw_priv,
130 if (list_empty(&ldu->active)) 154 if (list_empty(&ldu->active))
131 return 0; 155 return 0;
132 156
157 /* Must init otherwise list_empty(&ldu->active) will not work. */
133 list_del_init(&ldu->active); 158 list_del_init(&ldu->active);
134 if (--(ld->num_active) == 0) { 159 if (--(ld->num_active) == 0) {
135 BUG_ON(!ld->fb); 160 BUG_ON(!ld->fb);
@@ -149,24 +174,29 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv,
149 struct vmw_legacy_display_unit *entry; 174 struct vmw_legacy_display_unit *entry;
150 struct list_head *at; 175 struct list_head *at;
151 176
177 BUG_ON(!ld->num_active && ld->fb);
178 if (vfb != ld->fb) {
179 if (ld->fb && ld->fb->unpin)
180 ld->fb->unpin(ld->fb);
181 if (vfb->pin)
182 vfb->pin(vfb);
183 ld->fb = vfb;
184 }
185
152 if (!list_empty(&ldu->active)) 186 if (!list_empty(&ldu->active))
153 return 0; 187 return 0;
154 188
155 at = &ld->active; 189 at = &ld->active;
156 list_for_each_entry(entry, &ld->active, active) { 190 list_for_each_entry(entry, &ld->active, active) {
157 if (entry->unit > ldu->unit) 191 if (entry->base.unit > ldu->base.unit)
158 break; 192 break;
159 193
160 at = &entry->active; 194 at = &entry->active;
161 } 195 }
162 196
163 list_add(&ldu->active, at); 197 list_add(&ldu->active, at);
164 if (ld->num_active++ == 0) { 198
165 BUG_ON(ld->fb); 199 ld->num_active++;
166 if (vfb->pin)
167 vfb->pin(vfb);
168 ld->fb = vfb;
169 }
170 200
171 return 0; 201 return 0;
172} 202}
@@ -208,6 +238,8 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
208 238
209 /* ldu only supports one fb active at the time */ 239 /* ldu only supports one fb active at the time */
210 if (dev_priv->ldu_priv->fb && vfb && 240 if (dev_priv->ldu_priv->fb && vfb &&
241 !(dev_priv->ldu_priv->num_active == 1 &&
242 !list_empty(&ldu->active)) &&
211 dev_priv->ldu_priv->fb != vfb) { 243 dev_priv->ldu_priv->fb != vfb) {
212 DRM_ERROR("Multiple framebuffers not supported\n"); 244 DRM_ERROR("Multiple framebuffers not supported\n");
213 return -EINVAL; 245 return -EINVAL;
@@ -443,18 +475,16 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
443 if (!ldu) 475 if (!ldu)
444 return -ENOMEM; 476 return -ENOMEM;
445 477
446 ldu->unit = unit; 478 ldu->base.unit = unit;
447 crtc = &ldu->base.crtc; 479 crtc = &ldu->base.crtc;
448 encoder = &ldu->base.encoder; 480 encoder = &ldu->base.encoder;
449 connector = &ldu->base.connector; 481 connector = &ldu->base.connector;
450 482
483 INIT_LIST_HEAD(&ldu->active);
484
451 drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, 485 drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
452 DRM_MODE_CONNECTOR_LVDS); 486 DRM_MODE_CONNECTOR_LVDS);
453 /* Initial status */ 487 connector->status = vmw_ldu_connector_detect(connector);
454 if (unit == 0)
455 connector->status = connector_status_connected;
456 else
457 connector->status = connector_status_disconnected;
458 488
459 drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, 489 drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs,
460 DRM_MODE_ENCODER_LVDS); 490 DRM_MODE_ENCODER_LVDS);
@@ -462,8 +492,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
462 encoder->possible_crtcs = (1 << unit); 492 encoder->possible_crtcs = (1 << unit);
463 encoder->possible_clones = 0; 493 encoder->possible_clones = 0;
464 494
465 INIT_LIST_HEAD(&ldu->active);
466
467 drm_crtc_init(dev, crtc, &vmw_legacy_crtc_funcs); 495 drm_crtc_init(dev, crtc, &vmw_legacy_crtc_funcs);
468 496
469 drm_connector_attach_property(connector, 497 drm_connector_attach_property(connector,
@@ -487,18 +515,22 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv)
487 515
488 INIT_LIST_HEAD(&dev_priv->ldu_priv->active); 516 INIT_LIST_HEAD(&dev_priv->ldu_priv->active);
489 dev_priv->ldu_priv->num_active = 0; 517 dev_priv->ldu_priv->num_active = 0;
518 dev_priv->ldu_priv->last_num_active = 0;
490 dev_priv->ldu_priv->fb = NULL; 519 dev_priv->ldu_priv->fb = NULL;
491 520
492 drm_mode_create_dirty_info_property(dev_priv->dev); 521 drm_mode_create_dirty_info_property(dev_priv->dev);
493 522
494 vmw_ldu_init(dev_priv, 0); 523 vmw_ldu_init(dev_priv, 0);
495 vmw_ldu_init(dev_priv, 1); 524 /* for old hardware without multimon only enable one display */
496 vmw_ldu_init(dev_priv, 2); 525 if (dev_priv->capabilities & SVGA_CAP_MULTIMON) {
497 vmw_ldu_init(dev_priv, 3); 526 vmw_ldu_init(dev_priv, 1);
498 vmw_ldu_init(dev_priv, 4); 527 vmw_ldu_init(dev_priv, 2);
499 vmw_ldu_init(dev_priv, 5); 528 vmw_ldu_init(dev_priv, 3);
500 vmw_ldu_init(dev_priv, 6); 529 vmw_ldu_init(dev_priv, 4);
501 vmw_ldu_init(dev_priv, 7); 530 vmw_ldu_init(dev_priv, 5);
531 vmw_ldu_init(dev_priv, 6);
532 vmw_ldu_init(dev_priv, 7);
533 }
502 534
503 return 0; 535 return 0;
504} 536}