diff options
author | Dave Airlie <airlied@redhat.com> | 2016-03-16 18:12:31 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-03-16 18:12:31 -0400 |
commit | 70a09f36d02584fe0025fa14a5cbf276240b2fd4 (patch) | |
tree | 721f77fb4c78cf731fff70bd3095bc74b047d350 | |
parent | 189df01d1cf27b88b3c41f9378453178f76925a8 (diff) | |
parent | 5476aa46ff0377229f780c42e77b7e7e756040c7 (diff) |
Merge tag 'vmwgfx-next-160316' of git://people.freedesktop.org/~thomash/linux into drm-next
Pull request of 2016-03-16
* tag 'vmwgfx-next-160316' of git://people.freedesktop.org/~thomash/linux:
drm/vmwgfx: Bump driver minor
drm/vmwgfx: Allow the UPDATE_LAYOUT ioctl from control nodes
drm/vmwgfx: Send a hotplug event at master_set
drm/vmwgfx: Default to explicit crtc placement for screen targets and screen objects
drm/vmwgfx: Calculate the cursor position based on the crtc gui origin
drm/vmwgfx: Add connector properties to switch between explicit and implicit placement
drm/vmwgfx: Add suggested screen x and y connector properties
drm/vmwgfx: Add implicit framebuffer checks to the screen target code
drm/vmwgfx: Break out implicit fb code
drm/vmwgfx: Rework screen target page flips v2
drm/vmwgfx: Fix screen object page flips for large framebuffers
drm/vmwgfx: Fix a screen object framebuffer dirty corner case
drm/vmwgfx: Add DXGenMips support
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 163 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 19 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 179 | ||||
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 453 |
8 files changed, 496 insertions, 368 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 0ee76e523a90..6cbb7d4bdd11 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | |||
@@ -195,7 +195,7 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { | |||
195 | DRM_MASTER | DRM_AUTH), | 195 | DRM_MASTER | DRM_AUTH), |
196 | VMW_IOCTL_DEF(VMW_UPDATE_LAYOUT, | 196 | VMW_IOCTL_DEF(VMW_UPDATE_LAYOUT, |
197 | vmw_kms_update_layout_ioctl, | 197 | vmw_kms_update_layout_ioctl, |
198 | DRM_MASTER), | 198 | DRM_MASTER | DRM_CONTROL_ALLOW), |
199 | VMW_IOCTL_DEF(VMW_CREATE_SHADER, | 199 | VMW_IOCTL_DEF(VMW_CREATE_SHADER, |
200 | vmw_shader_define_ioctl, | 200 | vmw_shader_define_ioctl, |
201 | DRM_AUTH | DRM_RENDER_ALLOW), | 201 | DRM_AUTH | DRM_RENDER_ALLOW), |
@@ -1204,6 +1204,7 @@ static int vmw_master_set(struct drm_device *dev, | |||
1204 | } | 1204 | } |
1205 | 1205 | ||
1206 | dev_priv->active_master = vmaster; | 1206 | dev_priv->active_master = vmaster; |
1207 | drm_sysfs_hotplug_event(dev); | ||
1207 | 1208 | ||
1208 | return 0; | 1209 | return 0; |
1209 | } | 1210 | } |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 5cb1b1687cd4..019a6ca3e8e9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | |||
@@ -40,9 +40,9 @@ | |||
40 | #include <drm/ttm/ttm_module.h> | 40 | #include <drm/ttm/ttm_module.h> |
41 | #include "vmwgfx_fence.h" | 41 | #include "vmwgfx_fence.h" |
42 | 42 | ||
43 | #define VMWGFX_DRIVER_DATE "20150810" | 43 | #define VMWGFX_DRIVER_DATE "20160210" |
44 | #define VMWGFX_DRIVER_MAJOR 2 | 44 | #define VMWGFX_DRIVER_MAJOR 2 |
45 | #define VMWGFX_DRIVER_MINOR 9 | 45 | #define VMWGFX_DRIVER_MINOR 10 |
46 | #define VMWGFX_DRIVER_PATCHLEVEL 0 | 46 | #define VMWGFX_DRIVER_PATCHLEVEL 0 |
47 | #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 | 47 | #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 |
48 | #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) | 48 | #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) |
@@ -407,8 +407,11 @@ struct vmw_private { | |||
407 | void *fb_info; | 407 | void *fb_info; |
408 | enum vmw_display_unit_type active_display_unit; | 408 | enum vmw_display_unit_type active_display_unit; |
409 | struct vmw_legacy_display *ldu_priv; | 409 | struct vmw_legacy_display *ldu_priv; |
410 | struct vmw_screen_object_display *sou_priv; | ||
411 | struct vmw_overlay *overlay_priv; | 410 | struct vmw_overlay *overlay_priv; |
411 | struct drm_property *hotplug_mode_update_property; | ||
412 | struct drm_property *implicit_placement_property; | ||
413 | unsigned num_implicit; | ||
414 | struct vmw_framebuffer *implicit_fb; | ||
412 | 415 | ||
413 | /* | 416 | /* |
414 | * Context and surface management. | 417 | * Context and surface management. |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 5da5de0cb522..723ba16c6084 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | |||
@@ -3009,6 +3009,26 @@ out_unref: | |||
3009 | return ret; | 3009 | return ret; |
3010 | } | 3010 | } |
3011 | 3011 | ||
3012 | /** | ||
3013 | * vmw_cmd_dx_genmips - Validate an SVGA_3D_CMD_DX_GENMIPS command | ||
3014 | * | ||
3015 | * @dev_priv: Pointer to a device private struct. | ||
3016 | * @sw_context: The software context being used for this batch. | ||
3017 | * @header: Pointer to the command header in the command stream. | ||
3018 | */ | ||
3019 | static int vmw_cmd_dx_genmips(struct vmw_private *dev_priv, | ||
3020 | struct vmw_sw_context *sw_context, | ||
3021 | SVGA3dCmdHeader *header) | ||
3022 | { | ||
3023 | struct { | ||
3024 | SVGA3dCmdHeader header; | ||
3025 | SVGA3dCmdDXGenMips body; | ||
3026 | } *cmd = container_of(header, typeof(*cmd), header); | ||
3027 | |||
3028 | return vmw_view_id_val_add(sw_context, vmw_view_sr, | ||
3029 | cmd->body.shaderResourceViewId); | ||
3030 | } | ||
3031 | |||
3012 | static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv, | 3032 | static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv, |
3013 | struct vmw_sw_context *sw_context, | 3033 | struct vmw_sw_context *sw_context, |
3014 | void *buf, uint32_t *size) | 3034 | void *buf, uint32_t *size) |
@@ -3297,7 +3317,7 @@ static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = { | |||
3297 | &vmw_cmd_dx_clear_depthstencil_view, true, false, true), | 3317 | &vmw_cmd_dx_clear_depthstencil_view, true, false, true), |
3298 | VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY, &vmw_cmd_invalid, | 3318 | VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY, &vmw_cmd_invalid, |
3299 | true, false, true), | 3319 | true, false, true), |
3300 | VMW_CMD_DEF(SVGA_3D_CMD_DX_GENMIPS, &vmw_cmd_invalid, | 3320 | VMW_CMD_DEF(SVGA_3D_CMD_DX_GENMIPS, &vmw_cmd_dx_genmips, |
3301 | true, false, true), | 3321 | true, false, true), |
3302 | VMW_CMD_DEF(SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE, | 3322 | VMW_CMD_DEF(SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE, |
3303 | &vmw_cmd_dx_check_subresource, true, false, true), | 3323 | &vmw_cmd_dx_check_subresource, true, false, true), |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index b221a8c40282..4742ec4ead27 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | |||
@@ -236,8 +236,8 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) | |||
236 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); | 236 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); |
237 | bool shown = du->cursor_surface || du->cursor_dmabuf ? true : false; | 237 | bool shown = du->cursor_surface || du->cursor_dmabuf ? true : false; |
238 | 238 | ||
239 | du->cursor_x = x + crtc->x; | 239 | du->cursor_x = x + du->set_gui_x; |
240 | du->cursor_y = y + crtc->y; | 240 | du->cursor_y = y + du->set_gui_y; |
241 | 241 | ||
242 | /* | 242 | /* |
243 | * FIXME: Unclear whether there's any global state touched by the | 243 | * FIXME: Unclear whether there's any global state touched by the |
@@ -663,9 +663,8 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, | |||
663 | break; | 663 | break; |
664 | case vmw_du_screen_object: | 664 | case vmw_du_screen_object: |
665 | ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, &vfbd->base, | 665 | ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, &vfbd->base, |
666 | clips, num_clips, increment, | 666 | clips, NULL, num_clips, |
667 | true, | 667 | increment, true, NULL); |
668 | NULL); | ||
669 | break; | 668 | break; |
670 | case vmw_du_legacy: | 669 | case vmw_du_legacy: |
671 | ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base, 0, 0, | 670 | ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base, 0, 0, |
@@ -1109,6 +1108,22 @@ int vmw_kms_present(struct vmw_private *dev_priv, | |||
1109 | return 0; | 1108 | return 0; |
1110 | } | 1109 | } |
1111 | 1110 | ||
1111 | static void | ||
1112 | vmw_kms_create_hotplug_mode_update_property(struct vmw_private *dev_priv) | ||
1113 | { | ||
1114 | if (dev_priv->hotplug_mode_update_property) | ||
1115 | return; | ||
1116 | |||
1117 | dev_priv->hotplug_mode_update_property = | ||
1118 | drm_property_create_range(dev_priv->dev, | ||
1119 | DRM_MODE_PROP_IMMUTABLE, | ||
1120 | "hotplug_mode_update", 0, 1); | ||
1121 | |||
1122 | if (!dev_priv->hotplug_mode_update_property) | ||
1123 | return; | ||
1124 | |||
1125 | } | ||
1126 | |||
1112 | int vmw_kms_init(struct vmw_private *dev_priv) | 1127 | int vmw_kms_init(struct vmw_private *dev_priv) |
1113 | { | 1128 | { |
1114 | struct drm_device *dev = dev_priv->dev; | 1129 | struct drm_device *dev = dev_priv->dev; |
@@ -1121,6 +1136,9 @@ int vmw_kms_init(struct vmw_private *dev_priv) | |||
1121 | dev->mode_config.max_width = dev_priv->texture_max_width; | 1136 | dev->mode_config.max_width = dev_priv->texture_max_width; |
1122 | dev->mode_config.max_height = dev_priv->texture_max_height; | 1137 | dev->mode_config.max_height = dev_priv->texture_max_height; |
1123 | 1138 | ||
1139 | drm_mode_create_suggested_offset_properties(dev); | ||
1140 | vmw_kms_create_hotplug_mode_update_property(dev_priv); | ||
1141 | |||
1124 | ret = vmw_kms_stdu_init_display(dev_priv); | 1142 | ret = vmw_kms_stdu_init_display(dev_priv); |
1125 | if (ret) { | 1143 | if (ret) { |
1126 | ret = vmw_kms_sou_init_display(dev_priv); | 1144 | ret = vmw_kms_sou_init_display(dev_priv); |
@@ -1360,15 +1378,28 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, | |||
1360 | du->pref_active = true; | 1378 | du->pref_active = true; |
1361 | du->gui_x = rects[du->unit].x; | 1379 | du->gui_x = rects[du->unit].x; |
1362 | du->gui_y = rects[du->unit].y; | 1380 | du->gui_y = rects[du->unit].y; |
1381 | drm_object_property_set_value | ||
1382 | (&con->base, dev->mode_config.suggested_x_property, | ||
1383 | du->gui_x); | ||
1384 | drm_object_property_set_value | ||
1385 | (&con->base, dev->mode_config.suggested_y_property, | ||
1386 | du->gui_y); | ||
1363 | } else { | 1387 | } else { |
1364 | du->pref_width = 800; | 1388 | du->pref_width = 800; |
1365 | du->pref_height = 600; | 1389 | du->pref_height = 600; |
1366 | du->pref_active = false; | 1390 | du->pref_active = false; |
1391 | drm_object_property_set_value | ||
1392 | (&con->base, dev->mode_config.suggested_x_property, | ||
1393 | 0); | ||
1394 | drm_object_property_set_value | ||
1395 | (&con->base, dev->mode_config.suggested_y_property, | ||
1396 | 0); | ||
1367 | } | 1397 | } |
1368 | con->status = vmw_du_connector_detect(con, true); | 1398 | con->status = vmw_du_connector_detect(con, true); |
1369 | } | 1399 | } |
1370 | 1400 | ||
1371 | mutex_unlock(&dev->mode_config.mutex); | 1401 | mutex_unlock(&dev->mode_config.mutex); |
1402 | drm_sysfs_hotplug_event(dev); | ||
1372 | 1403 | ||
1373 | return 0; | 1404 | return 0; |
1374 | } | 1405 | } |
@@ -1591,6 +1622,12 @@ int vmw_du_connector_set_property(struct drm_connector *connector, | |||
1591 | struct drm_property *property, | 1622 | struct drm_property *property, |
1592 | uint64_t val) | 1623 | uint64_t val) |
1593 | { | 1624 | { |
1625 | struct vmw_display_unit *du = vmw_connector_to_du(connector); | ||
1626 | struct vmw_private *dev_priv = vmw_priv(connector->dev); | ||
1627 | |||
1628 | if (property == dev_priv->implicit_placement_property) | ||
1629 | du->is_implicit = val; | ||
1630 | |||
1594 | return 0; | 1631 | return 0; |
1595 | } | 1632 | } |
1596 | 1633 | ||
@@ -2096,3 +2133,119 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, | |||
2096 | 2133 | ||
2097 | return 0; | 2134 | return 0; |
2098 | } | 2135 | } |
2136 | |||
2137 | /** | ||
2138 | * vmw_kms_del_active - unregister a crtc binding to the implicit framebuffer | ||
2139 | * | ||
2140 | * @dev_priv: Pointer to a device private struct. | ||
2141 | * @du: The display unit of the crtc. | ||
2142 | */ | ||
2143 | void vmw_kms_del_active(struct vmw_private *dev_priv, | ||
2144 | struct vmw_display_unit *du) | ||
2145 | { | ||
2146 | lockdep_assert_held_once(&dev_priv->dev->mode_config.mutex); | ||
2147 | |||
2148 | if (du->active_implicit) { | ||
2149 | if (--(dev_priv->num_implicit) == 0) | ||
2150 | dev_priv->implicit_fb = NULL; | ||
2151 | du->active_implicit = false; | ||
2152 | } | ||
2153 | } | ||
2154 | |||
2155 | /** | ||
2156 | * vmw_kms_add_active - register a crtc binding to an implicit framebuffer | ||
2157 | * | ||
2158 | * @vmw_priv: Pointer to a device private struct. | ||
2159 | * @du: The display unit of the crtc. | ||
2160 | * @vfb: The implicit framebuffer | ||
2161 | * | ||
2162 | * Registers a binding to an implicit framebuffer. | ||
2163 | */ | ||
2164 | void vmw_kms_add_active(struct vmw_private *dev_priv, | ||
2165 | struct vmw_display_unit *du, | ||
2166 | struct vmw_framebuffer *vfb) | ||
2167 | { | ||
2168 | lockdep_assert_held_once(&dev_priv->dev->mode_config.mutex); | ||
2169 | |||
2170 | WARN_ON_ONCE(!dev_priv->num_implicit && dev_priv->implicit_fb); | ||
2171 | |||
2172 | if (!du->active_implicit && du->is_implicit) { | ||
2173 | dev_priv->implicit_fb = vfb; | ||
2174 | du->active_implicit = true; | ||
2175 | dev_priv->num_implicit++; | ||
2176 | } | ||
2177 | } | ||
2178 | |||
2179 | /** | ||
2180 | * vmw_kms_screen_object_flippable - Check whether we can page-flip a crtc. | ||
2181 | * | ||
2182 | * @dev_priv: Pointer to device-private struct. | ||
2183 | * @crtc: The crtc we want to flip. | ||
2184 | * | ||
2185 | * Returns true or false depending whether it's OK to flip this crtc | ||
2186 | * based on the criterion that we must not have more than one implicit | ||
2187 | * frame-buffer at any one time. | ||
2188 | */ | ||
2189 | bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv, | ||
2190 | struct drm_crtc *crtc) | ||
2191 | { | ||
2192 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); | ||
2193 | |||
2194 | lockdep_assert_held_once(&dev_priv->dev->mode_config.mutex); | ||
2195 | |||
2196 | if (!du->is_implicit) | ||
2197 | return true; | ||
2198 | |||
2199 | if (dev_priv->num_implicit != 1) | ||
2200 | return false; | ||
2201 | |||
2202 | return true; | ||
2203 | } | ||
2204 | |||
2205 | /** | ||
2206 | * vmw_kms_update_implicit_fb - Update the implicit fb. | ||
2207 | * | ||
2208 | * @dev_priv: Pointer to device-private struct. | ||
2209 | * @crtc: The crtc the new implicit frame-buffer is bound to. | ||
2210 | */ | ||
2211 | void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv, | ||
2212 | struct drm_crtc *crtc) | ||
2213 | { | ||
2214 | struct vmw_display_unit *du = vmw_crtc_to_du(crtc); | ||
2215 | struct vmw_framebuffer *vfb; | ||
2216 | |||
2217 | lockdep_assert_held_once(&dev_priv->dev->mode_config.mutex); | ||
2218 | |||
2219 | if (!du->is_implicit) | ||
2220 | return; | ||
2221 | |||
2222 | vfb = vmw_framebuffer_to_vfb(crtc->primary->fb); | ||
2223 | WARN_ON_ONCE(dev_priv->num_implicit != 1 && | ||
2224 | dev_priv->implicit_fb != vfb); | ||
2225 | |||
2226 | dev_priv->implicit_fb = vfb; | ||
2227 | } | ||
2228 | |||
2229 | /** | ||
2230 | * vmw_kms_create_implicit_placement_proparty - Set up the implicit placement | ||
2231 | * property. | ||
2232 | * | ||
2233 | * @dev_priv: Pointer to a device private struct. | ||
2234 | * @immutable: Whether the property is immutable. | ||
2235 | * | ||
2236 | * Sets up the implicit placement property unless it's already set up. | ||
2237 | */ | ||
2238 | void | ||
2239 | vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv, | ||
2240 | bool immutable) | ||
2241 | { | ||
2242 | if (dev_priv->implicit_placement_property) | ||
2243 | return; | ||
2244 | |||
2245 | dev_priv->implicit_placement_property = | ||
2246 | drm_property_create_range(dev_priv->dev, | ||
2247 | immutable ? | ||
2248 | DRM_MODE_PROP_IMMUTABLE : 0, | ||
2249 | "implicit_placement", 0, 1); | ||
2250 | |||
2251 | } | ||
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index edd81503516d..57203212c501 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | |||
@@ -178,6 +178,9 @@ struct vmw_display_unit { | |||
178 | int gui_x; | 178 | int gui_x; |
179 | int gui_y; | 179 | int gui_y; |
180 | bool is_implicit; | 180 | bool is_implicit; |
181 | bool active_implicit; | ||
182 | int set_gui_x; | ||
183 | int set_gui_y; | ||
181 | }; | 184 | }; |
182 | 185 | ||
183 | #define vmw_crtc_to_du(x) \ | 186 | #define vmw_crtc_to_du(x) \ |
@@ -254,6 +257,18 @@ int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, | |||
254 | struct drm_crtc **p_crtc, | 257 | struct drm_crtc **p_crtc, |
255 | struct drm_display_mode **p_mode); | 258 | struct drm_display_mode **p_mode); |
256 | void vmw_guess_mode_timing(struct drm_display_mode *mode); | 259 | void vmw_guess_mode_timing(struct drm_display_mode *mode); |
260 | void vmw_kms_del_active(struct vmw_private *dev_priv, | ||
261 | struct vmw_display_unit *du); | ||
262 | void vmw_kms_add_active(struct vmw_private *dev_priv, | ||
263 | struct vmw_display_unit *du, | ||
264 | struct vmw_framebuffer *vfb); | ||
265 | bool vmw_kms_crtc_flippable(struct vmw_private *dev_priv, | ||
266 | struct drm_crtc *crtc); | ||
267 | void vmw_kms_update_implicit_fb(struct vmw_private *dev_priv, | ||
268 | struct drm_crtc *crtc); | ||
269 | void vmw_kms_create_implicit_placement_property(struct vmw_private *dev_priv, | ||
270 | bool immutable); | ||
271 | |||
257 | 272 | ||
258 | /* | 273 | /* |
259 | * Legacy display unit functions - vmwgfx_ldu.c | 274 | * Legacy display unit functions - vmwgfx_ldu.c |
@@ -287,6 +302,7 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, | |||
287 | int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, | 302 | int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, |
288 | struct vmw_framebuffer *framebuffer, | 303 | struct vmw_framebuffer *framebuffer, |
289 | struct drm_clip_rect *clips, | 304 | struct drm_clip_rect *clips, |
305 | struct drm_vmw_rect *vclips, | ||
290 | unsigned num_clips, int increment, | 306 | unsigned num_clips, int increment, |
291 | bool interruptible, | 307 | bool interruptible, |
292 | struct vmw_fence_obj **out_fence); | 308 | struct vmw_fence_obj **out_fence); |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index b6fa44fe8929..63ccd9871ec9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | |||
@@ -288,6 +288,8 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set) | |||
288 | crtc->y = set->y; | 288 | crtc->y = set->y; |
289 | crtc->mode = *mode; | 289 | crtc->mode = *mode; |
290 | crtc->enabled = true; | 290 | crtc->enabled = true; |
291 | ldu->base.set_gui_x = set->x; | ||
292 | ldu->base.set_gui_y = set->y; | ||
291 | 293 | ||
292 | vmw_ldu_add_active(dev_priv, ldu, vfb); | 294 | vmw_ldu_add_active(dev_priv, ldu, vfb); |
293 | 295 | ||
@@ -375,8 +377,19 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) | |||
375 | drm_mode_crtc_set_gamma_size(crtc, 256); | 377 | drm_mode_crtc_set_gamma_size(crtc, 256); |
376 | 378 | ||
377 | drm_object_attach_property(&connector->base, | 379 | drm_object_attach_property(&connector->base, |
378 | dev->mode_config.dirty_info_property, | 380 | dev->mode_config.dirty_info_property, |
379 | 1); | 381 | 1); |
382 | drm_object_attach_property(&connector->base, | ||
383 | dev_priv->hotplug_mode_update_property, 1); | ||
384 | drm_object_attach_property(&connector->base, | ||
385 | dev->mode_config.suggested_x_property, 0); | ||
386 | drm_object_attach_property(&connector->base, | ||
387 | dev->mode_config.suggested_y_property, 0); | ||
388 | if (dev_priv->implicit_placement_property) | ||
389 | drm_object_attach_property | ||
390 | (&connector->base, | ||
391 | dev_priv->implicit_placement_property, | ||
392 | 1); | ||
380 | 393 | ||
381 | return 0; | 394 | return 0; |
382 | } | 395 | } |
@@ -412,6 +425,8 @@ int vmw_kms_ldu_init_display(struct vmw_private *dev_priv) | |||
412 | if (ret != 0) | 425 | if (ret != 0) |
413 | goto err_vblank_cleanup; | 426 | goto err_vblank_cleanup; |
414 | 427 | ||
428 | vmw_kms_create_implicit_placement_property(dev_priv, true); | ||
429 | |||
415 | if (dev_priv->capabilities & SVGA_CAP_MULTIMON) | 430 | if (dev_priv->capabilities & SVGA_CAP_MULTIMON) |
416 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) | 431 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) |
417 | vmw_ldu_init(dev_priv, i); | 432 | vmw_ldu_init(dev_priv, i); |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index c5a1a08b0449..0ea22fd112c9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | |||
@@ -74,19 +74,6 @@ struct vmw_kms_sou_dirty_cmd { | |||
74 | SVGA3dCmdBlitSurfaceToScreen body; | 74 | SVGA3dCmdBlitSurfaceToScreen body; |
75 | }; | 75 | }; |
76 | 76 | ||
77 | |||
78 | /* | ||
79 | * Other structs. | ||
80 | */ | ||
81 | |||
82 | struct vmw_screen_object_display { | ||
83 | unsigned num_implicit; | ||
84 | |||
85 | struct vmw_framebuffer *implicit_fb; | ||
86 | SVGAFifoCmdDefineGMRFB cur; | ||
87 | struct vmw_dma_buffer *pinned_gmrfb; | ||
88 | }; | ||
89 | |||
90 | /** | 77 | /** |
91 | * Display unit using screen objects. | 78 | * Display unit using screen objects. |
92 | */ | 79 | */ |
@@ -97,7 +84,6 @@ struct vmw_screen_object_unit { | |||
97 | struct vmw_dma_buffer *buffer; /**< Backing store buffer */ | 84 | struct vmw_dma_buffer *buffer; /**< Backing store buffer */ |
98 | 85 | ||
99 | bool defined; | 86 | bool defined; |
100 | bool active_implicit; | ||
101 | }; | 87 | }; |
102 | 88 | ||
103 | static void vmw_sou_destroy(struct vmw_screen_object_unit *sou) | 89 | static void vmw_sou_destroy(struct vmw_screen_object_unit *sou) |
@@ -116,33 +102,6 @@ static void vmw_sou_crtc_destroy(struct drm_crtc *crtc) | |||
116 | vmw_sou_destroy(vmw_crtc_to_sou(crtc)); | 102 | vmw_sou_destroy(vmw_crtc_to_sou(crtc)); |
117 | } | 103 | } |
118 | 104 | ||
119 | static void vmw_sou_del_active(struct vmw_private *vmw_priv, | ||
120 | struct vmw_screen_object_unit *sou) | ||
121 | { | ||
122 | struct vmw_screen_object_display *ld = vmw_priv->sou_priv; | ||
123 | |||
124 | if (sou->active_implicit) { | ||
125 | if (--(ld->num_implicit) == 0) | ||
126 | ld->implicit_fb = NULL; | ||
127 | sou->active_implicit = false; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | static void vmw_sou_add_active(struct vmw_private *vmw_priv, | ||
132 | struct vmw_screen_object_unit *sou, | ||
133 | struct vmw_framebuffer *vfb) | ||
134 | { | ||
135 | struct vmw_screen_object_display *ld = vmw_priv->sou_priv; | ||
136 | |||
137 | BUG_ON(!ld->num_implicit && ld->implicit_fb); | ||
138 | |||
139 | if (!sou->active_implicit && sou->base.is_implicit) { | ||
140 | ld->implicit_fb = vfb; | ||
141 | sou->active_implicit = true; | ||
142 | ld->num_implicit++; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | /** | 105 | /** |
147 | * Send the fifo command to create a screen. | 106 | * Send the fifo command to create a screen. |
148 | */ | 107 | */ |
@@ -185,6 +144,8 @@ static int vmw_sou_fifo_create(struct vmw_private *dev_priv, | |||
185 | cmd->obj.root.x = sou->base.gui_x; | 144 | cmd->obj.root.x = sou->base.gui_x; |
186 | cmd->obj.root.y = sou->base.gui_y; | 145 | cmd->obj.root.y = sou->base.gui_y; |
187 | } | 146 | } |
147 | sou->base.set_gui_x = cmd->obj.root.x; | ||
148 | sou->base.set_gui_y = cmd->obj.root.y; | ||
188 | 149 | ||
189 | /* Ok to assume that buffer is pinned in vram */ | 150 | /* Ok to assume that buffer is pinned in vram */ |
190 | vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr); | 151 | vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr); |
@@ -323,13 +284,13 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) | |||
323 | return -EINVAL; | 284 | return -EINVAL; |
324 | } | 285 | } |
325 | 286 | ||
326 | /* sou only supports one fb active at the time */ | 287 | /* Only one active implicit frame-buffer at a time. */ |
327 | if (sou->base.is_implicit && | 288 | if (sou->base.is_implicit && |
328 | dev_priv->sou_priv->implicit_fb && vfb && | 289 | dev_priv->implicit_fb && vfb && |
329 | !(dev_priv->sou_priv->num_implicit == 1 && | 290 | !(dev_priv->num_implicit == 1 && |
330 | sou->active_implicit) && | 291 | sou->base.active_implicit) && |
331 | dev_priv->sou_priv->implicit_fb != vfb) { | 292 | dev_priv->implicit_fb != vfb) { |
332 | DRM_ERROR("Multiple framebuffers not supported\n"); | 293 | DRM_ERROR("Multiple implicit framebuffers not supported.\n"); |
333 | return -EINVAL; | 294 | return -EINVAL; |
334 | } | 295 | } |
335 | 296 | ||
@@ -351,7 +312,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) | |||
351 | crtc->y = 0; | 312 | crtc->y = 0; |
352 | crtc->enabled = false; | 313 | crtc->enabled = false; |
353 | 314 | ||
354 | vmw_sou_del_active(dev_priv, sou); | 315 | vmw_kms_del_active(dev_priv, &sou->base); |
355 | 316 | ||
356 | vmw_sou_backing_free(dev_priv, sou); | 317 | vmw_sou_backing_free(dev_priv, sou); |
357 | 318 | ||
@@ -415,7 +376,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) | |||
415 | return ret; | 376 | return ret; |
416 | } | 377 | } |
417 | 378 | ||
418 | vmw_sou_add_active(dev_priv, sou, vfb); | 379 | vmw_kms_add_active(dev_priv, &sou->base, vfb); |
419 | 380 | ||
420 | connector->encoder = encoder; | 381 | connector->encoder = encoder; |
421 | encoder->crtc = crtc; | 382 | encoder->crtc = crtc; |
@@ -428,39 +389,6 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) | |||
428 | return 0; | 389 | return 0; |
429 | } | 390 | } |
430 | 391 | ||
431 | /** | ||
432 | * Returns if this unit can be page flipped. | ||
433 | * Must be called with the mode_config mutex held. | ||
434 | */ | ||
435 | static bool vmw_sou_screen_object_flippable(struct vmw_private *dev_priv, | ||
436 | struct drm_crtc *crtc) | ||
437 | { | ||
438 | struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc); | ||
439 | |||
440 | if (!sou->base.is_implicit) | ||
441 | return true; | ||
442 | |||
443 | if (dev_priv->sou_priv->num_implicit != 1) | ||
444 | return false; | ||
445 | |||
446 | return true; | ||
447 | } | ||
448 | |||
449 | /** | ||
450 | * Update the implicit fb to the current fb of this crtc. | ||
451 | * Must be called with the mode_config mutex held. | ||
452 | */ | ||
453 | static void vmw_sou_update_implicit_fb(struct vmw_private *dev_priv, | ||
454 | struct drm_crtc *crtc) | ||
455 | { | ||
456 | struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc); | ||
457 | |||
458 | BUG_ON(!sou->base.is_implicit); | ||
459 | |||
460 | dev_priv->sou_priv->implicit_fb = | ||
461 | vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb); | ||
462 | } | ||
463 | |||
464 | static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, | 392 | static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, |
465 | struct drm_framebuffer *fb, | 393 | struct drm_framebuffer *fb, |
466 | struct drm_pending_vblank_event *event, | 394 | struct drm_pending_vblank_event *event, |
@@ -470,30 +398,27 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, | |||
470 | struct drm_framebuffer *old_fb = crtc->primary->fb; | 398 | struct drm_framebuffer *old_fb = crtc->primary->fb; |
471 | struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb); | 399 | struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb); |
472 | struct vmw_fence_obj *fence = NULL; | 400 | struct vmw_fence_obj *fence = NULL; |
473 | struct drm_clip_rect clips; | 401 | struct drm_vmw_rect vclips; |
474 | int ret; | 402 | int ret; |
475 | 403 | ||
476 | /* require ScreenObject support for page flipping */ | 404 | if (!vmw_kms_crtc_flippable(dev_priv, crtc)) |
477 | if (!dev_priv->sou_priv) | ||
478 | return -ENOSYS; | ||
479 | |||
480 | if (!vmw_sou_screen_object_flippable(dev_priv, crtc)) | ||
481 | return -EINVAL; | 405 | return -EINVAL; |
482 | 406 | ||
483 | crtc->primary->fb = fb; | 407 | crtc->primary->fb = fb; |
484 | 408 | ||
485 | /* do a full screen dirty update */ | 409 | /* do a full screen dirty update */ |
486 | clips.x1 = clips.y1 = 0; | 410 | vclips.x = crtc->x; |
487 | clips.x2 = fb->width; | 411 | vclips.y = crtc->y; |
488 | clips.y2 = fb->height; | 412 | vclips.w = crtc->mode.hdisplay; |
413 | vclips.h = crtc->mode.vdisplay; | ||
489 | 414 | ||
490 | if (vfb->dmabuf) | 415 | if (vfb->dmabuf) |
491 | ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, vfb, | 416 | ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, vfb, |
492 | &clips, 1, 1, | 417 | NULL, &vclips, 1, 1, |
493 | true, &fence); | 418 | true, &fence); |
494 | else | 419 | else |
495 | ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, | 420 | ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, |
496 | &clips, NULL, NULL, | 421 | NULL, &vclips, NULL, |
497 | 0, 0, 1, 1, &fence); | 422 | 0, 0, 1, 1, &fence); |
498 | 423 | ||
499 | 424 | ||
@@ -521,7 +446,7 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, | |||
521 | vmw_fence_obj_unreference(&fence); | 446 | vmw_fence_obj_unreference(&fence); |
522 | 447 | ||
523 | if (vmw_crtc_to_du(crtc)->is_implicit) | 448 | if (vmw_crtc_to_du(crtc)->is_implicit) |
524 | vmw_sou_update_implicit_fb(dev_priv, crtc); | 449 | vmw_kms_update_implicit_fb(dev_priv, crtc); |
525 | 450 | ||
526 | return ret; | 451 | return ret; |
527 | 452 | ||
@@ -586,13 +511,12 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) | |||
586 | encoder = &sou->base.encoder; | 511 | encoder = &sou->base.encoder; |
587 | connector = &sou->base.connector; | 512 | connector = &sou->base.connector; |
588 | 513 | ||
589 | sou->active_implicit = false; | 514 | sou->base.active_implicit = false; |
590 | |||
591 | sou->base.pref_active = (unit == 0); | 515 | sou->base.pref_active = (unit == 0); |
592 | sou->base.pref_width = dev_priv->initial_width; | 516 | sou->base.pref_width = dev_priv->initial_width; |
593 | sou->base.pref_height = dev_priv->initial_height; | 517 | sou->base.pref_height = dev_priv->initial_height; |
594 | sou->base.pref_mode = NULL; | 518 | sou->base.pref_mode = NULL; |
595 | sou->base.is_implicit = true; | 519 | sou->base.is_implicit = false; |
596 | 520 | ||
597 | drm_connector_init(dev, connector, &vmw_sou_connector_funcs, | 521 | drm_connector_init(dev, connector, &vmw_sou_connector_funcs, |
598 | DRM_MODE_CONNECTOR_VIRTUAL); | 522 | DRM_MODE_CONNECTOR_VIRTUAL); |
@@ -611,8 +535,19 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) | |||
611 | drm_mode_crtc_set_gamma_size(crtc, 256); | 535 | drm_mode_crtc_set_gamma_size(crtc, 256); |
612 | 536 | ||
613 | drm_object_attach_property(&connector->base, | 537 | drm_object_attach_property(&connector->base, |
614 | dev->mode_config.dirty_info_property, | 538 | dev->mode_config.dirty_info_property, |
615 | 1); | 539 | 1); |
540 | drm_object_attach_property(&connector->base, | ||
541 | dev_priv->hotplug_mode_update_property, 1); | ||
542 | drm_object_attach_property(&connector->base, | ||
543 | dev->mode_config.suggested_x_property, 0); | ||
544 | drm_object_attach_property(&connector->base, | ||
545 | dev->mode_config.suggested_y_property, 0); | ||
546 | if (dev_priv->implicit_placement_property) | ||
547 | drm_object_attach_property | ||
548 | (&connector->base, | ||
549 | dev_priv->implicit_placement_property, | ||
550 | sou->base.is_implicit); | ||
616 | 551 | ||
617 | return 0; | 552 | return 0; |
618 | } | 553 | } |
@@ -622,11 +557,6 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) | |||
622 | struct drm_device *dev = dev_priv->dev; | 557 | struct drm_device *dev = dev_priv->dev; |
623 | int i, ret; | 558 | int i, ret; |
624 | 559 | ||
625 | if (dev_priv->sou_priv) { | ||
626 | DRM_INFO("sou system already on\n"); | ||
627 | return -EINVAL; | ||
628 | } | ||
629 | |||
630 | if (!(dev_priv->capabilities & SVGA_CAP_SCREEN_OBJECT_2)) { | 560 | if (!(dev_priv->capabilities & SVGA_CAP_SCREEN_OBJECT_2)) { |
631 | DRM_INFO("Not using screen objects," | 561 | DRM_INFO("Not using screen objects," |
632 | " missing cap SCREEN_OBJECT_2\n"); | 562 | " missing cap SCREEN_OBJECT_2\n"); |
@@ -634,21 +564,19 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) | |||
634 | } | 564 | } |
635 | 565 | ||
636 | ret = -ENOMEM; | 566 | ret = -ENOMEM; |
637 | dev_priv->sou_priv = kmalloc(sizeof(*dev_priv->sou_priv), GFP_KERNEL); | 567 | dev_priv->num_implicit = 0; |
638 | if (unlikely(!dev_priv->sou_priv)) | 568 | dev_priv->implicit_fb = NULL; |
639 | goto err_no_mem; | ||
640 | |||
641 | dev_priv->sou_priv->num_implicit = 0; | ||
642 | dev_priv->sou_priv->implicit_fb = NULL; | ||
643 | 569 | ||
644 | ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); | 570 | ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); |
645 | if (unlikely(ret != 0)) | 571 | if (unlikely(ret != 0)) |
646 | goto err_free; | 572 | return ret; |
647 | 573 | ||
648 | ret = drm_mode_create_dirty_info_property(dev); | 574 | ret = drm_mode_create_dirty_info_property(dev); |
649 | if (unlikely(ret != 0)) | 575 | if (unlikely(ret != 0)) |
650 | goto err_vblank_cleanup; | 576 | goto err_vblank_cleanup; |
651 | 577 | ||
578 | vmw_kms_create_implicit_placement_property(dev_priv, false); | ||
579 | |||
652 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) | 580 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) |
653 | vmw_sou_init(dev_priv, i); | 581 | vmw_sou_init(dev_priv, i); |
654 | 582 | ||
@@ -660,10 +588,6 @@ int vmw_kms_sou_init_display(struct vmw_private *dev_priv) | |||
660 | 588 | ||
661 | err_vblank_cleanup: | 589 | err_vblank_cleanup: |
662 | drm_vblank_cleanup(dev); | 590 | drm_vblank_cleanup(dev); |
663 | err_free: | ||
664 | kfree(dev_priv->sou_priv); | ||
665 | dev_priv->sou_priv = NULL; | ||
666 | err_no_mem: | ||
667 | return ret; | 591 | return ret; |
668 | } | 592 | } |
669 | 593 | ||
@@ -671,13 +595,8 @@ int vmw_kms_sou_close_display(struct vmw_private *dev_priv) | |||
671 | { | 595 | { |
672 | struct drm_device *dev = dev_priv->dev; | 596 | struct drm_device *dev = dev_priv->dev; |
673 | 597 | ||
674 | if (!dev_priv->sou_priv) | ||
675 | return -ENOSYS; | ||
676 | |||
677 | drm_vblank_cleanup(dev); | 598 | drm_vblank_cleanup(dev); |
678 | 599 | ||
679 | kfree(dev_priv->sou_priv); | ||
680 | |||
681 | return 0; | 600 | return 0; |
682 | } | 601 | } |
683 | 602 | ||
@@ -738,6 +657,11 @@ static void vmw_sou_surface_fifo_commit(struct vmw_kms_dirty *dirty) | |||
738 | SVGASignedRect *blit = (SVGASignedRect *) &cmd[1]; | 657 | SVGASignedRect *blit = (SVGASignedRect *) &cmd[1]; |
739 | int i; | 658 | int i; |
740 | 659 | ||
660 | if (!dirty->num_hits) { | ||
661 | vmw_fifo_commit(dirty->dev_priv, 0); | ||
662 | return; | ||
663 | } | ||
664 | |||
741 | cmd->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN; | 665 | cmd->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN; |
742 | cmd->header.size = sizeof(cmd->body) + region_size; | 666 | cmd->header.size = sizeof(cmd->body) + region_size; |
743 | 667 | ||
@@ -875,6 +799,11 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, | |||
875 | */ | 799 | */ |
876 | static void vmw_sou_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty) | 800 | static void vmw_sou_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty) |
877 | { | 801 | { |
802 | if (!dirty->num_hits) { | ||
803 | vmw_fifo_commit(dirty->dev_priv, 0); | ||
804 | return; | ||
805 | } | ||
806 | |||
878 | vmw_fifo_commit(dirty->dev_priv, | 807 | vmw_fifo_commit(dirty->dev_priv, |
879 | sizeof(struct vmw_kms_sou_dmabuf_blit) * | 808 | sizeof(struct vmw_kms_sou_dmabuf_blit) * |
880 | dirty->num_hits); | 809 | dirty->num_hits); |
@@ -909,6 +838,8 @@ static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty) | |||
909 | * @dev_priv: Pointer to the device private structure. | 838 | * @dev_priv: Pointer to the device private structure. |
910 | * @framebuffer: Pointer to the dma-buffer backed framebuffer. | 839 | * @framebuffer: Pointer to the dma-buffer backed framebuffer. |
911 | * @clips: Array of clip rects. | 840 | * @clips: Array of clip rects. |
841 | * @vclips: Alternate array of clip rects. Either @clips or @vclips must | ||
842 | * be NULL. | ||
912 | * @num_clips: Number of clip rects in @clips. | 843 | * @num_clips: Number of clip rects in @clips. |
913 | * @increment: Increment to use when looping over @clips. | 844 | * @increment: Increment to use when looping over @clips. |
914 | * @interruptible: Whether to perform waits interruptible if possible. | 845 | * @interruptible: Whether to perform waits interruptible if possible. |
@@ -922,6 +853,7 @@ static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty) | |||
922 | int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, | 853 | int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, |
923 | struct vmw_framebuffer *framebuffer, | 854 | struct vmw_framebuffer *framebuffer, |
924 | struct drm_clip_rect *clips, | 855 | struct drm_clip_rect *clips, |
856 | struct drm_vmw_rect *vclips, | ||
925 | unsigned num_clips, int increment, | 857 | unsigned num_clips, int increment, |
926 | bool interruptible, | 858 | bool interruptible, |
927 | struct vmw_fence_obj **out_fence) | 859 | struct vmw_fence_obj **out_fence) |
@@ -945,7 +877,7 @@ int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, | |||
945 | dirty.clip = vmw_sou_dmabuf_clip; | 877 | dirty.clip = vmw_sou_dmabuf_clip; |
946 | dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_dmabuf_blit) * | 878 | dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_dmabuf_blit) * |
947 | num_clips; | 879 | num_clips; |
948 | ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, NULL, | 880 | ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, |
949 | 0, 0, num_clips, increment, &dirty); | 881 | 0, 0, num_clips, increment, &dirty); |
950 | vmw_kms_helper_buffer_finish(dev_priv, NULL, buf, out_fence, NULL); | 882 | vmw_kms_helper_buffer_finish(dev_priv, NULL, buf, out_fence, NULL); |
951 | 883 | ||
@@ -967,6 +899,11 @@ out_revert: | |||
967 | */ | 899 | */ |
968 | static void vmw_sou_readback_fifo_commit(struct vmw_kms_dirty *dirty) | 900 | static void vmw_sou_readback_fifo_commit(struct vmw_kms_dirty *dirty) |
969 | { | 901 | { |
902 | if (!dirty->num_hits) { | ||
903 | vmw_fifo_commit(dirty->dev_priv, 0); | ||
904 | return; | ||
905 | } | ||
906 | |||
970 | vmw_fifo_commit(dirty->dev_priv, | 907 | vmw_fifo_commit(dirty->dev_priv, |
971 | sizeof(struct vmw_kms_sou_readback_blit) * | 908 | sizeof(struct vmw_kms_sou_readback_blit) * |
972 | dirty->num_hits); | 909 | dirty->num_hits); |
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 4ef5ffd7189d..b949102ad864 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | |||
@@ -96,7 +96,6 @@ struct vmw_stdu_surface_copy { | |||
96 | * content_vfbs dimensions, then this is a pointer into the | 96 | * content_vfbs dimensions, then this is a pointer into the |
97 | * corresponding field in content_vfbs. If not, then this | 97 | * corresponding field in content_vfbs. If not, then this |
98 | * is a separate buffer to which content_vfbs will blit to. | 98 | * is a separate buffer to which content_vfbs will blit to. |
99 | * @content_fb: holds the rendered content, can be a surface or DMA buffer | ||
100 | * @content_type: content_fb type | 99 | * @content_type: content_fb type |
101 | * @defined: true if the current display unit has been initialized | 100 | * @defined: true if the current display unit has been initialized |
102 | */ | 101 | */ |
@@ -104,8 +103,6 @@ struct vmw_screen_target_display_unit { | |||
104 | struct vmw_display_unit base; | 103 | struct vmw_display_unit base; |
105 | 104 | ||
106 | struct vmw_surface *display_srf; | 105 | struct vmw_surface *display_srf; |
107 | struct drm_framebuffer *content_fb; | ||
108 | |||
109 | enum stdu_content_type content_fb_type; | 106 | enum stdu_content_type content_fb_type; |
110 | 107 | ||
111 | bool defined; | 108 | bool defined; |
@@ -122,22 +119,6 @@ static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu); | |||
122 | *****************************************************************************/ | 119 | *****************************************************************************/ |
123 | 120 | ||
124 | /** | 121 | /** |
125 | * vmw_stdu_pin_display - pins the resource associated with the display surface | ||
126 | * | ||
127 | * @stdu: contains the display surface | ||
128 | * | ||
129 | * Since the display surface can either be a private surface allocated by us, | ||
130 | * or it can point to the content surface, we use this function to not pin the | ||
131 | * same resource twice. | ||
132 | */ | ||
133 | static int vmw_stdu_pin_display(struct vmw_screen_target_display_unit *stdu) | ||
134 | { | ||
135 | return vmw_resource_pin(&stdu->display_srf->res, false); | ||
136 | } | ||
137 | |||
138 | |||
139 | |||
140 | /** | ||
141 | * vmw_stdu_unpin_display - unpins the resource associated with display surface | 122 | * vmw_stdu_unpin_display - unpins the resource associated with display surface |
142 | * | 123 | * |
143 | * @stdu: contains the display surface | 124 | * @stdu: contains the display surface |
@@ -153,13 +134,7 @@ static void vmw_stdu_unpin_display(struct vmw_screen_target_display_unit *stdu) | |||
153 | struct vmw_resource *res = &stdu->display_srf->res; | 134 | struct vmw_resource *res = &stdu->display_srf->res; |
154 | 135 | ||
155 | vmw_resource_unpin(res); | 136 | vmw_resource_unpin(res); |
156 | 137 | vmw_surface_unreference(&stdu->display_srf); | |
157 | if (stdu->content_fb_type != SAME_AS_DISPLAY) { | ||
158 | vmw_resource_unreference(&res); | ||
159 | stdu->content_fb_type = SAME_AS_DISPLAY; | ||
160 | } | ||
161 | |||
162 | stdu->display_srf = NULL; | ||
163 | } | 138 | } |
164 | } | 139 | } |
165 | 140 | ||
@@ -185,6 +160,9 @@ static void vmw_stdu_crtc_destroy(struct drm_crtc *crtc) | |||
185 | * | 160 | * |
186 | * @dev_priv: VMW DRM device | 161 | * @dev_priv: VMW DRM device |
187 | * @stdu: display unit to create a Screen Target for | 162 | * @stdu: display unit to create a Screen Target for |
163 | * @mode: The mode to set. | ||
164 | * @crtc_x: X coordinate of screen target relative to framebuffer origin. | ||
165 | * @crtc_y: Y coordinate of screen target relative to framebuffer origin. | ||
188 | * | 166 | * |
189 | * Creates a STDU that we can used later. This function is called whenever the | 167 | * Creates a STDU that we can used later. This function is called whenever the |
190 | * framebuffer size changes. | 168 | * framebuffer size changes. |
@@ -193,7 +171,9 @@ static void vmw_stdu_crtc_destroy(struct drm_crtc *crtc) | |||
193 | * 0 on success, error code on failure | 171 | * 0 on success, error code on failure |
194 | */ | 172 | */ |
195 | static int vmw_stdu_define_st(struct vmw_private *dev_priv, | 173 | static int vmw_stdu_define_st(struct vmw_private *dev_priv, |
196 | struct vmw_screen_target_display_unit *stdu) | 174 | struct vmw_screen_target_display_unit *stdu, |
175 | struct drm_display_mode *mode, | ||
176 | int crtc_x, int crtc_y) | ||
197 | { | 177 | { |
198 | struct { | 178 | struct { |
199 | SVGA3dCmdHeader header; | 179 | SVGA3dCmdHeader header; |
@@ -211,17 +191,19 @@ static int vmw_stdu_define_st(struct vmw_private *dev_priv, | |||
211 | cmd->header.size = sizeof(cmd->body); | 191 | cmd->header.size = sizeof(cmd->body); |
212 | 192 | ||
213 | cmd->body.stid = stdu->base.unit; | 193 | cmd->body.stid = stdu->base.unit; |
214 | cmd->body.width = stdu->display_srf->base_size.width; | 194 | cmd->body.width = mode->hdisplay; |
215 | cmd->body.height = stdu->display_srf->base_size.height; | 195 | cmd->body.height = mode->vdisplay; |
216 | cmd->body.flags = (0 == cmd->body.stid) ? SVGA_STFLAG_PRIMARY : 0; | 196 | cmd->body.flags = (0 == cmd->body.stid) ? SVGA_STFLAG_PRIMARY : 0; |
217 | cmd->body.dpi = 0; | 197 | cmd->body.dpi = 0; |
218 | cmd->body.xRoot = stdu->base.crtc.x; | 198 | if (stdu->base.is_implicit) { |
219 | cmd->body.yRoot = stdu->base.crtc.y; | 199 | cmd->body.xRoot = crtc_x; |
220 | 200 | cmd->body.yRoot = crtc_y; | |
221 | if (!stdu->base.is_implicit) { | 201 | } else { |
222 | cmd->body.xRoot = stdu->base.gui_x; | 202 | cmd->body.xRoot = stdu->base.gui_x; |
223 | cmd->body.yRoot = stdu->base.gui_y; | 203 | cmd->body.yRoot = stdu->base.gui_y; |
224 | } | 204 | } |
205 | stdu->base.set_gui_x = cmd->body.xRoot; | ||
206 | stdu->base.set_gui_y = cmd->body.yRoot; | ||
225 | 207 | ||
226 | vmw_fifo_commit(dev_priv, sizeof(*cmd)); | 208 | vmw_fifo_commit(dev_priv, sizeof(*cmd)); |
227 | 209 | ||
@@ -392,126 +374,43 @@ static int vmw_stdu_destroy_st(struct vmw_private *dev_priv, | |||
392 | return ret; | 374 | return ret; |
393 | } | 375 | } |
394 | 376 | ||
395 | |||
396 | |||
397 | /** | 377 | /** |
398 | * vmw_stdu_crtc_set_config - Sets a mode | 378 | * vmw_stdu_bind_fb - Bind an fb to a defined screen target |
399 | * | 379 | * |
400 | * @set: mode parameters | 380 | * @dev_priv: Pointer to a device private struct. |
401 | * | 381 | * @crtc: The crtc holding the screen target. |
402 | * This function is the device-specific portion of the DRM CRTC mode set. | 382 | * @mode: The mode currently used by the screen target. Must be non-NULL. |
403 | * For the SVGA device, we do this by defining a Screen Target, binding a | 383 | * @new_fb: The new framebuffer to bind. Must be non-NULL. |
404 | * GB Surface to that target, and finally update the screen target. | ||
405 | * | 384 | * |
406 | * RETURNS: | 385 | * RETURNS: |
407 | * 0 on success, error code otherwise | 386 | * 0 on success, error code on failure. |
408 | */ | 387 | */ |
409 | static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) | 388 | static int vmw_stdu_bind_fb(struct vmw_private *dev_priv, |
389 | struct drm_crtc *crtc, | ||
390 | struct drm_display_mode *mode, | ||
391 | struct drm_framebuffer *new_fb) | ||
410 | { | 392 | { |
411 | struct vmw_private *dev_priv; | 393 | struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc); |
412 | struct vmw_screen_target_display_unit *stdu; | 394 | struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb); |
413 | struct vmw_framebuffer *vfb; | 395 | struct vmw_surface *new_display_srf = NULL; |
396 | enum stdu_content_type new_content_type; | ||
414 | struct vmw_framebuffer_surface *new_vfbs; | 397 | struct vmw_framebuffer_surface *new_vfbs; |
415 | struct drm_display_mode *mode; | 398 | int ret; |
416 | struct drm_framebuffer *new_fb; | ||
417 | struct drm_crtc *crtc; | ||
418 | struct drm_encoder *encoder; | ||
419 | struct drm_connector *connector; | ||
420 | int ret; | ||
421 | |||
422 | |||
423 | if (!set || !set->crtc) | ||
424 | return -EINVAL; | ||
425 | |||
426 | crtc = set->crtc; | ||
427 | crtc->x = set->x; | ||
428 | crtc->y = set->y; | ||
429 | stdu = vmw_crtc_to_stdu(crtc); | ||
430 | mode = set->mode; | ||
431 | new_fb = set->fb; | ||
432 | dev_priv = vmw_priv(crtc->dev); | ||
433 | |||
434 | |||
435 | if (set->num_connectors > 1) { | ||
436 | DRM_ERROR("Too many connectors\n"); | ||
437 | return -EINVAL; | ||
438 | } | ||
439 | |||
440 | if (set->num_connectors == 1 && | ||
441 | set->connectors[0] != &stdu->base.connector) { | ||
442 | DRM_ERROR("Connectors don't match %p %p\n", | ||
443 | set->connectors[0], &stdu->base.connector); | ||
444 | return -EINVAL; | ||
445 | } | ||
446 | |||
447 | |||
448 | /* Since they always map one to one these are safe */ | ||
449 | connector = &stdu->base.connector; | ||
450 | encoder = &stdu->base.encoder; | ||
451 | |||
452 | |||
453 | /* | ||
454 | * After this point the CRTC will be considered off unless a new fb | ||
455 | * is bound | ||
456 | */ | ||
457 | if (stdu->defined) { | ||
458 | /* Unbind current surface by binding an invalid one */ | ||
459 | ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); | ||
460 | if (unlikely(ret != 0)) | ||
461 | return ret; | ||
462 | |||
463 | /* Update Screen Target, display will now be blank */ | ||
464 | if (crtc->primary->fb) { | ||
465 | vmw_stdu_update_st(dev_priv, stdu); | ||
466 | if (unlikely(ret != 0)) | ||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | crtc->primary->fb = NULL; | ||
471 | crtc->enabled = false; | ||
472 | encoder->crtc = NULL; | ||
473 | connector->encoder = NULL; | ||
474 | |||
475 | vmw_stdu_unpin_display(stdu); | ||
476 | stdu->content_fb = NULL; | ||
477 | stdu->content_fb_type = SAME_AS_DISPLAY; | ||
478 | |||
479 | ret = vmw_stdu_destroy_st(dev_priv, stdu); | ||
480 | /* The hardware is hung, give up */ | ||
481 | if (unlikely(ret != 0)) | ||
482 | return ret; | ||
483 | } | ||
484 | |||
485 | |||
486 | /* Any of these conditions means the caller wants CRTC off */ | ||
487 | if (set->num_connectors == 0 || !mode || !new_fb) | ||
488 | return 0; | ||
489 | |||
490 | |||
491 | if (set->x + mode->hdisplay > new_fb->width || | ||
492 | set->y + mode->vdisplay > new_fb->height) { | ||
493 | DRM_ERROR("Set outside of framebuffer\n"); | ||
494 | return -EINVAL; | ||
495 | } | ||
496 | 399 | ||
497 | stdu->content_fb = new_fb; | 400 | WARN_ON_ONCE(!stdu->defined); |
498 | vfb = vmw_framebuffer_to_vfb(stdu->content_fb); | ||
499 | 401 | ||
500 | if (vfb->dmabuf) | 402 | if (!vfb->dmabuf && new_fb->width == mode->hdisplay && |
501 | stdu->content_fb_type = SEPARATE_DMA; | 403 | new_fb->height == mode->vdisplay) |
404 | new_content_type = SAME_AS_DISPLAY; | ||
405 | else if (vfb->dmabuf) | ||
406 | new_content_type = SEPARATE_DMA; | ||
407 | else | ||
408 | new_content_type = SEPARATE_SURFACE; | ||
502 | 409 | ||
503 | /* | 410 | if (new_content_type != SAME_AS_DISPLAY && |
504 | * If the requested mode is different than the width and height | 411 | !stdu->display_srf) { |
505 | * of the FB or if the content buffer is a DMA buf, then allocate | ||
506 | * a display FB that matches the dimension of the mode | ||
507 | */ | ||
508 | if (mode->hdisplay != new_fb->width || | ||
509 | mode->vdisplay != new_fb->height || | ||
510 | stdu->content_fb_type != SAME_AS_DISPLAY) { | ||
511 | struct vmw_surface content_srf; | 412 | struct vmw_surface content_srf; |
512 | struct drm_vmw_size display_base_size = {0}; | 413 | struct drm_vmw_size display_base_size = {0}; |
513 | struct vmw_surface *display_srf; | ||
514 | |||
515 | 414 | ||
516 | display_base_size.width = mode->hdisplay; | 415 | display_base_size.width = mode->hdisplay; |
517 | display_base_size.height = mode->vdisplay; | 416 | display_base_size.height = mode->vdisplay; |
@@ -521,7 +420,7 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) | |||
521 | * If content buffer is a DMA buf, then we have to construct | 420 | * If content buffer is a DMA buf, then we have to construct |
522 | * surface info | 421 | * surface info |
523 | */ | 422 | */ |
524 | if (stdu->content_fb_type == SEPARATE_DMA) { | 423 | if (new_content_type == SEPARATE_DMA) { |
525 | 424 | ||
526 | switch (new_fb->bits_per_pixel) { | 425 | switch (new_fb->bits_per_pixel) { |
527 | case 32: | 426 | case 32: |
@@ -538,17 +437,13 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) | |||
538 | 437 | ||
539 | default: | 438 | default: |
540 | DRM_ERROR("Invalid format\n"); | 439 | DRM_ERROR("Invalid format\n"); |
541 | ret = -EINVAL; | 440 | return -EINVAL; |
542 | goto err_unref_content; | ||
543 | } | 441 | } |
544 | 442 | ||
545 | content_srf.flags = 0; | 443 | content_srf.flags = 0; |
546 | content_srf.mip_levels[0] = 1; | 444 | content_srf.mip_levels[0] = 1; |
547 | content_srf.multisample_count = 0; | 445 | content_srf.multisample_count = 0; |
548 | } else { | 446 | } else { |
549 | |||
550 | stdu->content_fb_type = SEPARATE_SURFACE; | ||
551 | |||
552 | new_vfbs = vmw_framebuffer_to_vfbs(new_fb); | 447 | new_vfbs = vmw_framebuffer_to_vfbs(new_fb); |
553 | content_srf = *new_vfbs->surface; | 448 | content_srf = *new_vfbs->surface; |
554 | } | 449 | } |
@@ -563,26 +458,136 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) | |||
563 | content_srf.multisample_count, | 458 | content_srf.multisample_count, |
564 | 0, | 459 | 0, |
565 | display_base_size, | 460 | display_base_size, |
566 | &display_srf); | 461 | &new_display_srf); |
567 | if (unlikely(ret != 0)) { | 462 | if (unlikely(ret != 0)) { |
568 | DRM_ERROR("Cannot allocate a display FB.\n"); | 463 | DRM_ERROR("Could not allocate screen target surface.\n"); |
569 | goto err_unref_content; | 464 | return ret; |
570 | } | 465 | } |
571 | 466 | } else if (new_content_type == SAME_AS_DISPLAY) { | |
572 | stdu->display_srf = display_srf; | ||
573 | } else { | ||
574 | new_vfbs = vmw_framebuffer_to_vfbs(new_fb); | 467 | new_vfbs = vmw_framebuffer_to_vfbs(new_fb); |
575 | stdu->display_srf = new_vfbs->surface; | 468 | new_display_srf = vmw_surface_reference(new_vfbs->surface); |
576 | } | 469 | } |
577 | 470 | ||
471 | if (new_display_srf) { | ||
472 | /* Pin new surface before flipping */ | ||
473 | ret = vmw_resource_pin(&new_display_srf->res, false); | ||
474 | if (ret) | ||
475 | goto out_srf_unref; | ||
476 | |||
477 | ret = vmw_stdu_bind_st(dev_priv, stdu, &new_display_srf->res); | ||
478 | if (ret) | ||
479 | goto out_srf_unpin; | ||
480 | |||
481 | /* Unpin and unreference old surface */ | ||
482 | vmw_stdu_unpin_display(stdu); | ||
578 | 483 | ||
579 | ret = vmw_stdu_pin_display(stdu); | 484 | /* Transfer the reference */ |
580 | if (unlikely(ret != 0)) { | 485 | stdu->display_srf = new_display_srf; |
581 | stdu->display_srf = NULL; | 486 | new_display_srf = NULL; |
582 | goto err_unref_content; | ||
583 | } | 487 | } |
584 | 488 | ||
585 | vmw_svga_enable(dev_priv); | 489 | crtc->primary->fb = new_fb; |
490 | stdu->content_fb_type = new_content_type; | ||
491 | return 0; | ||
492 | |||
493 | out_srf_unpin: | ||
494 | vmw_resource_unpin(&new_display_srf->res); | ||
495 | out_srf_unref: | ||
496 | vmw_surface_unreference(&new_display_srf); | ||
497 | return ret; | ||
498 | } | ||
499 | |||
500 | /** | ||
501 | * vmw_stdu_crtc_set_config - Sets a mode | ||
502 | * | ||
503 | * @set: mode parameters | ||
504 | * | ||
505 | * This function is the device-specific portion of the DRM CRTC mode set. | ||
506 | * For the SVGA device, we do this by defining a Screen Target, binding a | ||
507 | * GB Surface to that target, and finally update the screen target. | ||
508 | * | ||
509 | * RETURNS: | ||
510 | * 0 on success, error code otherwise | ||
511 | */ | ||
512 | static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) | ||
513 | { | ||
514 | struct vmw_private *dev_priv; | ||
515 | struct vmw_framebuffer *vfb; | ||
516 | struct vmw_screen_target_display_unit *stdu; | ||
517 | struct drm_display_mode *mode; | ||
518 | struct drm_framebuffer *new_fb; | ||
519 | struct drm_crtc *crtc; | ||
520 | struct drm_encoder *encoder; | ||
521 | struct drm_connector *connector; | ||
522 | bool turning_off; | ||
523 | int ret; | ||
524 | |||
525 | |||
526 | if (!set || !set->crtc) | ||
527 | return -EINVAL; | ||
528 | |||
529 | crtc = set->crtc; | ||
530 | stdu = vmw_crtc_to_stdu(crtc); | ||
531 | mode = set->mode; | ||
532 | new_fb = set->fb; | ||
533 | dev_priv = vmw_priv(crtc->dev); | ||
534 | turning_off = set->num_connectors == 0 || !mode || !new_fb; | ||
535 | vfb = (new_fb) ? vmw_framebuffer_to_vfb(new_fb) : NULL; | ||
536 | |||
537 | if (set->num_connectors > 1) { | ||
538 | DRM_ERROR("Too many connectors\n"); | ||
539 | return -EINVAL; | ||
540 | } | ||
541 | |||
542 | if (set->num_connectors == 1 && | ||
543 | set->connectors[0] != &stdu->base.connector) { | ||
544 | DRM_ERROR("Connectors don't match %p %p\n", | ||
545 | set->connectors[0], &stdu->base.connector); | ||
546 | return -EINVAL; | ||
547 | } | ||
548 | |||
549 | if (!turning_off && (set->x + mode->hdisplay > new_fb->width || | ||
550 | set->y + mode->vdisplay > new_fb->height)) { | ||
551 | DRM_ERROR("Set outside of framebuffer\n"); | ||
552 | return -EINVAL; | ||
553 | } | ||
554 | |||
555 | /* Only one active implicit frame-buffer at a time. */ | ||
556 | if (!turning_off && stdu->base.is_implicit && dev_priv->implicit_fb && | ||
557 | !(dev_priv->num_implicit == 1 && stdu->base.active_implicit) | ||
558 | && dev_priv->implicit_fb != vfb) { | ||
559 | DRM_ERROR("Multiple implicit framebuffers not supported.\n"); | ||
560 | return -EINVAL; | ||
561 | } | ||
562 | |||
563 | /* Since they always map one to one these are safe */ | ||
564 | connector = &stdu->base.connector; | ||
565 | encoder = &stdu->base.encoder; | ||
566 | |||
567 | if (stdu->defined) { | ||
568 | ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); | ||
569 | if (ret) | ||
570 | return ret; | ||
571 | |||
572 | vmw_stdu_unpin_display(stdu); | ||
573 | (void) vmw_stdu_update_st(dev_priv, stdu); | ||
574 | vmw_kms_del_active(dev_priv, &stdu->base); | ||
575 | |||
576 | ret = vmw_stdu_destroy_st(dev_priv, stdu); | ||
577 | if (ret) | ||
578 | return ret; | ||
579 | |||
580 | crtc->primary->fb = NULL; | ||
581 | crtc->enabled = false; | ||
582 | encoder->crtc = NULL; | ||
583 | connector->encoder = NULL; | ||
584 | stdu->content_fb_type = SAME_AS_DISPLAY; | ||
585 | crtc->x = set->x; | ||
586 | crtc->y = set->y; | ||
587 | } | ||
588 | |||
589 | if (turning_off) | ||
590 | return 0; | ||
586 | 591 | ||
587 | /* | 592 | /* |
588 | * Steps to displaying a surface, assume surface is already | 593 | * Steps to displaying a surface, assume surface is already |
@@ -592,35 +597,33 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) | |||
592 | * 3. update that screen target (this is done later by | 597 | * 3. update that screen target (this is done later by |
593 | * vmw_kms_stdu_do_surface_dirty_or_present) | 598 | * vmw_kms_stdu_do_surface_dirty_or_present) |
594 | */ | 599 | */ |
595 | ret = vmw_stdu_define_st(dev_priv, stdu); | 600 | /* |
596 | if (unlikely(ret != 0)) | 601 | * Note on error handling: We can't really restore the crtc to |
597 | goto err_unpin_display_and_content; | 602 | * it's original state on error, but we at least update the |
603 | * current state to what's submitted to hardware to enable | ||
604 | * future recovery. | ||
605 | */ | ||
606 | vmw_svga_enable(dev_priv); | ||
607 | ret = vmw_stdu_define_st(dev_priv, stdu, mode, set->x, set->y); | ||
608 | if (ret) | ||
609 | return ret; | ||
598 | 610 | ||
599 | ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); | 611 | crtc->x = set->x; |
600 | if (unlikely(ret != 0)) | 612 | crtc->y = set->y; |
601 | goto err_unpin_destroy_st; | 613 | crtc->mode = *mode; |
602 | 614 | ||
615 | ret = vmw_stdu_bind_fb(dev_priv, crtc, mode, new_fb); | ||
616 | if (ret) | ||
617 | return ret; | ||
603 | 618 | ||
619 | vmw_kms_add_active(dev_priv, &stdu->base, vfb); | ||
620 | crtc->enabled = true; | ||
604 | connector->encoder = encoder; | 621 | connector->encoder = encoder; |
605 | encoder->crtc = crtc; | 622 | encoder->crtc = crtc; |
606 | 623 | ||
607 | crtc->mode = *mode; | 624 | return 0; |
608 | crtc->primary->fb = new_fb; | ||
609 | crtc->enabled = true; | ||
610 | |||
611 | return ret; | ||
612 | |||
613 | err_unpin_destroy_st: | ||
614 | vmw_stdu_destroy_st(dev_priv, stdu); | ||
615 | err_unpin_display_and_content: | ||
616 | vmw_stdu_unpin_display(stdu); | ||
617 | err_unref_content: | ||
618 | stdu->content_fb = NULL; | ||
619 | return ret; | ||
620 | } | 625 | } |
621 | 626 | ||
622 | |||
623 | |||
624 | /** | 627 | /** |
625 | * vmw_stdu_crtc_page_flip - Binds a buffer to a screen target | 628 | * vmw_stdu_crtc_page_flip - Binds a buffer to a screen target |
626 | * | 629 | * |
@@ -648,59 +651,34 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, | |||
648 | { | 651 | { |
649 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); | 652 | struct vmw_private *dev_priv = vmw_priv(crtc->dev); |
650 | struct vmw_screen_target_display_unit *stdu; | 653 | struct vmw_screen_target_display_unit *stdu; |
654 | struct drm_vmw_rect vclips; | ||
655 | struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb); | ||
651 | int ret; | 656 | int ret; |
652 | 657 | ||
653 | if (crtc == NULL) | ||
654 | return -EINVAL; | ||
655 | |||
656 | dev_priv = vmw_priv(crtc->dev); | 658 | dev_priv = vmw_priv(crtc->dev); |
657 | stdu = vmw_crtc_to_stdu(crtc); | 659 | stdu = vmw_crtc_to_stdu(crtc); |
658 | crtc->primary->fb = new_fb; | ||
659 | stdu->content_fb = new_fb; | ||
660 | |||
661 | if (stdu->display_srf) { | ||
662 | /* | ||
663 | * If the display surface is the same as the content surface | ||
664 | * then remove the reference | ||
665 | */ | ||
666 | if (stdu->content_fb_type == SAME_AS_DISPLAY) { | ||
667 | if (stdu->defined) { | ||
668 | /* Unbind the current surface */ | ||
669 | ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); | ||
670 | if (unlikely(ret != 0)) | ||
671 | goto err_out; | ||
672 | } | ||
673 | vmw_stdu_unpin_display(stdu); | ||
674 | stdu->display_srf = NULL; | ||
675 | } | ||
676 | } | ||
677 | |||
678 | |||
679 | if (!new_fb) { | ||
680 | /* Blanks the display */ | ||
681 | (void) vmw_stdu_update_st(dev_priv, stdu); | ||
682 | |||
683 | return 0; | ||
684 | } | ||
685 | 660 | ||
661 | if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc)) | ||
662 | return -EINVAL; | ||
686 | 663 | ||
687 | if (stdu->content_fb_type == SAME_AS_DISPLAY) { | 664 | ret = vmw_stdu_bind_fb(dev_priv, crtc, &crtc->mode, new_fb); |
688 | stdu->display_srf = vmw_framebuffer_to_vfbs(new_fb)->surface; | 665 | if (ret) |
689 | ret = vmw_stdu_pin_display(stdu); | 666 | return ret; |
690 | if (ret) { | ||
691 | stdu->display_srf = NULL; | ||
692 | goto err_out; | ||
693 | } | ||
694 | 667 | ||
695 | /* Bind display surface */ | 668 | if (stdu->base.is_implicit) |
696 | ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); | 669 | vmw_kms_update_implicit_fb(dev_priv, crtc); |
697 | if (unlikely(ret != 0)) | ||
698 | goto err_unpin_display_and_content; | ||
699 | } | ||
700 | 670 | ||
701 | /* Update display surface: after this point everything is bound */ | 671 | vclips.x = crtc->x; |
702 | ret = vmw_stdu_update_st(dev_priv, stdu); | 672 | vclips.y = crtc->y; |
703 | if (unlikely(ret != 0)) | 673 | vclips.w = crtc->mode.hdisplay; |
674 | vclips.h = crtc->mode.vdisplay; | ||
675 | if (vfb->dmabuf) | ||
676 | ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, &vclips, | ||
677 | 1, 1, true, false); | ||
678 | else | ||
679 | ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, &vclips, | ||
680 | NULL, 0, 0, 1, 1, NULL); | ||
681 | if (ret) | ||
704 | return ret; | 682 | return ret; |
705 | 683 | ||
706 | if (event) { | 684 | if (event) { |
@@ -721,14 +699,7 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, | |||
721 | vmw_fifo_flush(dev_priv, false); | 699 | vmw_fifo_flush(dev_priv, false); |
722 | } | 700 | } |
723 | 701 | ||
724 | return ret; | 702 | return 0; |
725 | |||
726 | err_unpin_display_and_content: | ||
727 | vmw_stdu_unpin_display(stdu); | ||
728 | err_out: | ||
729 | crtc->primary->fb = NULL; | ||
730 | stdu->content_fb = NULL; | ||
731 | return ret; | ||
732 | } | 703 | } |
733 | 704 | ||
734 | 705 | ||
@@ -1138,7 +1109,7 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) | |||
1138 | stdu->base.pref_active = (unit == 0); | 1109 | stdu->base.pref_active = (unit == 0); |
1139 | stdu->base.pref_width = dev_priv->initial_width; | 1110 | stdu->base.pref_width = dev_priv->initial_width; |
1140 | stdu->base.pref_height = dev_priv->initial_height; | 1111 | stdu->base.pref_height = dev_priv->initial_height; |
1141 | stdu->base.is_implicit = true; | 1112 | stdu->base.is_implicit = false; |
1142 | 1113 | ||
1143 | drm_connector_init(dev, connector, &vmw_stdu_connector_funcs, | 1114 | drm_connector_init(dev, connector, &vmw_stdu_connector_funcs, |
1144 | DRM_MODE_CONNECTOR_VIRTUAL); | 1115 | DRM_MODE_CONNECTOR_VIRTUAL); |
@@ -1159,7 +1130,17 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) | |||
1159 | drm_object_attach_property(&connector->base, | 1130 | drm_object_attach_property(&connector->base, |
1160 | dev->mode_config.dirty_info_property, | 1131 | dev->mode_config.dirty_info_property, |
1161 | 1); | 1132 | 1); |
1162 | 1133 | drm_object_attach_property(&connector->base, | |
1134 | dev_priv->hotplug_mode_update_property, 1); | ||
1135 | drm_object_attach_property(&connector->base, | ||
1136 | dev->mode_config.suggested_x_property, 0); | ||
1137 | drm_object_attach_property(&connector->base, | ||
1138 | dev->mode_config.suggested_y_property, 0); | ||
1139 | if (dev_priv->implicit_placement_property) | ||
1140 | drm_object_attach_property | ||
1141 | (&connector->base, | ||
1142 | dev_priv->implicit_placement_property, | ||
1143 | stdu->base.is_implicit); | ||
1163 | return 0; | 1144 | return 0; |
1164 | } | 1145 | } |
1165 | 1146 | ||
@@ -1224,6 +1205,8 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv) | |||
1224 | 1205 | ||
1225 | dev_priv->active_display_unit = vmw_du_screen_target; | 1206 | dev_priv->active_display_unit = vmw_du_screen_target; |
1226 | 1207 | ||
1208 | vmw_kms_create_implicit_placement_property(dev_priv, false); | ||
1209 | |||
1227 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) { | 1210 | for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) { |
1228 | ret = vmw_stdu_init(dev_priv, i); | 1211 | ret = vmw_stdu_init(dev_priv, i); |
1229 | 1212 | ||