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 /drivers/gpu | |
| 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
Diffstat (limited to 'drivers/gpu')
| -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 | ||
