Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 047b8e21 authored by Dave Airlie's avatar Dave Airlie
Browse files

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.
parents 296923e1 34c8ea40
Loading
Loading
Loading
Loading
+83 −0
Original line number Original line Diff line number Diff line
@@ -343,6 +343,7 @@ void vc4_free_object(struct drm_gem_object *gem_bo)
		bo->validated_shader = NULL;
		bo->validated_shader = NULL;
	}
	}


	bo->t_format = false;
	bo->free_time = jiffies;
	bo->free_time = jiffies;
	list_add(&bo->size_head, cache_list);
	list_add(&bo->size_head, cache_list);
	list_add(&bo->unref_head, &vc4->bo_cache.time_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;
	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)
void vc4_bo_cache_init(struct drm_device *dev)
{
{
	struct vc4_dev *vc4 = to_vc4_dev(dev);
	struct vc4_dev *vc4 = to_vc4_dev(dev);
+2 −0
Original line number Original line Diff line number Diff line
@@ -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_IOCTL_DEF_DRV(VC4_GET_HANG_STATE, vc4_get_hang_state_ioctl,
			  DRM_ROOT_ONLY),
			  DRM_ROOT_ONLY),
	DRM_IOCTL_DEF_DRV(VC4_GET_PARAM, vc4_get_param_ioctl, DRM_RENDER_ALLOW),
	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 = {
static struct drm_driver vc4_drm_driver = {
+6 −0
Original line number Original line Diff line number Diff line
@@ -148,6 +148,8 @@ struct vc4_bo {
	 */
	 */
	uint64_t write_seqno;
	uint64_t write_seqno;


	bool t_format;

	/* List entry for the BO's position in either
	/* List entry for the BO's position in either
	 * vc4_exec_info->unref_list or vc4_dev->bo_cache.time_list
	 * 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);
			       struct drm_file *file_priv);
int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
int vc4_mmap_bo_ioctl(struct drm_device *dev, void *data,
		      struct drm_file *file_priv);
		      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,
int vc4_get_hang_state_ioctl(struct drm_device *dev, void *data,
			     struct drm_file *file_priv);
			     struct drm_file *file_priv);
int vc4_mmap(struct file *filp, struct vm_area_struct *vma);
int vc4_mmap(struct file *filp, struct vm_area_struct *vma);
+52 −27
Original line number Original line Diff line number Diff line
@@ -42,6 +42,10 @@ vc4_atomic_complete_commit(struct vc4_commit *c)
	struct drm_device *dev = state->dev;
	struct drm_device *dev = state->dev;
	struct vc4_dev *vc4 = to_vc4_dev(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_modeset_disables(dev, state);


	drm_atomic_helper_commit_planes(dev, state, 0);
	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;
	state->legacy_cursor_update = false;


	drm_atomic_helper_commit_hw_done(state);

	drm_atomic_helper_wait_for_vblanks(dev, state);
	drm_atomic_helper_wait_for_vblanks(dev, state);


	drm_atomic_helper_cleanup_planes(dev, state);
	drm_atomic_helper_cleanup_planes(dev, state);


	drm_atomic_helper_commit_cleanup_done(state);

	drm_atomic_state_put(state);
	drm_atomic_state_put(state);


	up(&vc4->async_modeset);
	up(&vc4->async_modeset);
@@ -117,32 +125,10 @@ static int vc4_atomic_commit(struct drm_device *dev,
	if (!c)
	if (!c)
		return -ENOMEM;
		return -ENOMEM;


	/* Make sure that any outstanding modesets have finished. */
	ret = drm_atomic_helper_setup_commit(state, nonblock);
	if (nonblock) {
	if (ret)
		struct drm_crtc *crtc;
		return ret;
		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 = down_interruptible(&vc4->async_modeset);
	ret = down_interruptible(&vc4->async_modeset);
	if (ret) {
	if (ret) {
		kfree(c);
		kfree(c);
@@ -202,11 +188,50 @@ static int vc4_atomic_commit(struct drm_device *dev,
	return 0;
	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 = {
static const struct drm_mode_config_funcs vc4_mode_funcs = {
	.output_poll_changed = vc4_output_poll_changed,
	.output_poll_changed = vc4_output_poll_changed,
	.atomic_check = drm_atomic_helper_check,
	.atomic_check = drm_atomic_helper_check,
	.atomic_commit = vc4_atomic_commit,
	.atomic_commit = vc4_atomic_commit,
	.fb_create = drm_fb_cma_create,
	.fb_create = vc4_fb_create,
};
};


int vc4_kms_load(struct drm_device *dev)
int vc4_kms_load(struct drm_device *dev)
+27 −4
Original line number Original line Diff line number Diff line
@@ -500,8 +500,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
	u32 ctl0_offset = vc4_state->dlist_count;
	u32 ctl0_offset = vc4_state->dlist_count;
	const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
	const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
	int num_planes = drm_format_num_planes(format->drm);
	int num_planes = drm_format_num_planes(format->drm);
	u32 scl0, scl1;
	u32 scl0, scl1, pitch0;
	u32 lbm_size;
	u32 lbm_size, tiling;
	unsigned long irqflags;
	unsigned long irqflags;
	int ret, i;
	int ret, i;


@@ -542,11 +542,31 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
		scl1 = vc4_get_scl_field(state, 0);
		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 */
	/* Control word */
	vc4_dlist_write(vc4_state,
	vc4_dlist_write(vc4_state,
			SCALER_CTL0_VALID |
			SCALER_CTL0_VALID |
			(format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
			(format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
			(format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
			(format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
			VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
			(vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
			(vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
			VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
			VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
			VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
			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++)
	for (i = 0; i < num_planes; i++)
		vc4_dlist_write(vc4_state, 0xc0c0c0c0);
		vc4_dlist_write(vc4_state, 0xc0c0c0c0);


	/* Pitch word 0/1/2 */
	/* Pitch word 0 */
	for (i = 0; i < num_planes; i++) {
	vc4_dlist_write(vc4_state, pitch0);

	/* Pitch word 1/2 */
	for (i = 1; i < num_planes; i++) {
		vc4_dlist_write(vc4_state,
		vc4_dlist_write(vc4_state,
				VC4_SET_FIELD(fb->pitches[i], SCALER_SRC_PITCH));
				VC4_SET_FIELD(fb->pitches[i], SCALER_SRC_PITCH));
	}
	}
Loading