summaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-06-21 00:57:34 +0200
committerDave Airlie <airlied@redhat.com>2017-06-21 00:57:34 +0200
commit047b8e21e3bfa9faa4ed9a0c337fe0c687710251 (patch)
tree5aaf33d21b90852d1aea4e134317c5e0fb08fce8 /drivers/gpu
parentdrm/i915: remove rate_to_index, messed up merge. (diff)
parentdrm/vc4: Mimic drm_atomic_helper_commit() behavior (diff)
downloadlinux-047b8e21e3bfa9faa4ed9a0c337fe0c687710251.tar.xz
linux-047b8e21e3bfa9faa4ed9a0c337fe0c687710251.zip
Merge tag 'drm-misc-next-2017-06-19_0' of git://anongit.freedesktop.org/git/drm-misc into drm-next
UAPI Changes: - vc4: Add get/set tiling format ioctls (Eric) Driver Changes: - vc4: Add tiling T-format support for scanout (Eric) - vc4: Use atomic helpers in commit (Boris) Cc: Boris Brezillon <boris.brezillon@free-electrons.com> Cc: Eric Anholt <eric@anholt.net> * tag 'drm-misc-next-2017-06-19_0' of git://anongit.freedesktop.org/git/drm-misc: drm/vc4: Mimic drm_atomic_helper_commit() behavior drm/vc4: Add get/set tiling ioctls. drm/vc4: Add T-format scanout support.
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/vc4/vc4_bo.c83
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h6
-rw-r--r--drivers/gpu/drm/vc4/vc4_kms.c79
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c31
-rw-r--r--drivers/gpu/drm/vc4/vc4_regs.h19
6 files changed, 189 insertions, 31 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
index 590c0912afc1..487f96412d35 100644
--- a/drivers/gpu/drm/vc4/vc4_bo.c
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
@@ -343,6 +343,7 @@ void vc4_free_object(struct drm_gem_object *gem_bo)
bo->validated_shader = NULL;
}
+ bo->t_format = false;
bo->free_time = jiffies;
list_add(&bo->size_head, cache_list);
list_add(&bo->unref_head, &vc4->bo_cache.time_list);
@@ -568,6 +569,88 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
return ret;
}
+/**
+ * vc4_set_tiling_ioctl() - Sets the tiling modifier for a BO.
+ * @dev: DRM device
+ * @data: ioctl argument
+ * @file_priv: DRM file for this fd
+ *
+ * The tiling state of the BO decides the default modifier of an fb if
+ * no specific modifier was set by userspace, and the return value of
+ * vc4_get_tiling_ioctl() (so that userspace can treat a BO it
+ * received from dmabuf as the same tiling format as the producer
+ * used).
+ */
+int vc4_set_tiling_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_vc4_set_tiling *args = data;
+ struct drm_gem_object *gem_obj;
+ struct vc4_bo *bo;
+ bool t_format;
+
+ if (args->flags != 0)
+ return -EINVAL;
+
+ switch (args->modifier) {
+ case DRM_FORMAT_MOD_NONE:
+ t_format = false;
+ break;
+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
+ t_format = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ gem_obj = drm_gem_object_lookup(file_priv, args->handle);
+ if (!gem_obj) {
+ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
+ return -ENOENT;
+ }
+ bo = to_vc4_bo(gem_obj);
+ bo->t_format = t_format;
+
+ drm_gem_object_unreference_unlocked(gem_obj);
+
+ return 0;
+}
+
+/**
+ * vc4_get_tiling_ioctl() - Gets the tiling modifier for a BO.
+ * @dev: DRM device
+ * @data: ioctl argument
+ * @file_priv: DRM file for this fd
+ *
+ * Returns the tiling modifier for a BO as set by vc4_set_tiling_ioctl().
+ */
+int vc4_get_tiling_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_vc4_get_tiling *args = data;
+ struct drm_gem_object *gem_obj;
+ struct vc4_bo *bo;
+
+ if (args->flags != 0 || args->modifier != 0)
+ return -EINVAL;
+
+ gem_obj = drm_gem_object_lookup(file_priv, args->handle);
+ if (!gem_obj) {
+ DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
+ return -ENOENT;
+ }
+ bo = to_vc4_bo(gem_obj);
+
+ if (bo->t_format)
+ args->modifier = DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED;
+ else
+ args->modifier = DRM_FORMAT_MOD_NONE;
+
+ drm_gem_object_unreference_unlocked(gem_obj);
+
+ return 0;
+}
+
void vc4_bo_cache_init(struct drm_device *dev)
{
struct vc4_dev *vc4 = to_vc4_dev(dev);
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 136bb4213dc0..c6b487c3d2b7 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -138,6 +138,8 @@ static const struct drm_ioctl_desc vc4_drm_ioctls[] = {
DRM_IOCTL_DEF_DRV(VC4_GET_HANG_STATE, vc4_get_hang_state_ioctl,
DRM_ROOT_ONLY),
DRM_IOCTL_DEF_DRV(VC4_GET_PARAM, vc4_get_param_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VC4_SET_TILING, vc4_set_tiling_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VC4_GET_TILING, vc4_get_tiling_ioctl, DRM_RENDER_ALLOW),
};
static struct drm_driver vc4_drm_driver = {
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index a5bf2e5e0b57..df22698d62ee 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -148,6 +148,8 @@ struct vc4_bo {
*/
uint64_t write_seqno;
+ bool t_format;
+
/* List entry for the BO's position in either
* vc4_exec_info->unref_list or vc4_dev->bo_cache.time_list
*/
@@ -470,6 +472,10 @@ int vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+int vc4_set_tiling_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int vc4_get_tiling_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int vc4_mmap(struct file *filp, struct vm_area_struct *vma);
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index 928d191ef90f..bc6ecdc6f104 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -42,6 +42,10 @@ vc4_atomic_complete_commit(struct vc4_commit *c)
struct drm_device *dev = state->dev;
struct vc4_dev *vc4 = to_vc4_dev(dev);
+ drm_atomic_helper_wait_for_fences(dev, state, false);
+
+ drm_atomic_helper_wait_for_dependencies(state);
+
drm_atomic_helper_commit_modeset_disables(dev, state);
drm_atomic_helper_commit_planes(dev, state, 0);
@@ -57,10 +61,14 @@ vc4_atomic_complete_commit(struct vc4_commit *c)
*/
state->legacy_cursor_update = false;
+ drm_atomic_helper_commit_hw_done(state);
+
drm_atomic_helper_wait_for_vblanks(dev, state);
drm_atomic_helper_cleanup_planes(dev, state);
+ drm_atomic_helper_commit_cleanup_done(state);
+
drm_atomic_state_put(state);
up(&vc4->async_modeset);
@@ -117,32 +125,10 @@ static int vc4_atomic_commit(struct drm_device *dev,
if (!c)
return -ENOMEM;
- /* Make sure that any outstanding modesets have finished. */
- if (nonblock) {
- struct drm_crtc *crtc;
- struct drm_crtc_state *crtc_state;
- unsigned long flags;
- bool busy = false;
-
- /*
- * If there's an undispatched event to send then we're
- * obviously still busy. If there isn't, then we can
- * unconditionally wait for the semaphore because it
- * shouldn't be contended (for long).
- *
- * This is to prevent a race where queuing a new flip
- * from userspace immediately on receipt of an event
- * beats our clean-up and returns EBUSY.
- */
- spin_lock_irqsave(&dev->event_lock, flags);
- for_each_crtc_in_state(state, crtc, crtc_state, i)
- busy |= vc4_event_pending(crtc);
- spin_unlock_irqrestore(&dev->event_lock, flags);
- if (busy) {
- kfree(c);
- return -EBUSY;
- }
- }
+ ret = drm_atomic_helper_setup_commit(state, nonblock);
+ if (ret)
+ return ret;
+
ret = down_interruptible(&vc4->async_modeset);
if (ret) {
kfree(c);
@@ -202,11 +188,50 @@ static int vc4_atomic_commit(struct drm_device *dev,
return 0;
}
+static struct drm_framebuffer *vc4_fb_create(struct drm_device *dev,
+ struct drm_file *file_priv,
+ const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ struct drm_mode_fb_cmd2 mode_cmd_local;
+
+ /* If the user didn't specify a modifier, use the
+ * vc4_set_tiling_ioctl() state for the BO.
+ */
+ if (!(mode_cmd->flags & DRM_MODE_FB_MODIFIERS)) {
+ struct drm_gem_object *gem_obj;
+ struct vc4_bo *bo;
+
+ gem_obj = drm_gem_object_lookup(file_priv,
+ mode_cmd->handles[0]);
+ if (!gem_obj) {
+ DRM_ERROR("Failed to look up GEM BO %d\n",
+ mode_cmd->handles[0]);
+ return ERR_PTR(-ENOENT);
+ }
+ bo = to_vc4_bo(gem_obj);
+
+ mode_cmd_local = *mode_cmd;
+
+ if (bo->t_format) {
+ mode_cmd_local.modifier[0] =
+ DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED;
+ } else {
+ mode_cmd_local.modifier[0] = DRM_FORMAT_MOD_NONE;
+ }
+
+ drm_gem_object_unreference_unlocked(gem_obj);
+
+ mode_cmd = &mode_cmd_local;
+ }
+
+ return drm_fb_cma_create(dev, file_priv, mode_cmd);
+}
+
static const struct drm_mode_config_funcs vc4_mode_funcs = {
.output_poll_changed = vc4_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = vc4_atomic_commit,
- .fb_create = drm_fb_cma_create,
+ .fb_create = vc4_fb_create,
};
int vc4_kms_load(struct drm_device *dev)
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index da18dec21696..fa6809d8b0fe 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -500,8 +500,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
u32 ctl0_offset = vc4_state->dlist_count;
const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
int num_planes = drm_format_num_planes(format->drm);
- u32 scl0, scl1;
- u32 lbm_size;
+ u32 scl0, scl1, pitch0;
+ u32 lbm_size, tiling;
unsigned long irqflags;
int ret, i;
@@ -542,11 +542,31 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
scl1 = vc4_get_scl_field(state, 0);
}
+ switch (fb->modifier) {
+ case DRM_FORMAT_MOD_LINEAR:
+ tiling = SCALER_CTL0_TILING_LINEAR;
+ pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);
+ break;
+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
+ tiling = SCALER_CTL0_TILING_256B_OR_T;
+
+ pitch0 = (VC4_SET_FIELD(0, SCALER_PITCH0_TILE_Y_OFFSET),
+ VC4_SET_FIELD(0, SCALER_PITCH0_TILE_WIDTH_L),
+ VC4_SET_FIELD((vc4_state->src_w[0] + 31) >> 5,
+ SCALER_PITCH0_TILE_WIDTH_R));
+ break;
+ default:
+ DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx",
+ (long long)fb->modifier);
+ return -EINVAL;
+ }
+
/* Control word */
vc4_dlist_write(vc4_state,
SCALER_CTL0_VALID |
(format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
(format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
+ VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
(vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
@@ -600,8 +620,11 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
for (i = 0; i < num_planes; i++)
vc4_dlist_write(vc4_state, 0xc0c0c0c0);
- /* Pitch word 0/1/2 */
- for (i = 0; i < num_planes; i++) {
+ /* Pitch word 0 */
+ vc4_dlist_write(vc4_state, pitch0);
+
+ /* Pitch word 1/2 */
+ for (i = 1; i < num_planes; i++) {
vc4_dlist_write(vc4_state,
VC4_SET_FIELD(fb->pitches[i], SCALER_SRC_PITCH));
}
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index 932093936178..d382c34c1b9e 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -709,6 +709,13 @@ enum hvs_pixel_format {
#define SCALER_CTL0_SIZE_MASK VC4_MASK(29, 24)
#define SCALER_CTL0_SIZE_SHIFT 24
+#define SCALER_CTL0_TILING_MASK VC4_MASK(21, 20)
+#define SCALER_CTL0_TILING_SHIFT 20
+#define SCALER_CTL0_TILING_LINEAR 0
+#define SCALER_CTL0_TILING_64B 1
+#define SCALER_CTL0_TILING_128B 2
+#define SCALER_CTL0_TILING_256B_OR_T 3
+
#define SCALER_CTL0_HFLIP BIT(16)
#define SCALER_CTL0_VFLIP BIT(15)
@@ -838,7 +845,19 @@ enum hvs_pixel_format {
#define SCALER_PPF_KERNEL_OFFSET_SHIFT 0
#define SCALER_PPF_KERNEL_UNCACHED BIT(31)
+/* PITCH0/1/2 fields for raster. */
#define SCALER_SRC_PITCH_MASK VC4_MASK(15, 0)
#define SCALER_SRC_PITCH_SHIFT 0
+/* PITCH0 fields for T-tiled. */
+#define SCALER_PITCH0_TILE_WIDTH_L_MASK VC4_MASK(22, 16)
+#define SCALER_PITCH0_TILE_WIDTH_L_SHIFT 16
+#define SCALER_PITCH0_TILE_LINE_DIR BIT(15)
+#define SCALER_PITCH0_TILE_INITIAL_LINE_DIR BIT(14)
+/* Y offset within a tile. */
+#define SCALER_PITCH0_TILE_Y_OFFSET_MASK VC4_MASK(13, 7)
+#define SCALER_PITCH0_TILE_Y_OFFSET_SHIFT 7
+#define SCALER_PITCH0_TILE_WIDTH_R_MASK VC4_MASK(6, 0)
+#define SCALER_PITCH0_TILE_WIDTH_R_SHIFT 0
+
#endif /* VC4_REGS_H */